226 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */3 4#include <linux/lockdep.h>5#include <linux/netdevice.h>6 7#include "nfpcore/nfp_cpp.h"8#include "nfpcore/nfp_nsp.h"9#include "nfp_app.h"10#include "nfp_main.h"11#include "nfp_net.h"12#include "nfp_port.h"13 14struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)15{16 if (nfp_netdev_is_nfp_net(netdev)) {17 struct nfp_net *nn = netdev_priv(netdev);18 19 return nn->port;20 }21 22 if (nfp_netdev_is_nfp_repr(netdev)) {23 struct nfp_repr *repr = netdev_priv(netdev);24 25 return repr->port;26 }27 28 WARN(1, "Unknown netdev type for nfp_port\n");29 30 return NULL;31}32 33int nfp_port_get_port_parent_id(struct net_device *netdev,34 struct netdev_phys_item_id *ppid)35{36 struct nfp_port *port;37 const u8 *serial;38 39 port = nfp_port_from_netdev(netdev);40 if (!port)41 return -EOPNOTSUPP;42 43 ppid->id_len = nfp_cpp_serial(port->app->cpp, &serial);44 memcpy(&ppid->id, serial, ppid->id_len);45 46 return 0;47}48 49int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type,50 void *type_data)51{52 struct nfp_port *port;53 54 port = nfp_port_from_netdev(netdev);55 if (!port)56 return -EOPNOTSUPP;57 58 return nfp_app_setup_tc(port->app, netdev, type, type_data);59}60 61int nfp_port_set_features(struct net_device *netdev, netdev_features_t features)62{63 struct nfp_port *port;64 65 port = nfp_port_from_netdev(netdev);66 if (!port)67 return 0;68 69 if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&70 port->tc_offload_cnt) {71 netdev_err(netdev, "Cannot disable HW TC offload while offloads active\n");72 return -EBUSY;73 }74 75 return 0;76}77 78struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port)79{80 if (!port)81 return NULL;82 if (port->type != NFP_PORT_PHYS_PORT)83 return NULL;84 85 return port->eth_port;86}87 88struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port)89{90 if (!__nfp_port_get_eth_port(port))91 return NULL;92 93 if (test_bit(NFP_PORT_CHANGED, &port->flags))94 if (nfp_net_refresh_eth_port(port))95 return NULL;96 97 return __nfp_port_get_eth_port(port);98}99 100int101nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len)102{103 struct nfp_eth_table_port *eth_port;104 struct nfp_port *port;105 int n;106 107 port = nfp_port_from_netdev(netdev);108 if (!port)109 return -EOPNOTSUPP;110 111 switch (port->type) {112 case NFP_PORT_PHYS_PORT:113 eth_port = __nfp_port_get_eth_port(port);114 if (!eth_port)115 return -EOPNOTSUPP;116 117 if (!eth_port->is_split)118 n = snprintf(name, len, "p%d", eth_port->label_port);119 else120 n = snprintf(name, len, "p%ds%d", eth_port->label_port,121 eth_port->label_subport);122 break;123 case NFP_PORT_PF_PORT:124 if (!port->pf_split)125 n = snprintf(name, len, "pf%d", port->pf_id);126 else127 n = snprintf(name, len, "pf%ds%d", port->pf_id,128 port->pf_split_id);129 break;130 case NFP_PORT_VF_PORT:131 n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id);132 break;133 default:134 return -EOPNOTSUPP;135 }136 137 if (n >= len)138 return -EINVAL;139 140 return 0;141}142 143/**144 * nfp_port_configure() - helper to set the interface configured bit145 * @netdev: net_device instance146 * @configed: Desired state147 *148 * Helper to set the ifup/ifdown state on the PHY only if there is a physical149 * interface associated with the netdev.150 *151 * Return:152 * 0 - configuration successful (or no change);153 * -ERRNO - configuration failed.154 */155int nfp_port_configure(struct net_device *netdev, bool configed)156{157 struct nfp_eth_table_port *eth_port;158 struct nfp_port *port;159 int err;160 161 port = nfp_port_from_netdev(netdev);162 eth_port = __nfp_port_get_eth_port(port);163 if (!eth_port)164 return 0;165 if (port->eth_forced)166 return 0;167 168 err = nfp_eth_set_configured(port->app->cpp, eth_port->index, configed);169 return err < 0 && err != -EOPNOTSUPP ? err : 0;170}171 172int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,173 struct nfp_port *port, unsigned int id)174{175 /* Check if vNIC has external port associated and cfg is OK */176 if (!pf->eth_tbl || id >= pf->eth_tbl->count) {177 nfp_err(app->cpp,178 "NSP port entries don't match vNICs (no entry %d)\n",179 id);180 return -EINVAL;181 }182 if (pf->eth_tbl->ports[id].override_changed) {183 nfp_warn(app->cpp,184 "Config changed for port #%d, reboot required before port will be operational\n",185 pf->eth_tbl->ports[id].index);186 port->type = NFP_PORT_INVALID;187 return 0;188 }189 190 port->eth_port = &pf->eth_tbl->ports[id];191 port->eth_id = pf->eth_tbl->ports[id].index;192 port->netdev->dev_port = id;193 if (pf->mac_stats_mem)194 port->eth_stats =195 pf->mac_stats_mem + port->eth_id * NFP_MAC_STATS_SIZE;196 197 return 0;198}199 200struct nfp_port *201nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type,202 struct net_device *netdev)203{204 struct nfp_port *port;205 206 port = kzalloc(sizeof(*port), GFP_KERNEL);207 if (!port)208 return ERR_PTR(-ENOMEM);209 210 port->netdev = netdev;211 port->type = type;212 port->app = app;213 214 list_add_tail(&port->port_list, &app->pf->ports);215 216 return port;217}218 219void nfp_port_free(struct nfp_port *port)220{221 if (!port)222 return;223 list_del(&port->port_list);224 kfree(port);225}226