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 14 struct 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 33 int 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 49 int 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 61 int 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 78 struct nfp_port * 79 nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) 80 { 81 struct nfp_port *port; 82 83 lockdep_assert_held(&pf->lock); 84 85 if (type != NFP_PORT_PHYS_PORT) 86 return NULL; 87 88 list_for_each_entry(port, &pf->ports, port_list) 89 if (port->eth_id == id) 90 return port; 91 92 return NULL; 93 } 94 95 struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) 96 { 97 if (!port) 98 return NULL; 99 if (port->type != NFP_PORT_PHYS_PORT) 100 return NULL; 101 102 return port->eth_port; 103 } 104 105 struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port) 106 { 107 if (!__nfp_port_get_eth_port(port)) 108 return NULL; 109 110 if (test_bit(NFP_PORT_CHANGED, &port->flags)) 111 if (nfp_net_refresh_eth_port(port)) 112 return NULL; 113 114 return __nfp_port_get_eth_port(port); 115 } 116 117 int 118 nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) 119 { 120 struct nfp_eth_table_port *eth_port; 121 struct nfp_port *port; 122 int n; 123 124 port = nfp_port_from_netdev(netdev); 125 if (!port) 126 return -EOPNOTSUPP; 127 128 switch (port->type) { 129 case NFP_PORT_PHYS_PORT: 130 eth_port = __nfp_port_get_eth_port(port); 131 if (!eth_port) 132 return -EOPNOTSUPP; 133 134 if (!eth_port->is_split) 135 n = snprintf(name, len, "p%d", eth_port->label_port); 136 else 137 n = snprintf(name, len, "p%ds%d", eth_port->label_port, 138 eth_port->label_subport); 139 break; 140 case NFP_PORT_PF_PORT: 141 if (!port->pf_split) 142 n = snprintf(name, len, "pf%d", port->pf_id); 143 else 144 n = snprintf(name, len, "pf%ds%d", port->pf_id, 145 port->pf_split_id); 146 break; 147 case NFP_PORT_VF_PORT: 148 n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id); 149 break; 150 default: 151 return -EOPNOTSUPP; 152 } 153 154 if (n >= len) 155 return -EINVAL; 156 157 return 0; 158 } 159 160 /** 161 * nfp_port_configure() - helper to set the interface configured bit 162 * @netdev: net_device instance 163 * @configed: Desired state 164 * 165 * Helper to set the ifup/ifdown state on the PHY only if there is a physical 166 * interface associated with the netdev. 167 * 168 * Return: 169 * 0 - configuration successful (or no change); 170 * -ERRNO - configuration failed. 171 */ 172 int nfp_port_configure(struct net_device *netdev, bool configed) 173 { 174 struct nfp_eth_table_port *eth_port; 175 struct nfp_port *port; 176 int err; 177 178 port = nfp_port_from_netdev(netdev); 179 eth_port = __nfp_port_get_eth_port(port); 180 if (!eth_port) 181 return 0; 182 if (port->eth_forced) 183 return 0; 184 185 err = nfp_eth_set_configured(port->app->cpp, eth_port->index, configed); 186 return err < 0 && err != -EOPNOTSUPP ? err : 0; 187 } 188 189 int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, 190 struct nfp_port *port, unsigned int id) 191 { 192 /* Check if vNIC has external port associated and cfg is OK */ 193 if (!pf->eth_tbl || id >= pf->eth_tbl->count) { 194 nfp_err(app->cpp, 195 "NSP port entries don't match vNICs (no entry %d)\n", 196 id); 197 return -EINVAL; 198 } 199 if (pf->eth_tbl->ports[id].override_changed) { 200 nfp_warn(app->cpp, 201 "Config changed for port #%d, reboot required before port will be operational\n", 202 pf->eth_tbl->ports[id].index); 203 port->type = NFP_PORT_INVALID; 204 return 0; 205 } 206 207 port->eth_port = &pf->eth_tbl->ports[id]; 208 port->eth_id = pf->eth_tbl->ports[id].index; 209 if (pf->mac_stats_mem) 210 port->eth_stats = 211 pf->mac_stats_mem + port->eth_id * NFP_MAC_STATS_SIZE; 212 213 return 0; 214 } 215 216 struct nfp_port * 217 nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, 218 struct net_device *netdev) 219 { 220 struct nfp_port *port; 221 222 port = kzalloc(sizeof(*port), GFP_KERNEL); 223 if (!port) 224 return ERR_PTR(-ENOMEM); 225 226 port->netdev = netdev; 227 port->type = type; 228 port->app = app; 229 230 list_add_tail(&port->port_list, &app->pf->ports); 231 232 return port; 233 } 234 235 void nfp_port_free(struct nfp_port *port) 236 { 237 if (!port) 238 return; 239 list_del(&port->port_list); 240 kfree(port); 241 } 242