162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci#include "dpaa2-eth.h" 362306a36Sopenharmony_ci/* Copyright 2020 NXP 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define DPAA2_ETH_TRAP_DROP(_id, _group_id) \ 762306a36Sopenharmony_ci DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 862306a36Sopenharmony_ci DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, 0) 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic const struct devlink_trap_group dpaa2_eth_trap_groups_arr[] = { 1162306a36Sopenharmony_ci DEVLINK_TRAP_GROUP_GENERIC(PARSER_ERROR_DROPS, 0), 1262306a36Sopenharmony_ci}; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic const struct devlink_trap dpaa2_eth_traps_arr[] = { 1562306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(VXLAN_PARSING, PARSER_ERROR_DROPS), 1662306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(LLC_SNAP_PARSING, PARSER_ERROR_DROPS), 1762306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(VLAN_PARSING, PARSER_ERROR_DROPS), 1862306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(PPPOE_PPP_PARSING, PARSER_ERROR_DROPS), 1962306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(MPLS_PARSING, PARSER_ERROR_DROPS), 2062306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(ARP_PARSING, PARSER_ERROR_DROPS), 2162306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(IP_1_PARSING, PARSER_ERROR_DROPS), 2262306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(IP_N_PARSING, PARSER_ERROR_DROPS), 2362306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(GRE_PARSING, PARSER_ERROR_DROPS), 2462306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(UDP_PARSING, PARSER_ERROR_DROPS), 2562306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(TCP_PARSING, PARSER_ERROR_DROPS), 2662306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(IPSEC_PARSING, PARSER_ERROR_DROPS), 2762306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(SCTP_PARSING, PARSER_ERROR_DROPS), 2862306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(DCCP_PARSING, PARSER_ERROR_DROPS), 2962306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(GTP_PARSING, PARSER_ERROR_DROPS), 3062306a36Sopenharmony_ci DPAA2_ETH_TRAP_DROP(ESP_PARSING, PARSER_ERROR_DROPS), 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int dpaa2_eth_dl_info_get(struct devlink *devlink, 3462306a36Sopenharmony_ci struct devlink_info_req *req, 3562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); 3862306a36Sopenharmony_ci struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; 3962306a36Sopenharmony_ci char buf[10]; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci scnprintf(buf, 10, "%d.%d", priv->dpni_ver_major, priv->dpni_ver_minor); 4262306a36Sopenharmony_ci return devlink_info_version_running_put(req, "dpni", buf); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct dpaa2_eth_trap_item * 4662306a36Sopenharmony_cidpaa2_eth_dl_trap_item_lookup(struct dpaa2_eth_priv *priv, u16 trap_id) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct dpaa2_eth_trap_data *dpaa2_eth_trap_data = priv->trap_data; 4962306a36Sopenharmony_ci int i; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dpaa2_eth_traps_arr); i++) { 5262306a36Sopenharmony_ci if (dpaa2_eth_traps_arr[i].id == trap_id) 5362306a36Sopenharmony_ci return &dpaa2_eth_trap_data->trap_items_arr[i]; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return NULL; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct dpaa2_eth_trap_item *dpaa2_eth_dl_get_trap(struct dpaa2_eth_priv *priv, 6062306a36Sopenharmony_ci struct dpaa2_fapr *fapr) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci static const struct dpaa2_faf_error_bit { 6362306a36Sopenharmony_ci int position; 6462306a36Sopenharmony_ci enum devlink_trap_generic_id trap_id; 6562306a36Sopenharmony_ci } faf_bits[] = { 6662306a36Sopenharmony_ci { .position = 5, .trap_id = DEVLINK_TRAP_GENERIC_ID_VXLAN_PARSING }, 6762306a36Sopenharmony_ci { .position = 20, .trap_id = DEVLINK_TRAP_GENERIC_ID_LLC_SNAP_PARSING }, 6862306a36Sopenharmony_ci { .position = 24, .trap_id = DEVLINK_TRAP_GENERIC_ID_VLAN_PARSING }, 6962306a36Sopenharmony_ci { .position = 26, .trap_id = DEVLINK_TRAP_GENERIC_ID_PPPOE_PPP_PARSING }, 7062306a36Sopenharmony_ci { .position = 29, .trap_id = DEVLINK_TRAP_GENERIC_ID_MPLS_PARSING }, 7162306a36Sopenharmony_ci { .position = 31, .trap_id = DEVLINK_TRAP_GENERIC_ID_ARP_PARSING }, 7262306a36Sopenharmony_ci { .position = 52, .trap_id = DEVLINK_TRAP_GENERIC_ID_IP_1_PARSING }, 7362306a36Sopenharmony_ci { .position = 61, .trap_id = DEVLINK_TRAP_GENERIC_ID_IP_N_PARSING }, 7462306a36Sopenharmony_ci { .position = 67, .trap_id = DEVLINK_TRAP_GENERIC_ID_GRE_PARSING }, 7562306a36Sopenharmony_ci { .position = 71, .trap_id = DEVLINK_TRAP_GENERIC_ID_UDP_PARSING }, 7662306a36Sopenharmony_ci { .position = 76, .trap_id = DEVLINK_TRAP_GENERIC_ID_TCP_PARSING }, 7762306a36Sopenharmony_ci { .position = 80, .trap_id = DEVLINK_TRAP_GENERIC_ID_IPSEC_PARSING }, 7862306a36Sopenharmony_ci { .position = 82, .trap_id = DEVLINK_TRAP_GENERIC_ID_SCTP_PARSING }, 7962306a36Sopenharmony_ci { .position = 84, .trap_id = DEVLINK_TRAP_GENERIC_ID_DCCP_PARSING }, 8062306a36Sopenharmony_ci { .position = 88, .trap_id = DEVLINK_TRAP_GENERIC_ID_GTP_PARSING }, 8162306a36Sopenharmony_ci { .position = 90, .trap_id = DEVLINK_TRAP_GENERIC_ID_ESP_PARSING }, 8262306a36Sopenharmony_ci }; 8362306a36Sopenharmony_ci u64 faf_word; 8462306a36Sopenharmony_ci u64 mask; 8562306a36Sopenharmony_ci int i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(faf_bits); i++) { 8862306a36Sopenharmony_ci if (faf_bits[i].position < 32) { 8962306a36Sopenharmony_ci /* Low part of FAF. 9062306a36Sopenharmony_ci * position ranges from 31 to 0, mask from 0 to 31. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci mask = 1ull << (31 - faf_bits[i].position); 9362306a36Sopenharmony_ci faf_word = __le32_to_cpu(fapr->faf_lo); 9462306a36Sopenharmony_ci } else { 9562306a36Sopenharmony_ci /* High part of FAF. 9662306a36Sopenharmony_ci * position ranges from 95 to 32, mask from 0 to 63. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci mask = 1ull << (63 - (faf_bits[i].position - 32)); 9962306a36Sopenharmony_ci faf_word = __le64_to_cpu(fapr->faf_hi); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci if (faf_word & mask) 10262306a36Sopenharmony_ci return dpaa2_eth_dl_trap_item_lookup(priv, faf_bits[i].trap_id); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci return NULL; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int dpaa2_eth_dl_trap_init(struct devlink *devlink, 10862306a36Sopenharmony_ci const struct devlink_trap *trap, 10962306a36Sopenharmony_ci void *trap_ctx) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); 11262306a36Sopenharmony_ci struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; 11362306a36Sopenharmony_ci struct dpaa2_eth_trap_item *dpaa2_eth_trap_item; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci dpaa2_eth_trap_item = dpaa2_eth_dl_trap_item_lookup(priv, trap->id); 11662306a36Sopenharmony_ci if (WARN_ON(!dpaa2_eth_trap_item)) 11762306a36Sopenharmony_ci return -ENOENT; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci dpaa2_eth_trap_item->trap_ctx = trap_ctx; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int dpaa2_eth_dl_trap_action_set(struct devlink *devlink, 12562306a36Sopenharmony_ci const struct devlink_trap *trap, 12662306a36Sopenharmony_ci enum devlink_trap_action action, 12762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci /* No support for changing the action of an independent packet trap, 13062306a36Sopenharmony_ci * only per trap group - parser error drops 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 13362306a36Sopenharmony_ci "Cannot change trap action independently of group"); 13462306a36Sopenharmony_ci return -EOPNOTSUPP; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int dpaa2_eth_dl_trap_group_action_set(struct devlink *devlink, 13862306a36Sopenharmony_ci const struct devlink_trap_group *group, 13962306a36Sopenharmony_ci enum devlink_trap_action action, 14062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct dpaa2_eth_devlink_priv *dl_priv = devlink_priv(devlink); 14362306a36Sopenharmony_ci struct dpaa2_eth_priv *priv = dl_priv->dpaa2_priv; 14462306a36Sopenharmony_ci struct net_device *net_dev = priv->net_dev; 14562306a36Sopenharmony_ci struct device *dev = net_dev->dev.parent; 14662306a36Sopenharmony_ci struct dpni_error_cfg err_cfg = {0}; 14762306a36Sopenharmony_ci int err; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (group->id != DEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS) 15062306a36Sopenharmony_ci return -EOPNOTSUPP; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Configure handling of frames marked as errors from the parser */ 15362306a36Sopenharmony_ci err_cfg.errors = DPAA2_FAS_RX_ERR_MASK; 15462306a36Sopenharmony_ci err_cfg.set_frame_annotation = 1; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci switch (action) { 15762306a36Sopenharmony_ci case DEVLINK_TRAP_ACTION_DROP: 15862306a36Sopenharmony_ci err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case DEVLINK_TRAP_ACTION_TRAP: 16162306a36Sopenharmony_ci err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci default: 16462306a36Sopenharmony_ci return -EOPNOTSUPP; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token, &err_cfg); 16862306a36Sopenharmony_ci if (err) { 16962306a36Sopenharmony_ci dev_err(dev, "dpni_set_errors_behavior failed\n"); 17062306a36Sopenharmony_ci return err; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const struct devlink_ops dpaa2_eth_devlink_ops = { 17762306a36Sopenharmony_ci .info_get = dpaa2_eth_dl_info_get, 17862306a36Sopenharmony_ci .trap_init = dpaa2_eth_dl_trap_init, 17962306a36Sopenharmony_ci .trap_action_set = dpaa2_eth_dl_trap_action_set, 18062306a36Sopenharmony_ci .trap_group_action_set = dpaa2_eth_dl_trap_group_action_set, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint dpaa2_eth_dl_alloc(struct dpaa2_eth_priv *priv) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct net_device *net_dev = priv->net_dev; 18662306a36Sopenharmony_ci struct device *dev = net_dev->dev.parent; 18762306a36Sopenharmony_ci struct dpaa2_eth_devlink_priv *dl_priv; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci priv->devlink = 19062306a36Sopenharmony_ci devlink_alloc(&dpaa2_eth_devlink_ops, sizeof(*dl_priv), dev); 19162306a36Sopenharmony_ci if (!priv->devlink) { 19262306a36Sopenharmony_ci dev_err(dev, "devlink_alloc failed\n"); 19362306a36Sopenharmony_ci return -ENOMEM; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci dl_priv = devlink_priv(priv->devlink); 19662306a36Sopenharmony_ci dl_priv->dpaa2_priv = priv; 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid dpaa2_eth_dl_free(struct dpaa2_eth_priv *priv) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci devlink_free(priv->devlink); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_civoid dpaa2_eth_dl_register(struct dpaa2_eth_priv *priv) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci devlink_register(priv->devlink); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_civoid dpaa2_eth_dl_unregister(struct dpaa2_eth_priv *priv) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci devlink_unregister(priv->devlink); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ciint dpaa2_eth_dl_port_add(struct dpaa2_eth_priv *priv) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct devlink_port *devlink_port = &priv->devlink_port; 21962306a36Sopenharmony_ci struct devlink_port_attrs attrs = {}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 22262306a36Sopenharmony_ci devlink_port_attrs_set(devlink_port, &attrs); 22362306a36Sopenharmony_ci return devlink_port_register(priv->devlink, devlink_port, 0); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_civoid dpaa2_eth_dl_port_del(struct dpaa2_eth_priv *priv) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct devlink_port *devlink_port = &priv->devlink_port; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci devlink_port_unregister(devlink_port); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ciint dpaa2_eth_dl_traps_register(struct dpaa2_eth_priv *priv) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct dpaa2_eth_trap_data *dpaa2_eth_trap_data; 23662306a36Sopenharmony_ci struct net_device *net_dev = priv->net_dev; 23762306a36Sopenharmony_ci struct device *dev = net_dev->dev.parent; 23862306a36Sopenharmony_ci int err; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci dpaa2_eth_trap_data = kzalloc(sizeof(*dpaa2_eth_trap_data), GFP_KERNEL); 24162306a36Sopenharmony_ci if (!dpaa2_eth_trap_data) 24262306a36Sopenharmony_ci return -ENOMEM; 24362306a36Sopenharmony_ci priv->trap_data = dpaa2_eth_trap_data; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci dpaa2_eth_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(dpaa2_eth_traps_arr), 24662306a36Sopenharmony_ci sizeof(struct dpaa2_eth_trap_item), 24762306a36Sopenharmony_ci GFP_KERNEL); 24862306a36Sopenharmony_ci if (!dpaa2_eth_trap_data->trap_items_arr) { 24962306a36Sopenharmony_ci err = -ENOMEM; 25062306a36Sopenharmony_ci goto trap_data_free; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci err = devlink_trap_groups_register(priv->devlink, dpaa2_eth_trap_groups_arr, 25462306a36Sopenharmony_ci ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); 25562306a36Sopenharmony_ci if (err) { 25662306a36Sopenharmony_ci dev_err(dev, "devlink_trap_groups_register() = %d\n", err); 25762306a36Sopenharmony_ci goto trap_items_arr_free; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci err = devlink_traps_register(priv->devlink, dpaa2_eth_traps_arr, 26162306a36Sopenharmony_ci ARRAY_SIZE(dpaa2_eth_traps_arr), priv); 26262306a36Sopenharmony_ci if (err) { 26362306a36Sopenharmony_ci dev_err(dev, "devlink_traps_register() = %d\n", err); 26462306a36Sopenharmony_ci goto trap_groups_unregiser; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_citrap_groups_unregiser: 27062306a36Sopenharmony_ci devlink_trap_groups_unregister(priv->devlink, dpaa2_eth_trap_groups_arr, 27162306a36Sopenharmony_ci ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); 27262306a36Sopenharmony_citrap_items_arr_free: 27362306a36Sopenharmony_ci kfree(dpaa2_eth_trap_data->trap_items_arr); 27462306a36Sopenharmony_citrap_data_free: 27562306a36Sopenharmony_ci kfree(dpaa2_eth_trap_data); 27662306a36Sopenharmony_ci priv->trap_data = NULL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return err; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_civoid dpaa2_eth_dl_traps_unregister(struct dpaa2_eth_priv *priv) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci devlink_traps_unregister(priv->devlink, dpaa2_eth_traps_arr, 28462306a36Sopenharmony_ci ARRAY_SIZE(dpaa2_eth_traps_arr)); 28562306a36Sopenharmony_ci devlink_trap_groups_unregister(priv->devlink, dpaa2_eth_trap_groups_arr, 28662306a36Sopenharmony_ci ARRAY_SIZE(dpaa2_eth_trap_groups_arr)); 28762306a36Sopenharmony_ci kfree(priv->trap_data->trap_items_arr); 28862306a36Sopenharmony_ci kfree(priv->trap_data); 28962306a36Sopenharmony_ci} 290