| // SPDX-License-Identifier: GPL-2.0+ |
| /* Microchip VCAP API |
| * |
| * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. |
| */ |
| |
| #include "sparx5_tc.h" |
| #include "vcap_api.h" |
| #include "vcap_api_client.h" |
| #include "sparx5_main_regs.h" |
| #include "sparx5_main.h" |
| #include "sparx5_vcap_impl.h" |
| |
| static int sparx5_tc_matchall_replace(struct net_device *ndev, |
| struct tc_cls_matchall_offload *tmo, |
| bool ingress) |
| { |
| struct sparx5_port *port = netdev_priv(ndev); |
| struct flow_action_entry *action; |
| struct sparx5 *sparx5; |
| int err; |
| |
| if (!flow_offload_has_one_action(&tmo->rule->action)) { |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, |
| "Only one action per filter is supported"); |
| return -EOPNOTSUPP; |
| } |
| action = &tmo->rule->action.entries[0]; |
| |
| sparx5 = port->sparx5; |
| switch (action->id) { |
| case FLOW_ACTION_GOTO: |
| err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, |
| action->chain_index, tmo->cookie, |
| true); |
| if (err == -EFAULT) { |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, |
| "Unsupported goto chain"); |
| return -EOPNOTSUPP; |
| } |
| if (err == -EADDRINUSE) { |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, |
| "VCAP already enabled"); |
| return -EOPNOTSUPP; |
| } |
| if (err) { |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, |
| "Could not enable VCAP lookups"); |
| return err; |
| } |
| break; |
| default: |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); |
| return -EOPNOTSUPP; |
| } |
| return 0; |
| } |
| |
| static int sparx5_tc_matchall_destroy(struct net_device *ndev, |
| struct tc_cls_matchall_offload *tmo, |
| bool ingress) |
| { |
| struct sparx5_port *port = netdev_priv(ndev); |
| struct sparx5 *sparx5; |
| int err; |
| |
| sparx5 = port->sparx5; |
| if (!tmo->rule && tmo->cookie) { |
| err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0, |
| tmo->cookie, false); |
| if (err) |
| return err; |
| return 0; |
| } |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action"); |
| return -EOPNOTSUPP; |
| } |
| |
| int sparx5_tc_matchall(struct net_device *ndev, |
| struct tc_cls_matchall_offload *tmo, |
| bool ingress) |
| { |
| if (!tc_cls_can_offload_and_chain0(ndev, &tmo->common)) { |
| NL_SET_ERR_MSG_MOD(tmo->common.extack, |
| "Only chain zero is supported"); |
| return -EOPNOTSUPP; |
| } |
| |
| switch (tmo->command) { |
| case TC_CLSMATCHALL_REPLACE: |
| return sparx5_tc_matchall_replace(ndev, tmo, ingress); |
| case TC_CLSMATCHALL_DESTROY: |
| return sparx5_tc_matchall_destroy(ndev, tmo, ingress); |
| default: |
| return -EOPNOTSUPP; |
| } |
| } |