diff options
Diffstat (limited to 'drivers/net/ethernet/marvell/prestera/prestera_acl.c')
-rw-r--r-- | drivers/net/ethernet/marvell/prestera/prestera_acl.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.c b/drivers/net/ethernet/marvell/prestera/prestera_acl.c index 3a141f2db812..3d4b85f2d541 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.c @@ -61,6 +61,7 @@ struct prestera_acl_ruleset { u32 index; u16 pcl_id; bool offload; + bool ingress; }; struct prestera_acl_vtcam { @@ -70,6 +71,7 @@ struct prestera_acl_vtcam { u32 id; bool is_keymask_set; u8 lookup; + u8 direction; }; static const struct rhashtable_params prestera_acl_ruleset_ht_params = { @@ -93,23 +95,36 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = { .automatic_shrinking = true, }; -int prestera_acl_chain_to_client(u32 chain_index, u32 *client) +int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client) { - static const u32 client_map[] = { - PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0, - PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1, - PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 + static const u32 ingress_client_map[] = { + PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0, + PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1, + PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2 }; - if (chain_index >= ARRAY_SIZE(client_map)) + if (!ingress) { + /* prestera supports only one chain on egress */ + if (chain_index > 0) + return -EINVAL; + + *client = PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP; + return 0; + } + + if (chain_index >= ARRAY_SIZE(ingress_client_map)) return -EINVAL; - *client = client_map[chain_index]; + *client = ingress_client_map[chain_index]; return 0; } -static bool prestera_acl_chain_is_supported(u32 chain_index) +static bool prestera_acl_chain_is_supported(u32 chain_index, bool ingress) { + if (!ingress) + /* prestera supports only one chain on egress */ + return chain_index == 0; + return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0; } @@ -122,7 +137,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl, u32 uid = 0; int err; - if (!prestera_acl_chain_is_supported(chain_index)) + if (!prestera_acl_chain_is_supported(chain_index, block->ingress)) return ERR_PTR(-EINVAL); ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL); @@ -130,6 +145,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl, return ERR_PTR(-ENOMEM); ruleset->acl = acl; + ruleset->ingress = block->ingress; ruleset->ht_key.block = block; ruleset->ht_key.chain_index = chain_index; refcount_set(&ruleset->refcount, 1); @@ -172,13 +188,18 @@ int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset) { struct prestera_acl_iface iface; u32 vtcam_id; + int dir; int err; + dir = ruleset->ingress ? + PRESTERA_HW_VTCAM_DIR_INGRESS : PRESTERA_HW_VTCAM_DIR_EGRESS; + if (ruleset->offload) return -EEXIST; err = prestera_acl_vtcam_id_get(ruleset->acl, ruleset->ht_key.chain_index, + dir, ruleset->keymask, &vtcam_id); if (err) goto err_vtcam_create; @@ -719,7 +740,7 @@ vtcam_found: return 0; } -int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, +int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir, void *keymask, u32 *vtcam_id) { struct prestera_acl_vtcam *vtcam; @@ -731,7 +752,8 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, * fine for now */ list_for_each_entry(vtcam, &acl->vtcam_list, list) { - if (lookup != vtcam->lookup) + if (lookup != vtcam->lookup || + dir != vtcam->direction) continue; if (!keymask && !vtcam->is_keymask_set) { @@ -752,7 +774,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, return -ENOMEM; err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id, - PRESTERA_HW_VTCAM_DIR_INGRESS); + dir); if (err) { kfree(vtcam); @@ -765,6 +787,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, return 0; } + vtcam->direction = dir; vtcam->id = new_vtcam_id; vtcam->lookup = lookup; if (keymask) { |