diff options
Diffstat (limited to 'drivers/net/dsa/bcm_sf2_cfp.c')
| -rw-r--r-- | drivers/net/dsa/bcm_sf2_cfp.c | 46 |
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, | |||
| 1187 | int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, | 1196 | int 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 | ||
| 1219 | int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, | 1239 | int 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 | ||
