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