xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nfp_port.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3eb488c26SJakub Kicinski 
4ec8b1fbeSJakub Kicinski #include <linux/lockdep.h>
5d692403eSJakub Kicinski #include <linux/netdevice.h>
6ec8b1fbeSJakub Kicinski 
7a7ceb990SJakub Kicinski #include "nfpcore/nfp_cpp.h"
8eb488c26SJakub Kicinski #include "nfpcore/nfp_nsp.h"
9eb488c26SJakub Kicinski #include "nfp_app.h"
10eb488c26SJakub Kicinski #include "nfp_main.h"
11eb488c26SJakub Kicinski #include "nfp_net.h"
12eb488c26SJakub Kicinski #include "nfp_port.h"
13eb488c26SJakub Kicinski 
nfp_port_from_netdev(struct net_device * netdev)14eb488c26SJakub Kicinski struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)
15eb488c26SJakub Kicinski {
1639ae7eb6SJakub Kicinski 	if (nfp_netdev_is_nfp_net(netdev)) {
1739ae7eb6SJakub Kicinski 		struct nfp_net *nn = netdev_priv(netdev);
18eb488c26SJakub Kicinski 
19eb488c26SJakub Kicinski 		return nn->port;
20eb488c26SJakub Kicinski 	}
21eb488c26SJakub Kicinski 
2239ae7eb6SJakub Kicinski 	if (nfp_netdev_is_nfp_repr(netdev)) {
2339ae7eb6SJakub Kicinski 		struct nfp_repr *repr = netdev_priv(netdev);
2439ae7eb6SJakub Kicinski 
2539ae7eb6SJakub Kicinski 		return repr->port;
2639ae7eb6SJakub Kicinski 	}
2739ae7eb6SJakub Kicinski 
2839ae7eb6SJakub Kicinski 	WARN(1, "Unknown netdev type for nfp_port\n");
2939ae7eb6SJakub Kicinski 
3039ae7eb6SJakub Kicinski 	return NULL;
3139ae7eb6SJakub Kicinski }
3239ae7eb6SJakub Kicinski 
nfp_port_get_port_parent_id(struct net_device * netdev,struct netdev_phys_item_id * ppid)331e966763SPieter Jansen van Vuuren int nfp_port_get_port_parent_id(struct net_device *netdev,
341e966763SPieter Jansen van Vuuren 				struct netdev_phys_item_id *ppid)
351e966763SPieter Jansen van Vuuren {
361e966763SPieter Jansen van Vuuren 	struct nfp_port *port;
371e966763SPieter Jansen van Vuuren 	const u8 *serial;
381e966763SPieter Jansen van Vuuren 
391e966763SPieter Jansen van Vuuren 	port = nfp_port_from_netdev(netdev);
401e966763SPieter Jansen van Vuuren 	if (!port)
411e966763SPieter Jansen van Vuuren 		return -EOPNOTSUPP;
421e966763SPieter Jansen van Vuuren 
431e966763SPieter Jansen van Vuuren 	ppid->id_len = nfp_cpp_serial(port->app->cpp, &serial);
441e966763SPieter Jansen van Vuuren 	memcpy(&ppid->id, serial, ppid->id_len);
451e966763SPieter Jansen van Vuuren 
461e966763SPieter Jansen van Vuuren 	return 0;
471e966763SPieter Jansen van Vuuren }
481e966763SPieter Jansen van Vuuren 
nfp_port_setup_tc(struct net_device * netdev,enum tc_setup_type type,void * type_data)492572ac53SJiri Pirko int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type,
50de4784caSJiri Pirko 		      void *type_data)
518a276873SPieter Jansen van Vuuren {
528a276873SPieter Jansen van Vuuren 	struct nfp_port *port;
538a276873SPieter Jansen van Vuuren 
548a276873SPieter Jansen van Vuuren 	port = nfp_port_from_netdev(netdev);
558a276873SPieter Jansen van Vuuren 	if (!port)
568a276873SPieter Jansen van Vuuren 		return -EOPNOTSUPP;
578a276873SPieter Jansen van Vuuren 
58de4784caSJiri Pirko 	return nfp_app_setup_tc(port->app, netdev, type, type_data);
598a276873SPieter Jansen van Vuuren }
608a276873SPieter Jansen van Vuuren 
nfp_port_set_features(struct net_device * netdev,netdev_features_t features)61d692403eSJakub Kicinski int nfp_port_set_features(struct net_device *netdev, netdev_features_t features)
62d692403eSJakub Kicinski {
63d692403eSJakub Kicinski 	struct nfp_port *port;
64d692403eSJakub Kicinski 
65d692403eSJakub Kicinski 	port = nfp_port_from_netdev(netdev);
66d692403eSJakub Kicinski 	if (!port)
67d692403eSJakub Kicinski 		return 0;
68d692403eSJakub Kicinski 
69d692403eSJakub Kicinski 	if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
70d692403eSJakub Kicinski 	    port->tc_offload_cnt) {
71d692403eSJakub Kicinski 		netdev_err(netdev, "Cannot disable HW TC offload while offloads active\n");
72d692403eSJakub Kicinski 		return -EBUSY;
73d692403eSJakub Kicinski 	}
74d692403eSJakub Kicinski 
75d692403eSJakub Kicinski 	return 0;
76d692403eSJakub Kicinski }
77d692403eSJakub Kicinski 
__nfp_port_get_eth_port(struct nfp_port * port)78eb488c26SJakub Kicinski struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port)
79eb488c26SJakub Kicinski {
80eb488c26SJakub Kicinski 	if (!port)
81eb488c26SJakub Kicinski 		return NULL;
82eb488c26SJakub Kicinski 	if (port->type != NFP_PORT_PHYS_PORT)
83eb488c26SJakub Kicinski 		return NULL;
84eb488c26SJakub Kicinski 
85eb488c26SJakub Kicinski 	return port->eth_port;
86eb488c26SJakub Kicinski }
87eb488c26SJakub Kicinski 
nfp_port_get_eth_port(struct nfp_port * port)881876749dSJakub Kicinski struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port)
891876749dSJakub Kicinski {
901876749dSJakub Kicinski 	if (!__nfp_port_get_eth_port(port))
911876749dSJakub Kicinski 		return NULL;
921876749dSJakub Kicinski 
931876749dSJakub Kicinski 	if (test_bit(NFP_PORT_CHANGED, &port->flags))
941876749dSJakub Kicinski 		if (nfp_net_refresh_eth_port(port))
951876749dSJakub Kicinski 			return NULL;
961876749dSJakub Kicinski 
971876749dSJakub Kicinski 	return __nfp_port_get_eth_port(port);
981876749dSJakub Kicinski }
991876749dSJakub Kicinski 
100eb488c26SJakub Kicinski int
nfp_port_get_phys_port_name(struct net_device * netdev,char * name,size_t len)101eb488c26SJakub Kicinski nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
102eb488c26SJakub Kicinski {
103eb488c26SJakub Kicinski 	struct nfp_eth_table_port *eth_port;
104eb488c26SJakub Kicinski 	struct nfp_port *port;
105eb488c26SJakub Kicinski 	int n;
106eb488c26SJakub Kicinski 
107eb488c26SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
108168c478eSJakub Kicinski 	if (!port)
109168c478eSJakub Kicinski 		return -EOPNOTSUPP;
110168c478eSJakub Kicinski 
111168c478eSJakub Kicinski 	switch (port->type) {
112168c478eSJakub Kicinski 	case NFP_PORT_PHYS_PORT:
113eb488c26SJakub Kicinski 		eth_port = __nfp_port_get_eth_port(port);
114eb488c26SJakub Kicinski 		if (!eth_port)
115eb488c26SJakub Kicinski 			return -EOPNOTSUPP;
116eb488c26SJakub Kicinski 
117eb488c26SJakub Kicinski 		if (!eth_port->is_split)
118eb488c26SJakub Kicinski 			n = snprintf(name, len, "p%d", eth_port->label_port);
119eb488c26SJakub Kicinski 		else
120eb488c26SJakub Kicinski 			n = snprintf(name, len, "p%ds%d", eth_port->label_port,
121eb488c26SJakub Kicinski 				     eth_port->label_subport);
122168c478eSJakub Kicinski 		break;
123168c478eSJakub Kicinski 	case NFP_PORT_PF_PORT:
124290f54dbSJakub Kicinski 		if (!port->pf_split)
125168c478eSJakub Kicinski 			n = snprintf(name, len, "pf%d", port->pf_id);
126290f54dbSJakub Kicinski 		else
127290f54dbSJakub Kicinski 			n = snprintf(name, len, "pf%ds%d", port->pf_id,
128290f54dbSJakub Kicinski 				     port->pf_split_id);
129168c478eSJakub Kicinski 		break;
130168c478eSJakub Kicinski 	case NFP_PORT_VF_PORT:
131168c478eSJakub Kicinski 		n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id);
132168c478eSJakub Kicinski 		break;
133168c478eSJakub Kicinski 	default:
134168c478eSJakub Kicinski 		return -EOPNOTSUPP;
135168c478eSJakub Kicinski 	}
136168c478eSJakub Kicinski 
137eb488c26SJakub Kicinski 	if (n >= len)
138eb488c26SJakub Kicinski 		return -EINVAL;
139eb488c26SJakub Kicinski 
140eb488c26SJakub Kicinski 	return 0;
141eb488c26SJakub Kicinski }
142eb488c26SJakub Kicinski 
143447e9ebfSDirk van der Merwe /**
144447e9ebfSDirk van der Merwe  * nfp_port_configure() - helper to set the interface configured bit
145447e9ebfSDirk van der Merwe  * @netdev:	net_device instance
146447e9ebfSDirk van der Merwe  * @configed:	Desired state
147447e9ebfSDirk van der Merwe  *
148447e9ebfSDirk van der Merwe  * Helper to set the ifup/ifdown state on the PHY only if there is a physical
149447e9ebfSDirk van der Merwe  * interface associated with the netdev.
150447e9ebfSDirk van der Merwe  *
151447e9ebfSDirk van der Merwe  * Return:
152447e9ebfSDirk van der Merwe  * 0 - configuration successful (or no change);
153447e9ebfSDirk van der Merwe  * -ERRNO - configuration failed.
154447e9ebfSDirk van der Merwe  */
nfp_port_configure(struct net_device * netdev,bool configed)155447e9ebfSDirk van der Merwe int nfp_port_configure(struct net_device *netdev, bool configed)
156447e9ebfSDirk van der Merwe {
157447e9ebfSDirk van der Merwe 	struct nfp_eth_table_port *eth_port;
158447e9ebfSDirk van der Merwe 	struct nfp_port *port;
159447e9ebfSDirk van der Merwe 	int err;
160447e9ebfSDirk van der Merwe 
161447e9ebfSDirk van der Merwe 	port = nfp_port_from_netdev(netdev);
162447e9ebfSDirk van der Merwe 	eth_port = __nfp_port_get_eth_port(port);
163447e9ebfSDirk van der Merwe 	if (!eth_port)
164447e9ebfSDirk van der Merwe 		return 0;
1651f700367SJakub Kicinski 	if (port->eth_forced)
1661f700367SJakub Kicinski 		return 0;
167447e9ebfSDirk van der Merwe 
168447e9ebfSDirk van der Merwe 	err = nfp_eth_set_configured(port->app->cpp, eth_port->index, configed);
169447e9ebfSDirk van der Merwe 	return err < 0 && err != -EOPNOTSUPP ? err : 0;
170447e9ebfSDirk van der Merwe }
171447e9ebfSDirk van der Merwe 
nfp_port_init_phy_port(struct nfp_pf * pf,struct nfp_app * app,struct nfp_port * port,unsigned int id)172a7ceb990SJakub Kicinski int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,
173a7ceb990SJakub Kicinski 			   struct nfp_port *port, unsigned int id)
174a7ceb990SJakub Kicinski {
175a7ceb990SJakub Kicinski 	/* Check if vNIC has external port associated and cfg is OK */
1762eb333c4SJakub Kicinski 	if (!pf->eth_tbl || id >= pf->eth_tbl->count) {
177a7ceb990SJakub Kicinski 		nfp_err(app->cpp,
1782eb333c4SJakub Kicinski 			"NSP port entries don't match vNICs (no entry %d)\n",
179a7ceb990SJakub Kicinski 			id);
180a7ceb990SJakub Kicinski 		return -EINVAL;
181a7ceb990SJakub Kicinski 	}
1822eb333c4SJakub Kicinski 	if (pf->eth_tbl->ports[id].override_changed) {
183a7ceb990SJakub Kicinski 		nfp_warn(app->cpp,
184a7ceb990SJakub Kicinski 			 "Config changed for port #%d, reboot required before port will be operational\n",
1852eb333c4SJakub Kicinski 			 pf->eth_tbl->ports[id].index);
186a7ceb990SJakub Kicinski 		port->type = NFP_PORT_INVALID;
187a7ceb990SJakub Kicinski 		return 0;
188a7ceb990SJakub Kicinski 	}
189a7ceb990SJakub Kicinski 
1902eb333c4SJakub Kicinski 	port->eth_port = &pf->eth_tbl->ports[id];
1912eb333c4SJakub Kicinski 	port->eth_id = pf->eth_tbl->ports[id].index;
192*0ebd4fd6SYinjun Zhang 	port->netdev->dev_port = id;
1937344bea1SJakub Kicinski 	if (pf->mac_stats_mem)
1947344bea1SJakub Kicinski 		port->eth_stats =
1957344bea1SJakub Kicinski 			pf->mac_stats_mem + port->eth_id * NFP_MAC_STATS_SIZE;
1962eb333c4SJakub Kicinski 
197a7ceb990SJakub Kicinski 	return 0;
198a7ceb990SJakub Kicinski }
199a7ceb990SJakub Kicinski 
200eb488c26SJakub Kicinski struct nfp_port *
nfp_port_alloc(struct nfp_app * app,enum nfp_port_type type,struct net_device * netdev)201eb488c26SJakub Kicinski nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type,
202eb488c26SJakub Kicinski 	       struct net_device *netdev)
203eb488c26SJakub Kicinski {
204eb488c26SJakub Kicinski 	struct nfp_port *port;
205eb488c26SJakub Kicinski 
206eb488c26SJakub Kicinski 	port = kzalloc(sizeof(*port), GFP_KERNEL);
207eb488c26SJakub Kicinski 	if (!port)
208eb488c26SJakub Kicinski 		return ERR_PTR(-ENOMEM);
209eb488c26SJakub Kicinski 
210eb488c26SJakub Kicinski 	port->netdev = netdev;
211eb488c26SJakub Kicinski 	port->type = type;
212eb488c26SJakub Kicinski 	port->app = app;
213eb488c26SJakub Kicinski 
2143eb3b74aSJakub Kicinski 	list_add_tail(&port->port_list, &app->pf->ports);
2153eb3b74aSJakub Kicinski 
216eb488c26SJakub Kicinski 	return port;
217eb488c26SJakub Kicinski }
218eb488c26SJakub Kicinski 
nfp_port_free(struct nfp_port * port)219eb488c26SJakub Kicinski void nfp_port_free(struct nfp_port *port)
220eb488c26SJakub Kicinski {
2213eb3b74aSJakub Kicinski 	if (!port)
2223eb3b74aSJakub Kicinski 		return;
2233eb3b74aSJakub Kicinski 	list_del(&port->port_list);
224eb488c26SJakub Kicinski 	kfree(port);
225eb488c26SJakub Kicinski }
226