aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c')
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c146
1 files changed, 126 insertions, 20 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
index c88c47a14fbb..2e309f6673f7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
@@ -188,23 +188,83 @@ static void cxgb4_matchall_free_tc(struct net_device *dev)
tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_DISABLED;
}
-static int cxgb4_matchall_alloc_filter(struct net_device *dev,
+static int cxgb4_matchall_mirror_alloc(struct net_device *dev,
struct tc_cls_matchall_offload *cls)
{
struct netlink_ext_ack *extack = cls->common.extack;
struct cxgb4_tc_port_matchall *tc_port_matchall;
struct port_info *pi = netdev2pinfo(dev);
struct adapter *adap = netdev2adap(dev);
+ struct flow_action_entry *act;
+ int ret;
+ u32 i;
+
+ tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
+ flow_action_for_each(i, act, &cls->rule->action) {
+ if (act->id == FLOW_ACTION_MIRRED) {
+ ret = cxgb4_port_mirror_alloc(dev);
+ if (ret) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Couldn't allocate mirror");
+ return ret;
+ }
+
+ tc_port_matchall->ingress.viid_mirror = pi->viid_mirror;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void cxgb4_matchall_mirror_free(struct net_device *dev)
+{
+ struct cxgb4_tc_port_matchall *tc_port_matchall;
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adap = netdev2adap(dev);
+
+ tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
+ if (!tc_port_matchall->ingress.viid_mirror)
+ return;
+
+ cxgb4_port_mirror_free(dev);
+ tc_port_matchall->ingress.viid_mirror = 0;
+}
+
+static int cxgb4_matchall_del_filter(struct net_device *dev, u8 filter_type)
+{
+ struct cxgb4_tc_port_matchall *tc_port_matchall;
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adap = netdev2adap(dev);
+ int ret;
+
+ tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
+ ret = cxgb4_del_filter(dev, tc_port_matchall->ingress.tid[filter_type],
+ &tc_port_matchall->ingress.fs[filter_type]);
+ if (ret)
+ return ret;
+
+ tc_port_matchall->ingress.tid[filter_type] = 0;
+ return 0;
+}
+
+static int cxgb4_matchall_add_filter(struct net_device *dev,
+ struct tc_cls_matchall_offload *cls,
+ u8 filter_type)
+{
+ struct netlink_ext_ack *extack = cls->common.extack;
+ struct cxgb4_tc_port_matchall *tc_port_matchall;
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adap = netdev2adap(dev);
struct ch_filter_specification *fs;
int ret, fidx;
/* Get a free filter entry TID, where we can insert this new
* rule. Only insert rule if its prio doesn't conflict with
* existing rules.
- *
- * 1 slot is enough to create a wildcard matchall VIID rule.
*/
- fidx = cxgb4_get_free_ftid(dev, PF_INET, false, cls->common.prio);
+ fidx = cxgb4_get_free_ftid(dev, filter_type ? PF_INET6 : PF_INET,
+ false, cls->common.prio);
if (fidx < 0) {
NL_SET_ERR_MSG_MOD(extack,
"No free LETCAM index available");
@@ -212,13 +272,14 @@ static int cxgb4_matchall_alloc_filter(struct net_device *dev,
}
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
- fs = &tc_port_matchall->ingress.fs;
+ fs = &tc_port_matchall->ingress.fs[filter_type];
memset(fs, 0, sizeof(*fs));
if (fidx < adap->tids.nhpftids)
fs->prio = 1;
fs->tc_prio = cls->common.prio;
fs->tc_cookie = cls->cookie;
+ fs->type = filter_type;
fs->hitcnts = 1;
fs->val.pfvf_vld = 1;
@@ -231,9 +292,39 @@ static int cxgb4_matchall_alloc_filter(struct net_device *dev,
if (ret)
return ret;
- tc_port_matchall->ingress.tid = fidx;
+ tc_port_matchall->ingress.tid[filter_type] = fidx;
+ return 0;
+}
+
+static int cxgb4_matchall_alloc_filter(struct net_device *dev,
+ struct tc_cls_matchall_offload *cls)
+{
+ struct cxgb4_tc_port_matchall *tc_port_matchall;
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adap = netdev2adap(dev);
+ int ret, i;
+
+ tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
+
+ ret = cxgb4_matchall_mirror_alloc(dev, cls);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {
+ ret = cxgb4_matchall_add_filter(dev, cls, i);
+ if (ret)
+ goto out_free;
+ }
+
tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_ENABLED;
return 0;
+
+out_free:
+ while (i-- > 0)
+ cxgb4_matchall_del_filter(dev, i);
+
+ cxgb4_matchall_mirror_free(dev);
+ return ret;
}
static int cxgb4_matchall_free_filter(struct net_device *dev)
@@ -242,18 +333,21 @@ static int cxgb4_matchall_free_filter(struct net_device *dev)
struct port_info *pi = netdev2pinfo(dev);
struct adapter *adap = netdev2adap(dev);
int ret;
+ u8 i;
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
- ret = cxgb4_del_filter(dev, tc_port_matchall->ingress.tid,
- &tc_port_matchall->ingress.fs);
- if (ret)
- return ret;
+ for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {
+ ret = cxgb4_matchall_del_filter(dev, i);
+ if (ret)
+ return ret;
+ }
+
+ cxgb4_matchall_mirror_free(dev);
tc_port_matchall->ingress.packets = 0;
tc_port_matchall->ingress.bytes = 0;
tc_port_matchall->ingress.last_used = 0;
- tc_port_matchall->ingress.tid = 0;
tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_DISABLED;
return 0;
}
@@ -279,7 +373,7 @@ int cxgb4_tc_matchall_replace(struct net_device *dev,
ret = cxgb4_validate_flow_actions(dev,
&cls_matchall->rule->action,
- extack);
+ extack, 1);
if (ret)
return ret;
@@ -309,8 +403,12 @@ int cxgb4_tc_matchall_destroy(struct net_device *dev,
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
if (ingress) {
+ /* All the filter types of this matchall rule save the
+ * same cookie. So, checking for the first one is
+ * enough.
+ */
if (cls_matchall->cookie !=
- tc_port_matchall->ingress.fs.tc_cookie)
+ tc_port_matchall->ingress.fs[0].tc_cookie)
return -ENOENT;
return cxgb4_matchall_free_filter(dev);
@@ -326,27 +424,35 @@ int cxgb4_tc_matchall_destroy(struct net_device *dev,
int cxgb4_tc_matchall_stats(struct net_device *dev,
struct tc_cls_matchall_offload *cls_matchall)
{
+ u64 tmp_packets, tmp_bytes, packets = 0, bytes = 0;
struct cxgb4_tc_port_matchall *tc_port_matchall;
+ struct cxgb4_matchall_ingress_entry *ingress;
struct port_info *pi = netdev2pinfo(dev);
struct adapter *adap = netdev2adap(dev);
- u64 packets, bytes;
int ret;
+ u8 i;
tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
if (tc_port_matchall->ingress.state == CXGB4_MATCHALL_STATE_DISABLED)
return -ENOENT;
- ret = cxgb4_get_filter_counters(dev, tc_port_matchall->ingress.tid,
- &packets, &bytes,
- tc_port_matchall->ingress.fs.hash);
- if (ret)
- return ret;
+ ingress = &tc_port_matchall->ingress;
+ for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {
+ ret = cxgb4_get_filter_counters(dev, ingress->tid[i],
+ &tmp_packets, &tmp_bytes,
+ ingress->fs[i].hash);
+ if (ret)
+ return ret;
+
+ packets += tmp_packets;
+ bytes += tmp_bytes;
+ }
if (tc_port_matchall->ingress.packets != packets) {
flow_stats_update(&cls_matchall->stats,
bytes - tc_port_matchall->ingress.bytes,
packets - tc_port_matchall->ingress.packets,
- tc_port_matchall->ingress.last_used,
+ 0, tc_port_matchall->ingress.last_used,
FLOW_ACTION_HW_STATS_IMMEDIATE);
tc_port_matchall->ingress.packets = packets;