summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/microchip/vcap/vcap_api.c
diff options
context:
space:
mode:
authorSteen Hegelund <steen.hegelund@microchip.com>2023-01-24 11:45:08 +0100
committerPaolo Abeni <pabeni@redhat.com>2023-01-26 10:07:44 +0100
commit88bd9ea70b2ec59298125ff2bf9837034d73e3b7 (patch)
tree3eb0569ca66b1437ff43cd07640a4addb3140235 /drivers/net/ethernet/microchip/vcap/vcap_api.c
parent542e6e2c20e502cd8829304c5b4d6a45460d0a51 (diff)
downloadlinux-88bd9ea70b2ec59298125ff2bf9837034d73e3b7.tar.gz
linux-88bd9ea70b2ec59298125ff2bf9837034d73e3b7.tar.bz2
linux-88bd9ea70b2ec59298125ff2bf9837034d73e3b7.zip
net: microchip: sparx5: Add TC filter chaining support for IS0 and IS2 VCAPs
This allows rules to be chained between VCAP instances, e.g. from IS0 Lookup 0 to IS0 Lookup 1, or from one of the IS0 Lookups to one of the IS2 Lookups. Chaining from an IS2 Lookup to another IS2 Lookup is not supported in the hardware. Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'drivers/net/ethernet/microchip/vcap/vcap_api.c')
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_api.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index c740e83d9c20..258b0a397d37 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -1601,6 +1601,40 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
}
EXPORT_SYMBOL_GPL(vcap_find_admin);
+/* Is this the last admin instance ordered by chain id */
+static bool vcap_admin_is_last(struct vcap_control *vctrl,
+ struct vcap_admin *admin)
+{
+ struct vcap_admin *iter, *last = NULL;
+ int max_cid = 0;
+
+ list_for_each_entry(iter, &vctrl->list, list) {
+ if (iter->first_cid > max_cid) {
+ last = iter;
+ max_cid = iter->first_cid;
+ }
+ }
+ if (!last)
+ return false;
+
+ return admin == last;
+}
+
+/* Calculate the value used for chaining VCAP rules */
+int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid)
+{
+ int diff = to_cid - from_cid;
+
+ if (diff < 0) /* Wrong direction */
+ return diff;
+ to_cid %= VCAP_CID_LOOKUP_SIZE;
+ if (to_cid == 0) /* Destination aligned to a lookup == no chaining */
+ return 0;
+ diff %= VCAP_CID_LOOKUP_SIZE; /* Limit to a value within a lookup */
+ return diff;
+}
+EXPORT_SYMBOL_GPL(vcap_chain_offset);
+
/* Is the next chain id in one of the following lookups
* For now this does not support filters linked to other filters using
* keys and actions. That will be added later.
@@ -2825,6 +2859,7 @@ out:
static int vcap_enable_rules(struct vcap_control *vctrl,
struct net_device *ndev, int chain)
{
+ int next_chain = chain + VCAP_CID_LOOKUP_SIZE;
struct vcap_rule_internal *ri;
struct vcap_admin *admin;
int err = 0;
@@ -2836,8 +2871,11 @@ static int vcap_enable_rules(struct vcap_control *vctrl,
/* Found the admin, now find the offloadable rules */
mutex_lock(&admin->lock);
list_for_each_entry(ri, &admin->rules, list) {
- if (ri->data.vcap_chain_id != chain)
+ /* Is the rule in the lookup defined by the chain */
+ if (!(ri->data.vcap_chain_id >= chain &&
+ ri->data.vcap_chain_id < next_chain)) {
continue;
+ }
if (ri->ndev != ndev)
continue;
@@ -3054,6 +3092,9 @@ bool vcap_is_last_chain(struct vcap_control *vctrl, int cid)
if (!admin)
return false;
+ if (!vcap_admin_is_last(vctrl, admin))
+ return false;
+
/* This must be the last lookup in this VCAP type */
lookup = vcap_chain_id_to_lookup(admin, cid);
return lookup == admin->lookups - 1;