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