18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci/* Copyright (C) 2018 Netronome Systems, Inc. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 58c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 68c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 78c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 108c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "../nfpcore/nfp.h" 148c2ecf20Sopenharmony_ci#include "../nfpcore/nfp_cpp.h" 158c2ecf20Sopenharmony_ci#include "../nfpcore/nfp_nsp.h" 168c2ecf20Sopenharmony_ci#include "../nfp_app.h" 178c2ecf20Sopenharmony_ci#include "../nfp_main.h" 188c2ecf20Sopenharmony_ci#include "../nfp_net.h" 198c2ecf20Sopenharmony_ci#include "../nfp_net_repr.h" 208c2ecf20Sopenharmony_ci#include "../nfp_port.h" 218c2ecf20Sopenharmony_ci#include "main.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) | 268c2ecf20Sopenharmony_ci FIELD_PREP(NFP_ABM_PORTID_ID, id); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int 308c2ecf20Sopenharmony_cinfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev, 318c2ecf20Sopenharmony_ci enum tc_setup_type type, void *type_data) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct nfp_repr *repr = netdev_priv(netdev); 348c2ecf20Sopenharmony_ci struct nfp_port *port; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci port = nfp_port_from_netdev(netdev); 378c2ecf20Sopenharmony_ci if (!port || port->type != NFP_PORT_PF_PORT) 388c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci switch (type) { 418c2ecf20Sopenharmony_ci case TC_SETUP_ROOT_QDISC: 428c2ecf20Sopenharmony_ci return nfp_abm_setup_root(netdev, repr->app_priv, type_data); 438c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_MQ: 448c2ecf20Sopenharmony_ci return nfp_abm_setup_tc_mq(netdev, repr->app_priv, type_data); 458c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_RED: 468c2ecf20Sopenharmony_ci return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data); 478c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_GRED: 488c2ecf20Sopenharmony_ci return nfp_abm_setup_tc_gred(netdev, repr->app_priv, type_data); 498c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 508c2ecf20Sopenharmony_ci return nfp_abm_setup_cls_block(netdev, repr, type_data); 518c2ecf20Sopenharmony_ci default: 528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct net_device * 578c2ecf20Sopenharmony_cinfp_abm_repr_get(struct nfp_app *app, u32 port_id, bool *redir_egress) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci enum nfp_repr_type rtype; 608c2ecf20Sopenharmony_ci struct nfp_reprs *reprs; 618c2ecf20Sopenharmony_ci u8 port; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id); 648c2ecf20Sopenharmony_ci port = FIELD_GET(NFP_ABM_PORTID_ID, port_id); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci reprs = rcu_dereference(app->reprs[rtype]); 678c2ecf20Sopenharmony_ci if (!reprs) 688c2ecf20Sopenharmony_ci return NULL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (port >= reprs->num_reprs) 718c2ecf20Sopenharmony_ci return NULL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return rcu_dereference(reprs->reprs[port]); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int 778c2ecf20Sopenharmony_cinfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink, 788c2ecf20Sopenharmony_ci enum nfp_port_type ptype) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct net_device *netdev; 818c2ecf20Sopenharmony_ci enum nfp_repr_type rtype; 828c2ecf20Sopenharmony_ci struct nfp_reprs *reprs; 838c2ecf20Sopenharmony_ci struct nfp_repr *repr; 848c2ecf20Sopenharmony_ci struct nfp_port *port; 858c2ecf20Sopenharmony_ci unsigned int txqs; 868c2ecf20Sopenharmony_ci int err; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (ptype == NFP_PORT_PHYS_PORT) { 898c2ecf20Sopenharmony_ci rtype = NFP_REPR_TYPE_PHYS_PORT; 908c2ecf20Sopenharmony_ci txqs = 1; 918c2ecf20Sopenharmony_ci } else { 928c2ecf20Sopenharmony_ci rtype = NFP_REPR_TYPE_PF; 938c2ecf20Sopenharmony_ci txqs = alink->vnic->max_rx_rings; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci netdev = nfp_repr_alloc_mqs(app, txqs, 1); 978c2ecf20Sopenharmony_ci if (!netdev) 988c2ecf20Sopenharmony_ci return -ENOMEM; 998c2ecf20Sopenharmony_ci repr = netdev_priv(netdev); 1008c2ecf20Sopenharmony_ci repr->app_priv = alink; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci port = nfp_port_alloc(app, ptype, netdev); 1038c2ecf20Sopenharmony_ci if (IS_ERR(port)) { 1048c2ecf20Sopenharmony_ci err = PTR_ERR(port); 1058c2ecf20Sopenharmony_ci goto err_free_repr; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (ptype == NFP_PORT_PHYS_PORT) { 1098c2ecf20Sopenharmony_ci port->eth_forced = true; 1108c2ecf20Sopenharmony_ci err = nfp_port_init_phy_port(app->pf, app, port, alink->id); 1118c2ecf20Sopenharmony_ci if (err) 1128c2ecf20Sopenharmony_ci goto err_free_port; 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci port->pf_id = alink->abm->pf_id; 1158c2ecf20Sopenharmony_ci port->pf_split = app->pf->max_data_vnics > 1; 1168c2ecf20Sopenharmony_ci port->pf_split_id = alink->id; 1178c2ecf20Sopenharmony_ci port->vnic = alink->vnic->dp.ctrl_bar; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev); 1218c2ecf20Sopenharmony_ci eth_hw_addr_random(netdev); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id), 1248c2ecf20Sopenharmony_ci port, alink->vnic->dp.netdev); 1258c2ecf20Sopenharmony_ci if (err) 1268c2ecf20Sopenharmony_ci goto err_free_port; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci reprs = nfp_reprs_get_locked(app, rtype); 1298c2ecf20Sopenharmony_ci WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr"); 1308c2ecf20Sopenharmony_ci rtnl_lock(); 1318c2ecf20Sopenharmony_ci rcu_assign_pointer(reprs->reprs[alink->id], netdev); 1328c2ecf20Sopenharmony_ci rtnl_unlock(); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci nfp_info(app->cpp, "%s Port %d Representor(%s) created\n", 1358c2ecf20Sopenharmony_ci ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys", 1368c2ecf20Sopenharmony_ci alink->id, netdev->name); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cierr_free_port: 1418c2ecf20Sopenharmony_ci nfp_port_free(port); 1428c2ecf20Sopenharmony_cierr_free_repr: 1438c2ecf20Sopenharmony_ci nfp_repr_free(netdev); 1448c2ecf20Sopenharmony_ci return err; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void 1488c2ecf20Sopenharmony_cinfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink, 1498c2ecf20Sopenharmony_ci enum nfp_repr_type rtype) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct net_device *netdev; 1528c2ecf20Sopenharmony_ci struct nfp_reprs *reprs; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci reprs = nfp_reprs_get_locked(app, rtype); 1558c2ecf20Sopenharmony_ci netdev = nfp_repr_get_locked(app, reprs, alink->id); 1568c2ecf20Sopenharmony_ci if (!netdev) 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci rtnl_lock(); 1598c2ecf20Sopenharmony_ci rcu_assign_pointer(reprs->reprs[alink->id], NULL); 1608c2ecf20Sopenharmony_ci rtnl_unlock(); 1618c2ecf20Sopenharmony_ci synchronize_rcu(); 1628c2ecf20Sopenharmony_ci /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */ 1638c2ecf20Sopenharmony_ci nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev)); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void 1678c2ecf20Sopenharmony_cinfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF); 1708c2ecf20Sopenharmony_ci nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void nfp_abm_kill_reprs_all(struct nfp_abm *abm) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct nfp_pf *pf = abm->app->pf; 1768c2ecf20Sopenharmony_ci struct nfp_net *nn; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci list_for_each_entry(nn, &pf->vnics, vnic_list) 1798c2ecf20Sopenharmony_ci nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct nfp_abm *abm = app->priv; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return abm->eswitch_mode; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci nfp_abm_kill_reprs_all(abm); 1928c2ecf20Sopenharmony_ci nfp_abm_ctrl_qm_disable(abm); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void nfp_abm_eswitch_clean_up(struct nfp_abm *abm) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY) 2018c2ecf20Sopenharmony_ci WARN_ON(nfp_abm_eswitch_set_legacy(abm)); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct nfp_app *app = abm->app; 2078c2ecf20Sopenharmony_ci struct nfp_pf *pf = app->pf; 2088c2ecf20Sopenharmony_ci struct nfp_net *nn; 2098c2ecf20Sopenharmony_ci int err; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (!abm->red_support) 2128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci err = nfp_abm_ctrl_qm_enable(abm); 2158c2ecf20Sopenharmony_ci if (err) 2168c2ecf20Sopenharmony_ci return err; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci list_for_each_entry(nn, &pf->vnics, vnic_list) { 2198c2ecf20Sopenharmony_ci struct nfp_abm_link *alink = nn->app_priv; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT); 2228c2ecf20Sopenharmony_ci if (err) 2238c2ecf20Sopenharmony_ci goto err_kill_all_reprs; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT); 2268c2ecf20Sopenharmony_ci if (err) 2278c2ecf20Sopenharmony_ci goto err_kill_all_reprs; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cierr_kill_all_reprs: 2348c2ecf20Sopenharmony_ci nfp_abm_kill_reprs_all(abm); 2358c2ecf20Sopenharmony_ci nfp_abm_ctrl_qm_disable(abm); 2368c2ecf20Sopenharmony_ci return err; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct nfp_abm *abm = app->priv; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (abm->eswitch_mode == mode) 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci switch (mode) { 2478c2ecf20Sopenharmony_ci case DEVLINK_ESWITCH_MODE_LEGACY: 2488c2ecf20Sopenharmony_ci return nfp_abm_eswitch_set_legacy(abm); 2498c2ecf20Sopenharmony_ci case DEVLINK_ESWITCH_MODE_SWITCHDEV: 2508c2ecf20Sopenharmony_ci return nfp_abm_eswitch_set_switchdev(abm); 2518c2ecf20Sopenharmony_ci default: 2528c2ecf20Sopenharmony_ci return -EINVAL; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void 2578c2ecf20Sopenharmony_cinfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn, 2588c2ecf20Sopenharmony_ci unsigned int id) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id]; 2618c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 2628c2ecf20Sopenharmony_ci struct nfp_nsp *nsp; 2638c2ecf20Sopenharmony_ci char hwinfo[32]; 2648c2ecf20Sopenharmony_ci int err; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (id > pf->eth_tbl->count) { 2678c2ecf20Sopenharmony_ci nfp_warn(pf->cpp, "No entry for persistent MAC address\n"); 2688c2ecf20Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac.pf%u", 2738c2ecf20Sopenharmony_ci eth_port->eth_index, abm->pf_id); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci nsp = nfp_nsp_open(pf->cpp); 2768c2ecf20Sopenharmony_ci if (IS_ERR(nsp)) { 2778c2ecf20Sopenharmony_ci nfp_warn(pf->cpp, "Failed to access the NSP for persistent MAC address: %ld\n", 2788c2ecf20Sopenharmony_ci PTR_ERR(nsp)); 2798c2ecf20Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!nfp_nsp_has_hwinfo_lookup(nsp)) { 2848c2ecf20Sopenharmony_ci nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n"); 2858c2ecf20Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 2868c2ecf20Sopenharmony_ci nfp_nsp_close(nsp); 2878c2ecf20Sopenharmony_ci return; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo)); 2918c2ecf20Sopenharmony_ci nfp_nsp_close(nsp); 2928c2ecf20Sopenharmony_ci if (err) { 2938c2ecf20Sopenharmony_ci nfp_warn(pf->cpp, "Reading persistent MAC address failed: %d\n", 2948c2ecf20Sopenharmony_ci err); 2958c2ecf20Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 2968c2ecf20Sopenharmony_ci return; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 3008c2ecf20Sopenharmony_ci &mac_addr[0], &mac_addr[1], &mac_addr[2], 3018c2ecf20Sopenharmony_ci &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { 3028c2ecf20Sopenharmony_ci nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n", 3038c2ecf20Sopenharmony_ci hwinfo); 3048c2ecf20Sopenharmony_ci eth_hw_addr_random(nn->dp.netdev); 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr); 3098c2ecf20Sopenharmony_ci ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int 3138c2ecf20Sopenharmony_cinfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id]; 3168c2ecf20Sopenharmony_ci struct nfp_abm *abm = app->priv; 3178c2ecf20Sopenharmony_ci struct nfp_abm_link *alink; 3188c2ecf20Sopenharmony_ci int err; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci alink = kzalloc(sizeof(*alink), GFP_KERNEL); 3218c2ecf20Sopenharmony_ci if (!alink) 3228c2ecf20Sopenharmony_ci return -ENOMEM; 3238c2ecf20Sopenharmony_ci nn->app_priv = alink; 3248c2ecf20Sopenharmony_ci alink->abm = abm; 3258c2ecf20Sopenharmony_ci alink->vnic = nn; 3268c2ecf20Sopenharmony_ci alink->id = id; 3278c2ecf20Sopenharmony_ci alink->total_queues = alink->vnic->max_rx_rings; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&alink->dscp_map); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = nfp_abm_ctrl_read_params(alink); 3328c2ecf20Sopenharmony_ci if (err) 3338c2ecf20Sopenharmony_ci goto err_free_alink; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci alink->prio_map = kzalloc(abm->prio_map_len, GFP_KERNEL); 3368c2ecf20Sopenharmony_ci if (!alink->prio_map) { 3378c2ecf20Sopenharmony_ci err = -ENOMEM; 3388c2ecf20Sopenharmony_ci goto err_free_alink; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* This is a multi-host app, make sure MAC/PHY is up, but don't 3428c2ecf20Sopenharmony_ci * make the MAC/PHY state follow the state of any of the ports. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci err = nfp_eth_set_configured(app->cpp, eth_port->index, true); 3458c2ecf20Sopenharmony_ci if (err < 0) 3468c2ecf20Sopenharmony_ci goto err_free_priomap; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci netif_keep_dst(nn->dp.netdev); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci nfp_abm_vnic_set_mac(app->pf, abm, nn, id); 3518c2ecf20Sopenharmony_ci INIT_RADIX_TREE(&alink->qdiscs, GFP_KERNEL); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cierr_free_priomap: 3568c2ecf20Sopenharmony_ci kfree(alink->prio_map); 3578c2ecf20Sopenharmony_cierr_free_alink: 3588c2ecf20Sopenharmony_ci kfree(alink); 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct nfp_abm_link *alink = nn->app_priv; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci nfp_abm_kill_reprs(alink->abm, alink); 3678c2ecf20Sopenharmony_ci WARN(!radix_tree_empty(&alink->qdiscs), "left over qdiscs\n"); 3688c2ecf20Sopenharmony_ci kfree(alink->prio_map); 3698c2ecf20Sopenharmony_ci kfree(alink); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int nfp_abm_vnic_init(struct nfp_app *app, struct nfp_net *nn) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct nfp_abm_link *alink = nn->app_priv; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (nfp_abm_has_prio(alink->abm)) 3778c2ecf20Sopenharmony_ci return nfp_abm_ctrl_prio_map_update(alink, alink->prio_map); 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic u64 * 3828c2ecf20Sopenharmony_cinfp_abm_port_get_stats(struct nfp_app *app, struct nfp_port *port, u64 *data) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct nfp_repr *repr = netdev_priv(port->netdev); 3858c2ecf20Sopenharmony_ci struct nfp_abm_link *alink; 3868c2ecf20Sopenharmony_ci unsigned int i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (port->type != NFP_PORT_PF_PORT) 3898c2ecf20Sopenharmony_ci return data; 3908c2ecf20Sopenharmony_ci alink = repr->app_priv; 3918c2ecf20Sopenharmony_ci for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) { 3928c2ecf20Sopenharmony_ci *data++ = nfp_abm_ctrl_stat_non_sto(alink, i); 3938c2ecf20Sopenharmony_ci *data++ = nfp_abm_ctrl_stat_sto(alink, i); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci return data; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int 3998c2ecf20Sopenharmony_cinfp_abm_port_get_stats_count(struct nfp_app *app, struct nfp_port *port) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct nfp_repr *repr = netdev_priv(port->netdev); 4028c2ecf20Sopenharmony_ci struct nfp_abm_link *alink; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (port->type != NFP_PORT_PF_PORT) 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci alink = repr->app_priv; 4078c2ecf20Sopenharmony_ci return alink->vnic->dp.num_r_vecs * 2; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic u8 * 4118c2ecf20Sopenharmony_cinfp_abm_port_get_stats_strings(struct nfp_app *app, struct nfp_port *port, 4128c2ecf20Sopenharmony_ci u8 *data) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct nfp_repr *repr = netdev_priv(port->netdev); 4158c2ecf20Sopenharmony_ci struct nfp_abm_link *alink; 4168c2ecf20Sopenharmony_ci unsigned int i; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (port->type != NFP_PORT_PF_PORT) 4198c2ecf20Sopenharmony_ci return data; 4208c2ecf20Sopenharmony_ci alink = repr->app_priv; 4218c2ecf20Sopenharmony_ci for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) { 4228c2ecf20Sopenharmony_ci data = nfp_pr_et(data, "q%u_no_wait", i); 4238c2ecf20Sopenharmony_ci data = nfp_pr_et(data, "q%u_delayed", i); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci return data; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int nfp_abm_fw_init_reset(struct nfp_abm *abm) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci unsigned int i; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (!abm->red_support) 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci for (i = 0; i < abm->num_bands * NFP_NET_MAX_RX_RINGS; i++) { 4368c2ecf20Sopenharmony_ci __nfp_abm_ctrl_set_q_lvl(abm, i, NFP_ABM_LVL_INFINITY); 4378c2ecf20Sopenharmony_ci __nfp_abm_ctrl_set_q_act(abm, i, NFP_ABM_ACT_DROP); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return nfp_abm_ctrl_qm_disable(abm); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int nfp_abm_init(struct nfp_app *app) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct nfp_pf *pf = app->pf; 4468c2ecf20Sopenharmony_ci struct nfp_reprs *reprs; 4478c2ecf20Sopenharmony_ci struct nfp_abm *abm; 4488c2ecf20Sopenharmony_ci int err; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!pf->eth_tbl) { 4518c2ecf20Sopenharmony_ci nfp_err(pf->cpp, "ABM NIC requires ETH table\n"); 4528c2ecf20Sopenharmony_ci return -EINVAL; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci if (pf->max_data_vnics != pf->eth_tbl->count) { 4558c2ecf20Sopenharmony_ci nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", 4568c2ecf20Sopenharmony_ci pf->max_data_vnics, pf->eth_tbl->count); 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci if (!pf->mac_stats_bar) { 4608c2ecf20Sopenharmony_ci nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n"); 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci abm = kzalloc(sizeof(*abm), GFP_KERNEL); 4658c2ecf20Sopenharmony_ci if (!abm) 4668c2ecf20Sopenharmony_ci return -ENOMEM; 4678c2ecf20Sopenharmony_ci app->priv = abm; 4688c2ecf20Sopenharmony_ci abm->app = app; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci err = nfp_abm_ctrl_find_addrs(abm); 4718c2ecf20Sopenharmony_ci if (err) 4728c2ecf20Sopenharmony_ci goto err_free_abm; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci err = -ENOMEM; 4758c2ecf20Sopenharmony_ci abm->num_thresholds = array_size(abm->num_bands, NFP_NET_MAX_RX_RINGS); 4768c2ecf20Sopenharmony_ci abm->threshold_undef = bitmap_zalloc(abm->num_thresholds, GFP_KERNEL); 4778c2ecf20Sopenharmony_ci if (!abm->threshold_undef) 4788c2ecf20Sopenharmony_ci goto err_free_abm; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci abm->thresholds = kvcalloc(abm->num_thresholds, 4818c2ecf20Sopenharmony_ci sizeof(*abm->thresholds), GFP_KERNEL); 4828c2ecf20Sopenharmony_ci if (!abm->thresholds) 4838c2ecf20Sopenharmony_ci goto err_free_thresh_umap; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci abm->actions = kvcalloc(abm->num_thresholds, sizeof(*abm->actions), 4868c2ecf20Sopenharmony_ci GFP_KERNEL); 4878c2ecf20Sopenharmony_ci if (!abm->actions) 4888c2ecf20Sopenharmony_ci goto err_free_thresh; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* We start in legacy mode, make sure advanced queuing is disabled */ 4918c2ecf20Sopenharmony_ci err = nfp_abm_fw_init_reset(abm); 4928c2ecf20Sopenharmony_ci if (err) 4938c2ecf20Sopenharmony_ci goto err_free_act; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci err = -ENOMEM; 4968c2ecf20Sopenharmony_ci reprs = nfp_reprs_alloc(pf->max_data_vnics); 4978c2ecf20Sopenharmony_ci if (!reprs) 4988c2ecf20Sopenharmony_ci goto err_free_act; 4998c2ecf20Sopenharmony_ci RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci reprs = nfp_reprs_alloc(pf->max_data_vnics); 5028c2ecf20Sopenharmony_ci if (!reprs) 5038c2ecf20Sopenharmony_ci goto err_free_phys; 5048c2ecf20Sopenharmony_ci RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cierr_free_phys: 5098c2ecf20Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 5108c2ecf20Sopenharmony_cierr_free_act: 5118c2ecf20Sopenharmony_ci kvfree(abm->actions); 5128c2ecf20Sopenharmony_cierr_free_thresh: 5138c2ecf20Sopenharmony_ci kvfree(abm->thresholds); 5148c2ecf20Sopenharmony_cierr_free_thresh_umap: 5158c2ecf20Sopenharmony_ci bitmap_free(abm->threshold_undef); 5168c2ecf20Sopenharmony_cierr_free_abm: 5178c2ecf20Sopenharmony_ci kfree(abm); 5188c2ecf20Sopenharmony_ci app->priv = NULL; 5198c2ecf20Sopenharmony_ci return err; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic void nfp_abm_clean(struct nfp_app *app) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct nfp_abm *abm = app->priv; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci nfp_abm_eswitch_clean_up(abm); 5278c2ecf20Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); 5288c2ecf20Sopenharmony_ci nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 5298c2ecf20Sopenharmony_ci bitmap_free(abm->threshold_undef); 5308c2ecf20Sopenharmony_ci kvfree(abm->actions); 5318c2ecf20Sopenharmony_ci kvfree(abm->thresholds); 5328c2ecf20Sopenharmony_ci kfree(abm); 5338c2ecf20Sopenharmony_ci app->priv = NULL; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciconst struct nfp_app_type app_abm = { 5378c2ecf20Sopenharmony_ci .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC, 5388c2ecf20Sopenharmony_ci .name = "abm", 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci .init = nfp_abm_init, 5418c2ecf20Sopenharmony_ci .clean = nfp_abm_clean, 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci .vnic_alloc = nfp_abm_vnic_alloc, 5448c2ecf20Sopenharmony_ci .vnic_free = nfp_abm_vnic_free, 5458c2ecf20Sopenharmony_ci .vnic_init = nfp_abm_vnic_init, 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci .port_get_stats = nfp_abm_port_get_stats, 5488c2ecf20Sopenharmony_ci .port_get_stats_count = nfp_abm_port_get_stats_count, 5498c2ecf20Sopenharmony_ci .port_get_stats_strings = nfp_abm_port_get_stats_strings, 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci .setup_tc = nfp_abm_setup_tc, 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci .eswitch_mode_get = nfp_abm_eswitch_mode_get, 5548c2ecf20Sopenharmony_ci .eswitch_mode_set = nfp_abm_eswitch_mode_set, 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci .dev_get = nfp_abm_repr_get, 5578c2ecf20Sopenharmony_ci}; 558