xref: /openbmc/linux/net/devlink/port.c (revision 7d8c7bc9)
1eec1e5eaSJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
2eec1e5eaSJiri Pirko /*
3eec1e5eaSJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4eec1e5eaSJiri Pirko  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5eec1e5eaSJiri Pirko  */
6eec1e5eaSJiri Pirko 
7eec1e5eaSJiri Pirko #include "devl_internal.h"
8eec1e5eaSJiri Pirko 
9eec1e5eaSJiri Pirko #define DEVLINK_PORT_FN_CAPS_VALID_MASK \
10eec1e5eaSJiri Pirko 	(_BITUL(__DEVLINK_PORT_FN_ATTR_CAPS_MAX) - 1)
11eec1e5eaSJiri Pirko 
12eec1e5eaSJiri Pirko static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
13eec1e5eaSJiri Pirko 	[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
14eec1e5eaSJiri Pirko 	[DEVLINK_PORT_FN_ATTR_STATE] =
15eec1e5eaSJiri Pirko 		NLA_POLICY_RANGE(NLA_U8, DEVLINK_PORT_FN_STATE_INACTIVE,
16eec1e5eaSJiri Pirko 				 DEVLINK_PORT_FN_STATE_ACTIVE),
17eec1e5eaSJiri Pirko 	[DEVLINK_PORT_FN_ATTR_CAPS] =
18eec1e5eaSJiri Pirko 		NLA_POLICY_BITFIELD32(DEVLINK_PORT_FN_CAPS_VALID_MASK),
19eec1e5eaSJiri Pirko };
20eec1e5eaSJiri Pirko 
21eec1e5eaSJiri Pirko #define ASSERT_DEVLINK_PORT_REGISTERED(devlink_port)				\
22eec1e5eaSJiri Pirko 	WARN_ON_ONCE(!(devlink_port)->registered)
23eec1e5eaSJiri Pirko #define ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port)			\
24eec1e5eaSJiri Pirko 	WARN_ON_ONCE((devlink_port)->registered)
25eec1e5eaSJiri Pirko 
devlink_port_get_by_index(struct devlink * devlink,unsigned int port_index)26eec1e5eaSJiri Pirko struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
27eec1e5eaSJiri Pirko 					       unsigned int port_index)
28eec1e5eaSJiri Pirko {
29eec1e5eaSJiri Pirko 	return xa_load(&devlink->ports, port_index);
30eec1e5eaSJiri Pirko }
31eec1e5eaSJiri Pirko 
devlink_port_get_from_attrs(struct devlink * devlink,struct nlattr ** attrs)32eec1e5eaSJiri Pirko struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
33eec1e5eaSJiri Pirko 						 struct nlattr **attrs)
34eec1e5eaSJiri Pirko {
35eec1e5eaSJiri Pirko 	if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
36eec1e5eaSJiri Pirko 		u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
37eec1e5eaSJiri Pirko 		struct devlink_port *devlink_port;
38eec1e5eaSJiri Pirko 
39eec1e5eaSJiri Pirko 		devlink_port = devlink_port_get_by_index(devlink, port_index);
40eec1e5eaSJiri Pirko 		if (!devlink_port)
41eec1e5eaSJiri Pirko 			return ERR_PTR(-ENODEV);
42eec1e5eaSJiri Pirko 		return devlink_port;
43eec1e5eaSJiri Pirko 	}
44eec1e5eaSJiri Pirko 	return ERR_PTR(-EINVAL);
45eec1e5eaSJiri Pirko }
46eec1e5eaSJiri Pirko 
devlink_port_get_from_info(struct devlink * devlink,struct genl_info * info)47eec1e5eaSJiri Pirko struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
48eec1e5eaSJiri Pirko 						struct genl_info *info)
49eec1e5eaSJiri Pirko {
50eec1e5eaSJiri Pirko 	return devlink_port_get_from_attrs(devlink, info->attrs);
51eec1e5eaSJiri Pirko }
52eec1e5eaSJiri Pirko 
devlink_port_fn_cap_fill(struct nla_bitfield32 * caps,u32 cap,bool is_enable)53eec1e5eaSJiri Pirko static void devlink_port_fn_cap_fill(struct nla_bitfield32 *caps,
54eec1e5eaSJiri Pirko 				     u32 cap, bool is_enable)
55eec1e5eaSJiri Pirko {
56eec1e5eaSJiri Pirko 	caps->selector |= cap;
57eec1e5eaSJiri Pirko 	if (is_enable)
58eec1e5eaSJiri Pirko 		caps->value |= cap;
59eec1e5eaSJiri Pirko }
60eec1e5eaSJiri Pirko 
devlink_port_fn_roce_fill(struct devlink_port * devlink_port,struct nla_bitfield32 * caps,struct netlink_ext_ack * extack)61eec1e5eaSJiri Pirko static int devlink_port_fn_roce_fill(struct devlink_port *devlink_port,
62eec1e5eaSJiri Pirko 				     struct nla_bitfield32 *caps,
63eec1e5eaSJiri Pirko 				     struct netlink_ext_ack *extack)
64eec1e5eaSJiri Pirko {
65eec1e5eaSJiri Pirko 	bool is_enable;
66eec1e5eaSJiri Pirko 	int err;
67eec1e5eaSJiri Pirko 
68eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_fn_roce_get)
69eec1e5eaSJiri Pirko 		return 0;
70eec1e5eaSJiri Pirko 
71eec1e5eaSJiri Pirko 	err = devlink_port->ops->port_fn_roce_get(devlink_port, &is_enable,
72eec1e5eaSJiri Pirko 						  extack);
73eec1e5eaSJiri Pirko 	if (err) {
74eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
75eec1e5eaSJiri Pirko 			return 0;
76eec1e5eaSJiri Pirko 		return err;
77eec1e5eaSJiri Pirko 	}
78eec1e5eaSJiri Pirko 
79eec1e5eaSJiri Pirko 	devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_ROCE, is_enable);
80eec1e5eaSJiri Pirko 	return 0;
81eec1e5eaSJiri Pirko }
82eec1e5eaSJiri Pirko 
devlink_port_fn_migratable_fill(struct devlink_port * devlink_port,struct nla_bitfield32 * caps,struct netlink_ext_ack * extack)83eec1e5eaSJiri Pirko static int devlink_port_fn_migratable_fill(struct devlink_port *devlink_port,
84eec1e5eaSJiri Pirko 					   struct nla_bitfield32 *caps,
85eec1e5eaSJiri Pirko 					   struct netlink_ext_ack *extack)
86eec1e5eaSJiri Pirko {
87eec1e5eaSJiri Pirko 	bool is_enable;
88eec1e5eaSJiri Pirko 	int err;
89eec1e5eaSJiri Pirko 
90eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_fn_migratable_get ||
91eec1e5eaSJiri Pirko 	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
92eec1e5eaSJiri Pirko 		return 0;
93eec1e5eaSJiri Pirko 
94eec1e5eaSJiri Pirko 	err = devlink_port->ops->port_fn_migratable_get(devlink_port,
95eec1e5eaSJiri Pirko 							&is_enable, extack);
96eec1e5eaSJiri Pirko 	if (err) {
97eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
98eec1e5eaSJiri Pirko 			return 0;
99eec1e5eaSJiri Pirko 		return err;
100eec1e5eaSJiri Pirko 	}
101eec1e5eaSJiri Pirko 
102eec1e5eaSJiri Pirko 	devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_MIGRATABLE, is_enable);
103eec1e5eaSJiri Pirko 	return 0;
104eec1e5eaSJiri Pirko }
105eec1e5eaSJiri Pirko 
devlink_port_fn_ipsec_crypto_fill(struct devlink_port * devlink_port,struct nla_bitfield32 * caps,struct netlink_ext_ack * extack)106eec1e5eaSJiri Pirko static int devlink_port_fn_ipsec_crypto_fill(struct devlink_port *devlink_port,
107eec1e5eaSJiri Pirko 					     struct nla_bitfield32 *caps,
108eec1e5eaSJiri Pirko 					     struct netlink_ext_ack *extack)
109eec1e5eaSJiri Pirko {
110eec1e5eaSJiri Pirko 	bool is_enable;
111eec1e5eaSJiri Pirko 	int err;
112eec1e5eaSJiri Pirko 
113eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_fn_ipsec_crypto_get ||
114eec1e5eaSJiri Pirko 	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
115eec1e5eaSJiri Pirko 		return 0;
116eec1e5eaSJiri Pirko 
117eec1e5eaSJiri Pirko 	err = devlink_port->ops->port_fn_ipsec_crypto_get(devlink_port, &is_enable, extack);
118eec1e5eaSJiri Pirko 	if (err) {
119eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
120eec1e5eaSJiri Pirko 			return 0;
121eec1e5eaSJiri Pirko 		return err;
122eec1e5eaSJiri Pirko 	}
123eec1e5eaSJiri Pirko 
124eec1e5eaSJiri Pirko 	devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO, is_enable);
125eec1e5eaSJiri Pirko 	return 0;
126eec1e5eaSJiri Pirko }
127eec1e5eaSJiri Pirko 
devlink_port_fn_ipsec_packet_fill(struct devlink_port * devlink_port,struct nla_bitfield32 * caps,struct netlink_ext_ack * extack)128eec1e5eaSJiri Pirko static int devlink_port_fn_ipsec_packet_fill(struct devlink_port *devlink_port,
129eec1e5eaSJiri Pirko 					     struct nla_bitfield32 *caps,
130eec1e5eaSJiri Pirko 					     struct netlink_ext_ack *extack)
131eec1e5eaSJiri Pirko {
132eec1e5eaSJiri Pirko 	bool is_enable;
133eec1e5eaSJiri Pirko 	int err;
134eec1e5eaSJiri Pirko 
135eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_fn_ipsec_packet_get ||
136eec1e5eaSJiri Pirko 	    devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
137eec1e5eaSJiri Pirko 		return 0;
138eec1e5eaSJiri Pirko 
139eec1e5eaSJiri Pirko 	err = devlink_port->ops->port_fn_ipsec_packet_get(devlink_port, &is_enable, extack);
140eec1e5eaSJiri Pirko 	if (err) {
141eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
142eec1e5eaSJiri Pirko 			return 0;
143eec1e5eaSJiri Pirko 		return err;
144eec1e5eaSJiri Pirko 	}
145eec1e5eaSJiri Pirko 
146eec1e5eaSJiri Pirko 	devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_IPSEC_PACKET, is_enable);
147eec1e5eaSJiri Pirko 	return 0;
148eec1e5eaSJiri Pirko }
149eec1e5eaSJiri Pirko 
devlink_port_fn_caps_fill(struct devlink_port * devlink_port,struct sk_buff * msg,struct netlink_ext_ack * extack,bool * msg_updated)150eec1e5eaSJiri Pirko static int devlink_port_fn_caps_fill(struct devlink_port *devlink_port,
151eec1e5eaSJiri Pirko 				     struct sk_buff *msg,
152eec1e5eaSJiri Pirko 				     struct netlink_ext_ack *extack,
153eec1e5eaSJiri Pirko 				     bool *msg_updated)
154eec1e5eaSJiri Pirko {
155eec1e5eaSJiri Pirko 	struct nla_bitfield32 caps = {};
156eec1e5eaSJiri Pirko 	int err;
157eec1e5eaSJiri Pirko 
158eec1e5eaSJiri Pirko 	err = devlink_port_fn_roce_fill(devlink_port, &caps, extack);
159eec1e5eaSJiri Pirko 	if (err)
160eec1e5eaSJiri Pirko 		return err;
161eec1e5eaSJiri Pirko 
162eec1e5eaSJiri Pirko 	err = devlink_port_fn_migratable_fill(devlink_port, &caps, extack);
163eec1e5eaSJiri Pirko 	if (err)
164eec1e5eaSJiri Pirko 		return err;
165eec1e5eaSJiri Pirko 
166eec1e5eaSJiri Pirko 	err = devlink_port_fn_ipsec_crypto_fill(devlink_port, &caps, extack);
167eec1e5eaSJiri Pirko 	if (err)
168eec1e5eaSJiri Pirko 		return err;
169eec1e5eaSJiri Pirko 
170eec1e5eaSJiri Pirko 	err = devlink_port_fn_ipsec_packet_fill(devlink_port, &caps, extack);
171eec1e5eaSJiri Pirko 	if (err)
172eec1e5eaSJiri Pirko 		return err;
173eec1e5eaSJiri Pirko 
174eec1e5eaSJiri Pirko 	if (!caps.selector)
175eec1e5eaSJiri Pirko 		return 0;
176eec1e5eaSJiri Pirko 	err = nla_put_bitfield32(msg, DEVLINK_PORT_FN_ATTR_CAPS, caps.value,
177eec1e5eaSJiri Pirko 				 caps.selector);
178eec1e5eaSJiri Pirko 	if (err)
179eec1e5eaSJiri Pirko 		return err;
180eec1e5eaSJiri Pirko 
181eec1e5eaSJiri Pirko 	*msg_updated = true;
182eec1e5eaSJiri Pirko 	return 0;
183eec1e5eaSJiri Pirko }
184eec1e5eaSJiri Pirko 
devlink_nl_port_handle_fill(struct sk_buff * msg,struct devlink_port * devlink_port)185eec1e5eaSJiri Pirko int devlink_nl_port_handle_fill(struct sk_buff *msg, struct devlink_port *devlink_port)
186eec1e5eaSJiri Pirko {
187eec1e5eaSJiri Pirko 	if (devlink_nl_put_handle(msg, devlink_port->devlink))
188eec1e5eaSJiri Pirko 		return -EMSGSIZE;
189eec1e5eaSJiri Pirko 	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
190eec1e5eaSJiri Pirko 		return -EMSGSIZE;
191eec1e5eaSJiri Pirko 	return 0;
192eec1e5eaSJiri Pirko }
193eec1e5eaSJiri Pirko 
devlink_nl_port_handle_size(struct devlink_port * devlink_port)194eec1e5eaSJiri Pirko size_t devlink_nl_port_handle_size(struct devlink_port *devlink_port)
195eec1e5eaSJiri Pirko {
196eec1e5eaSJiri Pirko 	struct devlink *devlink = devlink_port->devlink;
197eec1e5eaSJiri Pirko 
198eec1e5eaSJiri Pirko 	return nla_total_size(strlen(devlink->dev->bus->name) + 1) /* DEVLINK_ATTR_BUS_NAME */
199eec1e5eaSJiri Pirko 	     + nla_total_size(strlen(dev_name(devlink->dev)) + 1) /* DEVLINK_ATTR_DEV_NAME */
200eec1e5eaSJiri Pirko 	     + nla_total_size(4); /* DEVLINK_ATTR_PORT_INDEX */
201eec1e5eaSJiri Pirko }
202eec1e5eaSJiri Pirko 
devlink_nl_port_attrs_put(struct sk_buff * msg,struct devlink_port * devlink_port)203eec1e5eaSJiri Pirko static int devlink_nl_port_attrs_put(struct sk_buff *msg,
204eec1e5eaSJiri Pirko 				     struct devlink_port *devlink_port)
205eec1e5eaSJiri Pirko {
206eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
207eec1e5eaSJiri Pirko 
208eec1e5eaSJiri Pirko 	if (!devlink_port->attrs_set)
209eec1e5eaSJiri Pirko 		return 0;
210eec1e5eaSJiri Pirko 	if (attrs->lanes) {
211eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
212eec1e5eaSJiri Pirko 			return -EMSGSIZE;
213eec1e5eaSJiri Pirko 	}
214eec1e5eaSJiri Pirko 	if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
215eec1e5eaSJiri Pirko 		return -EMSGSIZE;
216eec1e5eaSJiri Pirko 	if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
217eec1e5eaSJiri Pirko 		return -EMSGSIZE;
218eec1e5eaSJiri Pirko 	switch (devlink_port->attrs.flavour) {
219eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_PF:
220eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
221eec1e5eaSJiri Pirko 				attrs->pci_pf.controller) ||
222eec1e5eaSJiri Pirko 		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
223eec1e5eaSJiri Pirko 			return -EMSGSIZE;
224eec1e5eaSJiri Pirko 		if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
225eec1e5eaSJiri Pirko 			return -EMSGSIZE;
226eec1e5eaSJiri Pirko 		break;
227eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_VF:
228eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
229eec1e5eaSJiri Pirko 				attrs->pci_vf.controller) ||
230eec1e5eaSJiri Pirko 		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
231eec1e5eaSJiri Pirko 		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
232eec1e5eaSJiri Pirko 			return -EMSGSIZE;
233eec1e5eaSJiri Pirko 		if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
234eec1e5eaSJiri Pirko 			return -EMSGSIZE;
235eec1e5eaSJiri Pirko 		break;
236eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_SF:
237eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
238eec1e5eaSJiri Pirko 				attrs->pci_sf.controller) ||
239eec1e5eaSJiri Pirko 		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
240eec1e5eaSJiri Pirko 				attrs->pci_sf.pf) ||
241eec1e5eaSJiri Pirko 		    nla_put_u32(msg, DEVLINK_ATTR_PORT_PCI_SF_NUMBER,
242eec1e5eaSJiri Pirko 				attrs->pci_sf.sf))
243eec1e5eaSJiri Pirko 			return -EMSGSIZE;
244eec1e5eaSJiri Pirko 		break;
245eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PHYSICAL:
246eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_CPU:
247eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_DSA:
248eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
249eec1e5eaSJiri Pirko 				attrs->phys.port_number))
250eec1e5eaSJiri Pirko 			return -EMSGSIZE;
251eec1e5eaSJiri Pirko 		if (!attrs->split)
252eec1e5eaSJiri Pirko 			return 0;
253eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
254eec1e5eaSJiri Pirko 				attrs->phys.port_number))
255eec1e5eaSJiri Pirko 			return -EMSGSIZE;
256eec1e5eaSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
257eec1e5eaSJiri Pirko 				attrs->phys.split_subport_number))
258eec1e5eaSJiri Pirko 			return -EMSGSIZE;
259eec1e5eaSJiri Pirko 		break;
260eec1e5eaSJiri Pirko 	default:
261eec1e5eaSJiri Pirko 		break;
262eec1e5eaSJiri Pirko 	}
263eec1e5eaSJiri Pirko 	return 0;
264eec1e5eaSJiri Pirko }
265eec1e5eaSJiri Pirko 
devlink_port_fn_hw_addr_fill(struct devlink_port * port,struct sk_buff * msg,struct netlink_ext_ack * extack,bool * msg_updated)266eec1e5eaSJiri Pirko static int devlink_port_fn_hw_addr_fill(struct devlink_port *port,
267eec1e5eaSJiri Pirko 					struct sk_buff *msg,
268eec1e5eaSJiri Pirko 					struct netlink_ext_ack *extack,
269eec1e5eaSJiri Pirko 					bool *msg_updated)
270eec1e5eaSJiri Pirko {
271eec1e5eaSJiri Pirko 	u8 hw_addr[MAX_ADDR_LEN];
272eec1e5eaSJiri Pirko 	int hw_addr_len;
273eec1e5eaSJiri Pirko 	int err;
274eec1e5eaSJiri Pirko 
275eec1e5eaSJiri Pirko 	if (!port->ops->port_fn_hw_addr_get)
276eec1e5eaSJiri Pirko 		return 0;
277eec1e5eaSJiri Pirko 
278eec1e5eaSJiri Pirko 	err = port->ops->port_fn_hw_addr_get(port, hw_addr, &hw_addr_len,
279eec1e5eaSJiri Pirko 					     extack);
280eec1e5eaSJiri Pirko 	if (err) {
281eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
282eec1e5eaSJiri Pirko 			return 0;
283eec1e5eaSJiri Pirko 		return err;
284eec1e5eaSJiri Pirko 	}
285eec1e5eaSJiri Pirko 	err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
286eec1e5eaSJiri Pirko 	if (err)
287eec1e5eaSJiri Pirko 		return err;
288eec1e5eaSJiri Pirko 	*msg_updated = true;
289eec1e5eaSJiri Pirko 	return 0;
290eec1e5eaSJiri Pirko }
291eec1e5eaSJiri Pirko 
292eec1e5eaSJiri Pirko static bool
devlink_port_fn_state_valid(enum devlink_port_fn_state state)293eec1e5eaSJiri Pirko devlink_port_fn_state_valid(enum devlink_port_fn_state state)
294eec1e5eaSJiri Pirko {
295eec1e5eaSJiri Pirko 	return state == DEVLINK_PORT_FN_STATE_INACTIVE ||
296eec1e5eaSJiri Pirko 	       state == DEVLINK_PORT_FN_STATE_ACTIVE;
297eec1e5eaSJiri Pirko }
298eec1e5eaSJiri Pirko 
299eec1e5eaSJiri Pirko static bool
devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate)300eec1e5eaSJiri Pirko devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate)
301eec1e5eaSJiri Pirko {
302eec1e5eaSJiri Pirko 	return opstate == DEVLINK_PORT_FN_OPSTATE_DETACHED ||
303eec1e5eaSJiri Pirko 	       opstate == DEVLINK_PORT_FN_OPSTATE_ATTACHED;
304eec1e5eaSJiri Pirko }
305eec1e5eaSJiri Pirko 
devlink_port_fn_state_fill(struct devlink_port * port,struct sk_buff * msg,struct netlink_ext_ack * extack,bool * msg_updated)306eec1e5eaSJiri Pirko static int devlink_port_fn_state_fill(struct devlink_port *port,
307eec1e5eaSJiri Pirko 				      struct sk_buff *msg,
308eec1e5eaSJiri Pirko 				      struct netlink_ext_ack *extack,
309eec1e5eaSJiri Pirko 				      bool *msg_updated)
310eec1e5eaSJiri Pirko {
311eec1e5eaSJiri Pirko 	enum devlink_port_fn_opstate opstate;
312eec1e5eaSJiri Pirko 	enum devlink_port_fn_state state;
313eec1e5eaSJiri Pirko 	int err;
314eec1e5eaSJiri Pirko 
315eec1e5eaSJiri Pirko 	if (!port->ops->port_fn_state_get)
316eec1e5eaSJiri Pirko 		return 0;
317eec1e5eaSJiri Pirko 
318eec1e5eaSJiri Pirko 	err = port->ops->port_fn_state_get(port, &state, &opstate, extack);
319eec1e5eaSJiri Pirko 	if (err) {
320eec1e5eaSJiri Pirko 		if (err == -EOPNOTSUPP)
321eec1e5eaSJiri Pirko 			return 0;
322eec1e5eaSJiri Pirko 		return err;
323eec1e5eaSJiri Pirko 	}
324eec1e5eaSJiri Pirko 	if (!devlink_port_fn_state_valid(state)) {
325eec1e5eaSJiri Pirko 		WARN_ON_ONCE(1);
326eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(extack, "Invalid state read from driver");
327eec1e5eaSJiri Pirko 		return -EINVAL;
328eec1e5eaSJiri Pirko 	}
329eec1e5eaSJiri Pirko 	if (!devlink_port_fn_opstate_valid(opstate)) {
330eec1e5eaSJiri Pirko 		WARN_ON_ONCE(1);
331eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(extack, "Invalid operational state read from driver");
332eec1e5eaSJiri Pirko 		return -EINVAL;
333eec1e5eaSJiri Pirko 	}
334eec1e5eaSJiri Pirko 	if (nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_STATE, state) ||
335eec1e5eaSJiri Pirko 	    nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_OPSTATE, opstate))
336eec1e5eaSJiri Pirko 		return -EMSGSIZE;
337eec1e5eaSJiri Pirko 	*msg_updated = true;
338eec1e5eaSJiri Pirko 	return 0;
339eec1e5eaSJiri Pirko }
340eec1e5eaSJiri Pirko 
341eec1e5eaSJiri Pirko static int
devlink_port_fn_mig_set(struct devlink_port * devlink_port,bool enable,struct netlink_ext_ack * extack)342eec1e5eaSJiri Pirko devlink_port_fn_mig_set(struct devlink_port *devlink_port, bool enable,
343eec1e5eaSJiri Pirko 			struct netlink_ext_ack *extack)
344eec1e5eaSJiri Pirko {
345eec1e5eaSJiri Pirko 	return devlink_port->ops->port_fn_migratable_set(devlink_port, enable,
346eec1e5eaSJiri Pirko 							 extack);
347eec1e5eaSJiri Pirko }
348eec1e5eaSJiri Pirko 
349eec1e5eaSJiri Pirko static int
devlink_port_fn_roce_set(struct devlink_port * devlink_port,bool enable,struct netlink_ext_ack * extack)350eec1e5eaSJiri Pirko devlink_port_fn_roce_set(struct devlink_port *devlink_port, bool enable,
351eec1e5eaSJiri Pirko 			 struct netlink_ext_ack *extack)
352eec1e5eaSJiri Pirko {
353eec1e5eaSJiri Pirko 	return devlink_port->ops->port_fn_roce_set(devlink_port, enable,
354eec1e5eaSJiri Pirko 						   extack);
355eec1e5eaSJiri Pirko }
356eec1e5eaSJiri Pirko 
357eec1e5eaSJiri Pirko static int
devlink_port_fn_ipsec_crypto_set(struct devlink_port * devlink_port,bool enable,struct netlink_ext_ack * extack)358eec1e5eaSJiri Pirko devlink_port_fn_ipsec_crypto_set(struct devlink_port *devlink_port, bool enable,
359eec1e5eaSJiri Pirko 				 struct netlink_ext_ack *extack)
360eec1e5eaSJiri Pirko {
361eec1e5eaSJiri Pirko 	return devlink_port->ops->port_fn_ipsec_crypto_set(devlink_port, enable, extack);
362eec1e5eaSJiri Pirko }
363eec1e5eaSJiri Pirko 
364eec1e5eaSJiri Pirko static int
devlink_port_fn_ipsec_packet_set(struct devlink_port * devlink_port,bool enable,struct netlink_ext_ack * extack)365eec1e5eaSJiri Pirko devlink_port_fn_ipsec_packet_set(struct devlink_port *devlink_port, bool enable,
366eec1e5eaSJiri Pirko 				 struct netlink_ext_ack *extack)
367eec1e5eaSJiri Pirko {
368eec1e5eaSJiri Pirko 	return devlink_port->ops->port_fn_ipsec_packet_set(devlink_port, enable, extack);
369eec1e5eaSJiri Pirko }
370eec1e5eaSJiri Pirko 
devlink_port_fn_caps_set(struct devlink_port * devlink_port,const struct nlattr * attr,struct netlink_ext_ack * extack)371eec1e5eaSJiri Pirko static int devlink_port_fn_caps_set(struct devlink_port *devlink_port,
372eec1e5eaSJiri Pirko 				    const struct nlattr *attr,
373eec1e5eaSJiri Pirko 				    struct netlink_ext_ack *extack)
374eec1e5eaSJiri Pirko {
375eec1e5eaSJiri Pirko 	struct nla_bitfield32 caps;
376eec1e5eaSJiri Pirko 	u32 caps_value;
377eec1e5eaSJiri Pirko 	int err;
378eec1e5eaSJiri Pirko 
379eec1e5eaSJiri Pirko 	caps = nla_get_bitfield32(attr);
380eec1e5eaSJiri Pirko 	caps_value = caps.value & caps.selector;
381eec1e5eaSJiri Pirko 	if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE) {
382eec1e5eaSJiri Pirko 		err = devlink_port_fn_roce_set(devlink_port,
383eec1e5eaSJiri Pirko 					       caps_value & DEVLINK_PORT_FN_CAP_ROCE,
384eec1e5eaSJiri Pirko 					       extack);
385eec1e5eaSJiri Pirko 		if (err)
386eec1e5eaSJiri Pirko 			return err;
387eec1e5eaSJiri Pirko 	}
388eec1e5eaSJiri Pirko 	if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) {
389eec1e5eaSJiri Pirko 		err = devlink_port_fn_mig_set(devlink_port, caps_value &
390eec1e5eaSJiri Pirko 					      DEVLINK_PORT_FN_CAP_MIGRATABLE,
391eec1e5eaSJiri Pirko 					      extack);
392eec1e5eaSJiri Pirko 		if (err)
393eec1e5eaSJiri Pirko 			return err;
394eec1e5eaSJiri Pirko 	}
395eec1e5eaSJiri Pirko 	if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO) {
396eec1e5eaSJiri Pirko 		err = devlink_port_fn_ipsec_crypto_set(devlink_port, caps_value &
397eec1e5eaSJiri Pirko 						       DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO,
398eec1e5eaSJiri Pirko 						       extack);
399eec1e5eaSJiri Pirko 		if (err)
400eec1e5eaSJiri Pirko 			return err;
401eec1e5eaSJiri Pirko 	}
402eec1e5eaSJiri Pirko 	if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_PACKET) {
403eec1e5eaSJiri Pirko 		err = devlink_port_fn_ipsec_packet_set(devlink_port, caps_value &
404eec1e5eaSJiri Pirko 						       DEVLINK_PORT_FN_CAP_IPSEC_PACKET,
405eec1e5eaSJiri Pirko 						       extack);
406eec1e5eaSJiri Pirko 		if (err)
407eec1e5eaSJiri Pirko 			return err;
408eec1e5eaSJiri Pirko 	}
409eec1e5eaSJiri Pirko 	return 0;
410eec1e5eaSJiri Pirko }
411eec1e5eaSJiri Pirko 
412eec1e5eaSJiri Pirko static int
devlink_nl_port_function_attrs_put(struct sk_buff * msg,struct devlink_port * port,struct netlink_ext_ack * extack)413eec1e5eaSJiri Pirko devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
414eec1e5eaSJiri Pirko 				   struct netlink_ext_ack *extack)
415eec1e5eaSJiri Pirko {
416eec1e5eaSJiri Pirko 	struct nlattr *function_attr;
417eec1e5eaSJiri Pirko 	bool msg_updated = false;
418eec1e5eaSJiri Pirko 	int err;
419eec1e5eaSJiri Pirko 
420eec1e5eaSJiri Pirko 	function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
421eec1e5eaSJiri Pirko 	if (!function_attr)
422eec1e5eaSJiri Pirko 		return -EMSGSIZE;
423eec1e5eaSJiri Pirko 
424eec1e5eaSJiri Pirko 	err = devlink_port_fn_hw_addr_fill(port, msg, extack, &msg_updated);
425eec1e5eaSJiri Pirko 	if (err)
426eec1e5eaSJiri Pirko 		goto out;
427eec1e5eaSJiri Pirko 	err = devlink_port_fn_caps_fill(port, msg, extack, &msg_updated);
428eec1e5eaSJiri Pirko 	if (err)
429eec1e5eaSJiri Pirko 		goto out;
430eec1e5eaSJiri Pirko 	err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated);
431eec1e5eaSJiri Pirko out:
432eec1e5eaSJiri Pirko 	if (err || !msg_updated)
433eec1e5eaSJiri Pirko 		nla_nest_cancel(msg, function_attr);
434eec1e5eaSJiri Pirko 	else
435eec1e5eaSJiri Pirko 		nla_nest_end(msg, function_attr);
436eec1e5eaSJiri Pirko 	return err;
437eec1e5eaSJiri Pirko }
438eec1e5eaSJiri Pirko 
devlink_nl_port_fill(struct sk_buff * msg,struct devlink_port * devlink_port,enum devlink_command cmd,u32 portid,u32 seq,int flags,struct netlink_ext_ack * extack)439eec1e5eaSJiri Pirko static int devlink_nl_port_fill(struct sk_buff *msg,
440eec1e5eaSJiri Pirko 				struct devlink_port *devlink_port,
441eec1e5eaSJiri Pirko 				enum devlink_command cmd, u32 portid, u32 seq,
442eec1e5eaSJiri Pirko 				int flags, struct netlink_ext_ack *extack)
443eec1e5eaSJiri Pirko {
444eec1e5eaSJiri Pirko 	struct devlink *devlink = devlink_port->devlink;
445eec1e5eaSJiri Pirko 	void *hdr;
446eec1e5eaSJiri Pirko 
447eec1e5eaSJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
448eec1e5eaSJiri Pirko 	if (!hdr)
449eec1e5eaSJiri Pirko 		return -EMSGSIZE;
450eec1e5eaSJiri Pirko 
451eec1e5eaSJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
452eec1e5eaSJiri Pirko 		goto nla_put_failure;
453eec1e5eaSJiri Pirko 	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
454eec1e5eaSJiri Pirko 		goto nla_put_failure;
455eec1e5eaSJiri Pirko 
456eec1e5eaSJiri Pirko 	spin_lock_bh(&devlink_port->type_lock);
457eec1e5eaSJiri Pirko 	if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
458eec1e5eaSJiri Pirko 		goto nla_put_failure_type_locked;
459eec1e5eaSJiri Pirko 	if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
460eec1e5eaSJiri Pirko 	    nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
461eec1e5eaSJiri Pirko 			devlink_port->desired_type))
462eec1e5eaSJiri Pirko 		goto nla_put_failure_type_locked;
463eec1e5eaSJiri Pirko 	if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
464eec1e5eaSJiri Pirko 		if (devlink_port->type_eth.netdev &&
465eec1e5eaSJiri Pirko 		    (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
466eec1e5eaSJiri Pirko 				 devlink_port->type_eth.ifindex) ||
467eec1e5eaSJiri Pirko 		     nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
468eec1e5eaSJiri Pirko 				    devlink_port->type_eth.ifname)))
469eec1e5eaSJiri Pirko 			goto nla_put_failure_type_locked;
470eec1e5eaSJiri Pirko 	}
471eec1e5eaSJiri Pirko 	if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
472eec1e5eaSJiri Pirko 		struct ib_device *ibdev = devlink_port->type_ib.ibdev;
473eec1e5eaSJiri Pirko 
474eec1e5eaSJiri Pirko 		if (ibdev &&
475eec1e5eaSJiri Pirko 		    nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
476eec1e5eaSJiri Pirko 				   ibdev->name))
477eec1e5eaSJiri Pirko 			goto nla_put_failure_type_locked;
478eec1e5eaSJiri Pirko 	}
479eec1e5eaSJiri Pirko 	spin_unlock_bh(&devlink_port->type_lock);
480eec1e5eaSJiri Pirko 	if (devlink_nl_port_attrs_put(msg, devlink_port))
481eec1e5eaSJiri Pirko 		goto nla_put_failure;
482eec1e5eaSJiri Pirko 	if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
483eec1e5eaSJiri Pirko 		goto nla_put_failure;
484eec1e5eaSJiri Pirko 	if (devlink_port->linecard &&
485eec1e5eaSJiri Pirko 	    nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX,
486eec1e5eaSJiri Pirko 			devlink_port->linecard->index))
487eec1e5eaSJiri Pirko 		goto nla_put_failure;
488eec1e5eaSJiri Pirko 
489eec1e5eaSJiri Pirko 	genlmsg_end(msg, hdr);
490eec1e5eaSJiri Pirko 	return 0;
491eec1e5eaSJiri Pirko 
492eec1e5eaSJiri Pirko nla_put_failure_type_locked:
493eec1e5eaSJiri Pirko 	spin_unlock_bh(&devlink_port->type_lock);
494eec1e5eaSJiri Pirko nla_put_failure:
495eec1e5eaSJiri Pirko 	genlmsg_cancel(msg, hdr);
496eec1e5eaSJiri Pirko 	return -EMSGSIZE;
497eec1e5eaSJiri Pirko }
498eec1e5eaSJiri Pirko 
devlink_port_notify(struct devlink_port * devlink_port,enum devlink_command cmd)499eec1e5eaSJiri Pirko static void devlink_port_notify(struct devlink_port *devlink_port,
500eec1e5eaSJiri Pirko 				enum devlink_command cmd)
501eec1e5eaSJiri Pirko {
502eec1e5eaSJiri Pirko 	struct devlink *devlink = devlink_port->devlink;
503eec1e5eaSJiri Pirko 	struct sk_buff *msg;
504eec1e5eaSJiri Pirko 	int err;
505eec1e5eaSJiri Pirko 
506eec1e5eaSJiri Pirko 	WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
507eec1e5eaSJiri Pirko 
508eec1e5eaSJiri Pirko 	if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
509eec1e5eaSJiri Pirko 		return;
510eec1e5eaSJiri Pirko 
511eec1e5eaSJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
512eec1e5eaSJiri Pirko 	if (!msg)
513eec1e5eaSJiri Pirko 		return;
514eec1e5eaSJiri Pirko 
515eec1e5eaSJiri Pirko 	err = devlink_nl_port_fill(msg, devlink_port, cmd, 0, 0, 0, NULL);
516eec1e5eaSJiri Pirko 	if (err) {
517eec1e5eaSJiri Pirko 		nlmsg_free(msg);
518eec1e5eaSJiri Pirko 		return;
519eec1e5eaSJiri Pirko 	}
520eec1e5eaSJiri Pirko 
521eec1e5eaSJiri Pirko 	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
522eec1e5eaSJiri Pirko 				0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
523eec1e5eaSJiri Pirko }
524eec1e5eaSJiri Pirko 
devlink_ports_notify(struct devlink * devlink,enum devlink_command cmd)525eec1e5eaSJiri Pirko static void devlink_ports_notify(struct devlink *devlink,
526eec1e5eaSJiri Pirko 				 enum devlink_command cmd)
527eec1e5eaSJiri Pirko {
528eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port;
529eec1e5eaSJiri Pirko 	unsigned long port_index;
530eec1e5eaSJiri Pirko 
531eec1e5eaSJiri Pirko 	xa_for_each(&devlink->ports, port_index, devlink_port)
532eec1e5eaSJiri Pirko 		devlink_port_notify(devlink_port, cmd);
533eec1e5eaSJiri Pirko }
534eec1e5eaSJiri Pirko 
devlink_ports_notify_register(struct devlink * devlink)535eec1e5eaSJiri Pirko void devlink_ports_notify_register(struct devlink *devlink)
536eec1e5eaSJiri Pirko {
537eec1e5eaSJiri Pirko 	devlink_ports_notify(devlink, DEVLINK_CMD_PORT_NEW);
538eec1e5eaSJiri Pirko }
539eec1e5eaSJiri Pirko 
devlink_ports_notify_unregister(struct devlink * devlink)540eec1e5eaSJiri Pirko void devlink_ports_notify_unregister(struct devlink *devlink)
541eec1e5eaSJiri Pirko {
542eec1e5eaSJiri Pirko 	devlink_ports_notify(devlink, DEVLINK_CMD_PORT_DEL);
543eec1e5eaSJiri Pirko }
544eec1e5eaSJiri Pirko 
devlink_nl_port_get_doit(struct sk_buff * skb,struct genl_info * info)545eec1e5eaSJiri Pirko int devlink_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info)
546eec1e5eaSJiri Pirko {
547eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = info->user_ptr[1];
548eec1e5eaSJiri Pirko 	struct sk_buff *msg;
549eec1e5eaSJiri Pirko 	int err;
550eec1e5eaSJiri Pirko 
551eec1e5eaSJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
552eec1e5eaSJiri Pirko 	if (!msg)
553eec1e5eaSJiri Pirko 		return -ENOMEM;
554eec1e5eaSJiri Pirko 
555eec1e5eaSJiri Pirko 	err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
556eec1e5eaSJiri Pirko 				   info->snd_portid, info->snd_seq, 0,
557eec1e5eaSJiri Pirko 				   info->extack);
558eec1e5eaSJiri Pirko 	if (err) {
559eec1e5eaSJiri Pirko 		nlmsg_free(msg);
560eec1e5eaSJiri Pirko 		return err;
561eec1e5eaSJiri Pirko 	}
562eec1e5eaSJiri Pirko 
563eec1e5eaSJiri Pirko 	return genlmsg_reply(msg, info);
564eec1e5eaSJiri Pirko }
565eec1e5eaSJiri Pirko 
566eec1e5eaSJiri Pirko static int
devlink_nl_port_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)567eec1e5eaSJiri Pirko devlink_nl_port_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
568eec1e5eaSJiri Pirko 			     struct netlink_callback *cb, int flags)
569eec1e5eaSJiri Pirko {
570eec1e5eaSJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
571eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port;
572eec1e5eaSJiri Pirko 	unsigned long port_index;
573eec1e5eaSJiri Pirko 	int err = 0;
574eec1e5eaSJiri Pirko 
575eec1e5eaSJiri Pirko 	xa_for_each_start(&devlink->ports, port_index, devlink_port, state->idx) {
576eec1e5eaSJiri Pirko 		err = devlink_nl_port_fill(msg, devlink_port,
57730d8d56aSJiri Pirko 					   DEVLINK_CMD_PORT_NEW,
578eec1e5eaSJiri Pirko 					   NETLINK_CB(cb->skb).portid,
579eec1e5eaSJiri Pirko 					   cb->nlh->nlmsg_seq, flags,
580eec1e5eaSJiri Pirko 					   cb->extack);
581eec1e5eaSJiri Pirko 		if (err) {
582eec1e5eaSJiri Pirko 			state->idx = port_index;
583eec1e5eaSJiri Pirko 			break;
584eec1e5eaSJiri Pirko 		}
585eec1e5eaSJiri Pirko 	}
586eec1e5eaSJiri Pirko 
587eec1e5eaSJiri Pirko 	return err;
588eec1e5eaSJiri Pirko }
589eec1e5eaSJiri Pirko 
devlink_nl_port_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)590eec1e5eaSJiri Pirko int devlink_nl_port_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
591eec1e5eaSJiri Pirko {
592eec1e5eaSJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_port_get_dump_one);
593eec1e5eaSJiri Pirko }
594eec1e5eaSJiri Pirko 
devlink_port_type_set(struct devlink_port * devlink_port,enum devlink_port_type port_type)595eec1e5eaSJiri Pirko static int devlink_port_type_set(struct devlink_port *devlink_port,
596eec1e5eaSJiri Pirko 				 enum devlink_port_type port_type)
597eec1e5eaSJiri Pirko 
598eec1e5eaSJiri Pirko {
599eec1e5eaSJiri Pirko 	int err;
600eec1e5eaSJiri Pirko 
601eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_type_set)
602eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
603eec1e5eaSJiri Pirko 
604eec1e5eaSJiri Pirko 	if (port_type == devlink_port->type)
605eec1e5eaSJiri Pirko 		return 0;
606eec1e5eaSJiri Pirko 
607eec1e5eaSJiri Pirko 	err = devlink_port->ops->port_type_set(devlink_port, port_type);
608eec1e5eaSJiri Pirko 	if (err)
609eec1e5eaSJiri Pirko 		return err;
610eec1e5eaSJiri Pirko 
611eec1e5eaSJiri Pirko 	devlink_port->desired_type = port_type;
612eec1e5eaSJiri Pirko 	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
613eec1e5eaSJiri Pirko 	return 0;
614eec1e5eaSJiri Pirko }
615eec1e5eaSJiri Pirko 
devlink_port_function_hw_addr_set(struct devlink_port * port,const struct nlattr * attr,struct netlink_ext_ack * extack)616eec1e5eaSJiri Pirko static int devlink_port_function_hw_addr_set(struct devlink_port *port,
617eec1e5eaSJiri Pirko 					     const struct nlattr *attr,
618eec1e5eaSJiri Pirko 					     struct netlink_ext_ack *extack)
619eec1e5eaSJiri Pirko {
620eec1e5eaSJiri Pirko 	const u8 *hw_addr;
621eec1e5eaSJiri Pirko 	int hw_addr_len;
622eec1e5eaSJiri Pirko 
623eec1e5eaSJiri Pirko 	hw_addr = nla_data(attr);
624eec1e5eaSJiri Pirko 	hw_addr_len = nla_len(attr);
625eec1e5eaSJiri Pirko 	if (hw_addr_len > MAX_ADDR_LEN) {
626eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(extack, "Port function hardware address too long");
627eec1e5eaSJiri Pirko 		return -EINVAL;
628eec1e5eaSJiri Pirko 	}
629eec1e5eaSJiri Pirko 	if (port->type == DEVLINK_PORT_TYPE_ETH) {
630eec1e5eaSJiri Pirko 		if (hw_addr_len != ETH_ALEN) {
631eec1e5eaSJiri Pirko 			NL_SET_ERR_MSG(extack, "Address must be 6 bytes for Ethernet device");
632eec1e5eaSJiri Pirko 			return -EINVAL;
633eec1e5eaSJiri Pirko 		}
634eec1e5eaSJiri Pirko 		if (!is_unicast_ether_addr(hw_addr)) {
635eec1e5eaSJiri Pirko 			NL_SET_ERR_MSG(extack, "Non-unicast hardware address unsupported");
636eec1e5eaSJiri Pirko 			return -EINVAL;
637eec1e5eaSJiri Pirko 		}
638eec1e5eaSJiri Pirko 	}
639eec1e5eaSJiri Pirko 
640eec1e5eaSJiri Pirko 	return port->ops->port_fn_hw_addr_set(port, hw_addr, hw_addr_len,
641eec1e5eaSJiri Pirko 					      extack);
642eec1e5eaSJiri Pirko }
643eec1e5eaSJiri Pirko 
devlink_port_fn_state_set(struct devlink_port * port,const struct nlattr * attr,struct netlink_ext_ack * extack)644eec1e5eaSJiri Pirko static int devlink_port_fn_state_set(struct devlink_port *port,
645eec1e5eaSJiri Pirko 				     const struct nlattr *attr,
646eec1e5eaSJiri Pirko 				     struct netlink_ext_ack *extack)
647eec1e5eaSJiri Pirko {
648eec1e5eaSJiri Pirko 	enum devlink_port_fn_state state;
649eec1e5eaSJiri Pirko 
650eec1e5eaSJiri Pirko 	state = nla_get_u8(attr);
651eec1e5eaSJiri Pirko 	return port->ops->port_fn_state_set(port, state, extack);
652eec1e5eaSJiri Pirko }
653eec1e5eaSJiri Pirko 
devlink_port_function_validate(struct devlink_port * devlink_port,struct nlattr ** tb,struct netlink_ext_ack * extack)654eec1e5eaSJiri Pirko static int devlink_port_function_validate(struct devlink_port *devlink_port,
655eec1e5eaSJiri Pirko 					  struct nlattr **tb,
656eec1e5eaSJiri Pirko 					  struct netlink_ext_ack *extack)
657eec1e5eaSJiri Pirko {
658eec1e5eaSJiri Pirko 	const struct devlink_port_ops *ops = devlink_port->ops;
659eec1e5eaSJiri Pirko 	struct nlattr *attr;
660eec1e5eaSJiri Pirko 
661eec1e5eaSJiri Pirko 	if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] &&
662eec1e5eaSJiri Pirko 	    !ops->port_fn_hw_addr_set) {
663eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR],
664eec1e5eaSJiri Pirko 				    "Port doesn't support function attributes");
665eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
666eec1e5eaSJiri Pirko 	}
667eec1e5eaSJiri Pirko 	if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) {
668ef3d6ed3SParav Pandit 		NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FN_ATTR_STATE],
669eec1e5eaSJiri Pirko 				    "Function does not support state setting");
670eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
671eec1e5eaSJiri Pirko 	}
672eec1e5eaSJiri Pirko 	attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
673eec1e5eaSJiri Pirko 	if (attr) {
674eec1e5eaSJiri Pirko 		struct nla_bitfield32 caps;
675eec1e5eaSJiri Pirko 
676eec1e5eaSJiri Pirko 		caps = nla_get_bitfield32(attr);
677eec1e5eaSJiri Pirko 		if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE &&
678eec1e5eaSJiri Pirko 		    !ops->port_fn_roce_set) {
679eec1e5eaSJiri Pirko 			NL_SET_ERR_MSG_ATTR(extack, attr,
680eec1e5eaSJiri Pirko 					    "Port doesn't support RoCE function attribute");
681eec1e5eaSJiri Pirko 			return -EOPNOTSUPP;
682eec1e5eaSJiri Pirko 		}
683eec1e5eaSJiri Pirko 		if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) {
684eec1e5eaSJiri Pirko 			if (!ops->port_fn_migratable_set) {
685eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
686eec1e5eaSJiri Pirko 						    "Port doesn't support migratable function attribute");
687eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
688eec1e5eaSJiri Pirko 			}
689eec1e5eaSJiri Pirko 			if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
690eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
691eec1e5eaSJiri Pirko 						    "migratable function attribute supported for VFs only");
692eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
693eec1e5eaSJiri Pirko 			}
694eec1e5eaSJiri Pirko 		}
695eec1e5eaSJiri Pirko 		if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO) {
696eec1e5eaSJiri Pirko 			if (!ops->port_fn_ipsec_crypto_set) {
697eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
698eec1e5eaSJiri Pirko 						    "Port doesn't support ipsec_crypto function attribute");
699eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
700eec1e5eaSJiri Pirko 			}
701eec1e5eaSJiri Pirko 			if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
702eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
703eec1e5eaSJiri Pirko 						    "ipsec_crypto function attribute supported for VFs only");
704eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
705eec1e5eaSJiri Pirko 			}
706eec1e5eaSJiri Pirko 		}
707eec1e5eaSJiri Pirko 		if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_PACKET) {
708eec1e5eaSJiri Pirko 			if (!ops->port_fn_ipsec_packet_set) {
709eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
710eec1e5eaSJiri Pirko 						    "Port doesn't support ipsec_packet function attribute");
711eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
712eec1e5eaSJiri Pirko 			}
713eec1e5eaSJiri Pirko 			if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
714eec1e5eaSJiri Pirko 				NL_SET_ERR_MSG_ATTR(extack, attr,
715eec1e5eaSJiri Pirko 						    "ipsec_packet function attribute supported for VFs only");
716eec1e5eaSJiri Pirko 				return -EOPNOTSUPP;
717eec1e5eaSJiri Pirko 			}
718eec1e5eaSJiri Pirko 		}
719eec1e5eaSJiri Pirko 	}
720eec1e5eaSJiri Pirko 	return 0;
721eec1e5eaSJiri Pirko }
722eec1e5eaSJiri Pirko 
devlink_port_function_set(struct devlink_port * port,const struct nlattr * attr,struct netlink_ext_ack * extack)723eec1e5eaSJiri Pirko static int devlink_port_function_set(struct devlink_port *port,
724eec1e5eaSJiri Pirko 				     const struct nlattr *attr,
725eec1e5eaSJiri Pirko 				     struct netlink_ext_ack *extack)
726eec1e5eaSJiri Pirko {
727eec1e5eaSJiri Pirko 	struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
728eec1e5eaSJiri Pirko 	int err;
729eec1e5eaSJiri Pirko 
730eec1e5eaSJiri Pirko 	err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
731eec1e5eaSJiri Pirko 			       devlink_function_nl_policy, extack);
732eec1e5eaSJiri Pirko 	if (err < 0) {
733eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(extack, "Fail to parse port function attributes");
734eec1e5eaSJiri Pirko 		return err;
735eec1e5eaSJiri Pirko 	}
736eec1e5eaSJiri Pirko 
737eec1e5eaSJiri Pirko 	err = devlink_port_function_validate(port, tb, extack);
738eec1e5eaSJiri Pirko 	if (err)
739eec1e5eaSJiri Pirko 		return err;
740eec1e5eaSJiri Pirko 
741eec1e5eaSJiri Pirko 	attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
742eec1e5eaSJiri Pirko 	if (attr) {
743eec1e5eaSJiri Pirko 		err = devlink_port_function_hw_addr_set(port, attr, extack);
744eec1e5eaSJiri Pirko 		if (err)
745eec1e5eaSJiri Pirko 			return err;
746eec1e5eaSJiri Pirko 	}
747eec1e5eaSJiri Pirko 
748eec1e5eaSJiri Pirko 	attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
749eec1e5eaSJiri Pirko 	if (attr) {
750eec1e5eaSJiri Pirko 		err = devlink_port_fn_caps_set(port, attr, extack);
751eec1e5eaSJiri Pirko 		if (err)
752eec1e5eaSJiri Pirko 			return err;
753eec1e5eaSJiri Pirko 	}
754eec1e5eaSJiri Pirko 
755eec1e5eaSJiri Pirko 	/* Keep this as the last function attribute set, so that when
756eec1e5eaSJiri Pirko 	 * multiple port function attributes are set along with state,
757eec1e5eaSJiri Pirko 	 * Those can be applied first before activating the state.
758eec1e5eaSJiri Pirko 	 */
759eec1e5eaSJiri Pirko 	attr = tb[DEVLINK_PORT_FN_ATTR_STATE];
760eec1e5eaSJiri Pirko 	if (attr)
761eec1e5eaSJiri Pirko 		err = devlink_port_fn_state_set(port, attr, extack);
762eec1e5eaSJiri Pirko 
763eec1e5eaSJiri Pirko 	if (!err)
764eec1e5eaSJiri Pirko 		devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
765eec1e5eaSJiri Pirko 	return err;
766eec1e5eaSJiri Pirko }
767eec1e5eaSJiri Pirko 
devlink_nl_cmd_port_set_doit(struct sk_buff * skb,struct genl_info * info)768eec1e5eaSJiri Pirko int devlink_nl_cmd_port_set_doit(struct sk_buff *skb, struct genl_info *info)
769eec1e5eaSJiri Pirko {
770eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = info->user_ptr[1];
771eec1e5eaSJiri Pirko 	int err;
772eec1e5eaSJiri Pirko 
773eec1e5eaSJiri Pirko 	if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
774eec1e5eaSJiri Pirko 		enum devlink_port_type port_type;
775eec1e5eaSJiri Pirko 
776eec1e5eaSJiri Pirko 		port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
777eec1e5eaSJiri Pirko 		err = devlink_port_type_set(devlink_port, port_type);
778eec1e5eaSJiri Pirko 		if (err)
779eec1e5eaSJiri Pirko 			return err;
780eec1e5eaSJiri Pirko 	}
781eec1e5eaSJiri Pirko 
782eec1e5eaSJiri Pirko 	if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
783eec1e5eaSJiri Pirko 		struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
784eec1e5eaSJiri Pirko 		struct netlink_ext_ack *extack = info->extack;
785eec1e5eaSJiri Pirko 
786eec1e5eaSJiri Pirko 		err = devlink_port_function_set(devlink_port, attr, extack);
787eec1e5eaSJiri Pirko 		if (err)
788eec1e5eaSJiri Pirko 			return err;
789eec1e5eaSJiri Pirko 	}
790eec1e5eaSJiri Pirko 
791eec1e5eaSJiri Pirko 	return 0;
792eec1e5eaSJiri Pirko }
793eec1e5eaSJiri Pirko 
devlink_nl_cmd_port_split_doit(struct sk_buff * skb,struct genl_info * info)794eec1e5eaSJiri Pirko int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, struct genl_info *info)
795eec1e5eaSJiri Pirko {
796eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = info->user_ptr[1];
797eec1e5eaSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
798eec1e5eaSJiri Pirko 	u32 count;
799eec1e5eaSJiri Pirko 
800eec1e5eaSJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT))
801eec1e5eaSJiri Pirko 		return -EINVAL;
802eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_split)
803eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
804eec1e5eaSJiri Pirko 
805eec1e5eaSJiri Pirko 	count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
806eec1e5eaSJiri Pirko 
807eec1e5eaSJiri Pirko 	if (!devlink_port->attrs.splittable) {
808eec1e5eaSJiri Pirko 		/* Split ports cannot be split. */
809eec1e5eaSJiri Pirko 		if (devlink_port->attrs.split)
810eec1e5eaSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Port cannot be split further");
811eec1e5eaSJiri Pirko 		else
812eec1e5eaSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Port cannot be split");
813eec1e5eaSJiri Pirko 		return -EINVAL;
814eec1e5eaSJiri Pirko 	}
815eec1e5eaSJiri Pirko 
816eec1e5eaSJiri Pirko 	if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
817eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(info->extack, "Invalid split count");
818eec1e5eaSJiri Pirko 		return -EINVAL;
819eec1e5eaSJiri Pirko 	}
820eec1e5eaSJiri Pirko 
821eec1e5eaSJiri Pirko 	return devlink_port->ops->port_split(devlink, devlink_port, count,
822eec1e5eaSJiri Pirko 					     info->extack);
823eec1e5eaSJiri Pirko }
824eec1e5eaSJiri Pirko 
devlink_nl_cmd_port_unsplit_doit(struct sk_buff * skb,struct genl_info * info)825eec1e5eaSJiri Pirko int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
826eec1e5eaSJiri Pirko 				     struct genl_info *info)
827eec1e5eaSJiri Pirko {
828eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = info->user_ptr[1];
829eec1e5eaSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
830eec1e5eaSJiri Pirko 
831eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_unsplit)
832eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
833eec1e5eaSJiri Pirko 	return devlink_port->ops->port_unsplit(devlink, devlink_port, info->extack);
834eec1e5eaSJiri Pirko }
835eec1e5eaSJiri Pirko 
devlink_nl_cmd_port_new_doit(struct sk_buff * skb,struct genl_info * info)836eec1e5eaSJiri Pirko int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct genl_info *info)
837eec1e5eaSJiri Pirko {
838eec1e5eaSJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
839eec1e5eaSJiri Pirko 	struct devlink_port_new_attrs new_attrs = {};
840eec1e5eaSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
841eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port;
842eec1e5eaSJiri Pirko 	struct sk_buff *msg;
843eec1e5eaSJiri Pirko 	int err;
844eec1e5eaSJiri Pirko 
845eec1e5eaSJiri Pirko 	if (!devlink->ops->port_new)
846eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
847eec1e5eaSJiri Pirko 
848eec1e5eaSJiri Pirko 	if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] ||
849eec1e5eaSJiri Pirko 	    !info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
850eec1e5eaSJiri Pirko 		NL_SET_ERR_MSG(extack, "Port flavour or PCI PF are not specified");
851eec1e5eaSJiri Pirko 		return -EINVAL;
852eec1e5eaSJiri Pirko 	}
853eec1e5eaSJiri Pirko 	new_attrs.flavour = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_FLAVOUR]);
854eec1e5eaSJiri Pirko 	new_attrs.pfnum =
855eec1e5eaSJiri Pirko 		nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
856eec1e5eaSJiri Pirko 
857eec1e5eaSJiri Pirko 	if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
858eec1e5eaSJiri Pirko 		/* Port index of the new port being created by driver. */
859eec1e5eaSJiri Pirko 		new_attrs.port_index =
860eec1e5eaSJiri Pirko 			nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
861eec1e5eaSJiri Pirko 		new_attrs.port_index_valid = true;
862eec1e5eaSJiri Pirko 	}
863eec1e5eaSJiri Pirko 	if (info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]) {
864eec1e5eaSJiri Pirko 		new_attrs.controller =
865eec1e5eaSJiri Pirko 			nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]);
866eec1e5eaSJiri Pirko 		new_attrs.controller_valid = true;
867eec1e5eaSJiri Pirko 	}
868eec1e5eaSJiri Pirko 	if (new_attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_SF &&
869eec1e5eaSJiri Pirko 	    info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
870eec1e5eaSJiri Pirko 		new_attrs.sfnum = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
871eec1e5eaSJiri Pirko 		new_attrs.sfnum_valid = true;
872eec1e5eaSJiri Pirko 	}
873eec1e5eaSJiri Pirko 
874eec1e5eaSJiri Pirko 	err = devlink->ops->port_new(devlink, &new_attrs,
875eec1e5eaSJiri Pirko 				     extack, &devlink_port);
876eec1e5eaSJiri Pirko 	if (err)
877eec1e5eaSJiri Pirko 		return err;
878eec1e5eaSJiri Pirko 
879eec1e5eaSJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
880eec1e5eaSJiri Pirko 	if (!msg) {
881eec1e5eaSJiri Pirko 		err = -ENOMEM;
882eec1e5eaSJiri Pirko 		goto err_out_port_del;
883eec1e5eaSJiri Pirko 	}
884*7d8c7bc9SJiri Pirko 	err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
885eec1e5eaSJiri Pirko 				   info->snd_portid, info->snd_seq, 0, NULL);
886eec1e5eaSJiri Pirko 	if (WARN_ON_ONCE(err))
887eec1e5eaSJiri Pirko 		goto err_out_msg_free;
888eec1e5eaSJiri Pirko 	err = genlmsg_reply(msg, info);
889eec1e5eaSJiri Pirko 	if (err)
890eec1e5eaSJiri Pirko 		goto err_out_port_del;
891eec1e5eaSJiri Pirko 	return 0;
892eec1e5eaSJiri Pirko 
893eec1e5eaSJiri Pirko err_out_msg_free:
894eec1e5eaSJiri Pirko 	nlmsg_free(msg);
895eec1e5eaSJiri Pirko err_out_port_del:
896eec1e5eaSJiri Pirko 	devlink_port->ops->port_del(devlink, devlink_port, NULL);
897eec1e5eaSJiri Pirko 	return err;
898eec1e5eaSJiri Pirko }
899eec1e5eaSJiri Pirko 
devlink_nl_cmd_port_del_doit(struct sk_buff * skb,struct genl_info * info)900eec1e5eaSJiri Pirko int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct genl_info *info)
901eec1e5eaSJiri Pirko {
902eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = info->user_ptr[1];
903eec1e5eaSJiri Pirko 	struct netlink_ext_ack *extack = info->extack;
904eec1e5eaSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
905eec1e5eaSJiri Pirko 
906eec1e5eaSJiri Pirko 	if (!devlink_port->ops->port_del)
907eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
908eec1e5eaSJiri Pirko 
909eec1e5eaSJiri Pirko 	return devlink_port->ops->port_del(devlink, devlink_port, extack);
910eec1e5eaSJiri Pirko }
911eec1e5eaSJiri Pirko 
devlink_port_type_warn(struct work_struct * work)912eec1e5eaSJiri Pirko static void devlink_port_type_warn(struct work_struct *work)
913eec1e5eaSJiri Pirko {
914eec1e5eaSJiri Pirko 	struct devlink_port *port = container_of(to_delayed_work(work),
915eec1e5eaSJiri Pirko 						 struct devlink_port,
916eec1e5eaSJiri Pirko 						 type_warn_dw);
917eec1e5eaSJiri Pirko 	dev_warn(port->devlink->dev, "Type was not set for devlink port.");
918eec1e5eaSJiri Pirko }
919eec1e5eaSJiri Pirko 
devlink_port_type_should_warn(struct devlink_port * devlink_port)920eec1e5eaSJiri Pirko static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
921eec1e5eaSJiri Pirko {
922eec1e5eaSJiri Pirko 	/* Ignore CPU and DSA flavours. */
923eec1e5eaSJiri Pirko 	return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
924eec1e5eaSJiri Pirko 	       devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
925eec1e5eaSJiri Pirko 	       devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
926eec1e5eaSJiri Pirko }
927eec1e5eaSJiri Pirko 
928eec1e5eaSJiri Pirko #define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
929eec1e5eaSJiri Pirko 
devlink_port_type_warn_schedule(struct devlink_port * devlink_port)930eec1e5eaSJiri Pirko static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
931eec1e5eaSJiri Pirko {
932eec1e5eaSJiri Pirko 	if (!devlink_port_type_should_warn(devlink_port))
933eec1e5eaSJiri Pirko 		return;
934eec1e5eaSJiri Pirko 	/* Schedule a work to WARN in case driver does not set port
935eec1e5eaSJiri Pirko 	 * type within timeout.
936eec1e5eaSJiri Pirko 	 */
937eec1e5eaSJiri Pirko 	schedule_delayed_work(&devlink_port->type_warn_dw,
938eec1e5eaSJiri Pirko 			      DEVLINK_PORT_TYPE_WARN_TIMEOUT);
939eec1e5eaSJiri Pirko }
940eec1e5eaSJiri Pirko 
devlink_port_type_warn_cancel(struct devlink_port * devlink_port)941eec1e5eaSJiri Pirko static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
942eec1e5eaSJiri Pirko {
943eec1e5eaSJiri Pirko 	if (!devlink_port_type_should_warn(devlink_port))
944eec1e5eaSJiri Pirko 		return;
945eec1e5eaSJiri Pirko 	cancel_delayed_work_sync(&devlink_port->type_warn_dw);
946eec1e5eaSJiri Pirko }
947eec1e5eaSJiri Pirko 
948eec1e5eaSJiri Pirko /**
949eec1e5eaSJiri Pirko  * devlink_port_init() - Init devlink port
950eec1e5eaSJiri Pirko  *
951eec1e5eaSJiri Pirko  * @devlink: devlink
952eec1e5eaSJiri Pirko  * @devlink_port: devlink port
953eec1e5eaSJiri Pirko  *
954eec1e5eaSJiri Pirko  * Initialize essential stuff that is needed for functions
955eec1e5eaSJiri Pirko  * that may be called before devlink port registration.
956eec1e5eaSJiri Pirko  * Call to this function is optional and not needed
957eec1e5eaSJiri Pirko  * in case the driver does not use such functions.
958eec1e5eaSJiri Pirko  */
devlink_port_init(struct devlink * devlink,struct devlink_port * devlink_port)959eec1e5eaSJiri Pirko void devlink_port_init(struct devlink *devlink,
960eec1e5eaSJiri Pirko 		       struct devlink_port *devlink_port)
961eec1e5eaSJiri Pirko {
962eec1e5eaSJiri Pirko 	if (devlink_port->initialized)
963eec1e5eaSJiri Pirko 		return;
964eec1e5eaSJiri Pirko 	devlink_port->devlink = devlink;
965eec1e5eaSJiri Pirko 	INIT_LIST_HEAD(&devlink_port->region_list);
966eec1e5eaSJiri Pirko 	devlink_port->initialized = true;
967eec1e5eaSJiri Pirko }
968eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_init);
969eec1e5eaSJiri Pirko 
970eec1e5eaSJiri Pirko /**
971eec1e5eaSJiri Pirko  * devlink_port_fini() - Deinitialize devlink port
972eec1e5eaSJiri Pirko  *
973eec1e5eaSJiri Pirko  * @devlink_port: devlink port
974eec1e5eaSJiri Pirko  *
975eec1e5eaSJiri Pirko  * Deinitialize essential stuff that is in use for functions
976eec1e5eaSJiri Pirko  * that may be called after devlink port unregistration.
977eec1e5eaSJiri Pirko  * Call to this function is optional and not needed
978eec1e5eaSJiri Pirko  * in case the driver does not use such functions.
979eec1e5eaSJiri Pirko  */
devlink_port_fini(struct devlink_port * devlink_port)980eec1e5eaSJiri Pirko void devlink_port_fini(struct devlink_port *devlink_port)
981eec1e5eaSJiri Pirko {
982eec1e5eaSJiri Pirko 	WARN_ON(!list_empty(&devlink_port->region_list));
983eec1e5eaSJiri Pirko }
984eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_fini);
985eec1e5eaSJiri Pirko 
986eec1e5eaSJiri Pirko static const struct devlink_port_ops devlink_port_dummy_ops = {};
987eec1e5eaSJiri Pirko 
988eec1e5eaSJiri Pirko /**
989eec1e5eaSJiri Pirko  * devl_port_register_with_ops() - Register devlink port
990eec1e5eaSJiri Pirko  *
991eec1e5eaSJiri Pirko  * @devlink: devlink
992eec1e5eaSJiri Pirko  * @devlink_port: devlink port
993eec1e5eaSJiri Pirko  * @port_index: driver-specific numerical identifier of the port
994eec1e5eaSJiri Pirko  * @ops: port ops
995eec1e5eaSJiri Pirko  *
996eec1e5eaSJiri Pirko  * Register devlink port with provided port index. User can use
997eec1e5eaSJiri Pirko  * any indexing, even hw-related one. devlink_port structure
998eec1e5eaSJiri Pirko  * is convenient to be embedded inside user driver private structure.
999eec1e5eaSJiri Pirko  * Note that the caller should take care of zeroing the devlink_port
1000eec1e5eaSJiri Pirko  * structure.
1001eec1e5eaSJiri Pirko  */
devl_port_register_with_ops(struct devlink * devlink,struct devlink_port * devlink_port,unsigned int port_index,const struct devlink_port_ops * ops)1002eec1e5eaSJiri Pirko int devl_port_register_with_ops(struct devlink *devlink,
1003eec1e5eaSJiri Pirko 				struct devlink_port *devlink_port,
1004eec1e5eaSJiri Pirko 				unsigned int port_index,
1005eec1e5eaSJiri Pirko 				const struct devlink_port_ops *ops)
1006eec1e5eaSJiri Pirko {
1007eec1e5eaSJiri Pirko 	int err;
1008eec1e5eaSJiri Pirko 
1009eec1e5eaSJiri Pirko 	devl_assert_locked(devlink);
1010eec1e5eaSJiri Pirko 
1011eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1012eec1e5eaSJiri Pirko 
1013eec1e5eaSJiri Pirko 	devlink_port_init(devlink, devlink_port);
1014eec1e5eaSJiri Pirko 	devlink_port->registered = true;
1015eec1e5eaSJiri Pirko 	devlink_port->index = port_index;
1016eec1e5eaSJiri Pirko 	devlink_port->ops = ops ? ops : &devlink_port_dummy_ops;
1017eec1e5eaSJiri Pirko 	spin_lock_init(&devlink_port->type_lock);
1018eec1e5eaSJiri Pirko 	INIT_LIST_HEAD(&devlink_port->reporter_list);
1019eec1e5eaSJiri Pirko 	err = xa_insert(&devlink->ports, port_index, devlink_port, GFP_KERNEL);
1020eec1e5eaSJiri Pirko 	if (err) {
1021eec1e5eaSJiri Pirko 		devlink_port->registered = false;
1022eec1e5eaSJiri Pirko 		return err;
1023eec1e5eaSJiri Pirko 	}
1024eec1e5eaSJiri Pirko 
1025eec1e5eaSJiri Pirko 	INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
1026eec1e5eaSJiri Pirko 	devlink_port_type_warn_schedule(devlink_port);
1027eec1e5eaSJiri Pirko 	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
1028eec1e5eaSJiri Pirko 	return 0;
1029eec1e5eaSJiri Pirko }
1030eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devl_port_register_with_ops);
1031eec1e5eaSJiri Pirko 
1032eec1e5eaSJiri Pirko /**
1033eec1e5eaSJiri Pirko  *	devlink_port_register_with_ops - Register devlink port
1034eec1e5eaSJiri Pirko  *
1035eec1e5eaSJiri Pirko  *	@devlink: devlink
1036eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1037eec1e5eaSJiri Pirko  *	@port_index: driver-specific numerical identifier of the port
1038eec1e5eaSJiri Pirko  *	@ops: port ops
1039eec1e5eaSJiri Pirko  *
1040eec1e5eaSJiri Pirko  *	Register devlink port with provided port index. User can use
1041eec1e5eaSJiri Pirko  *	any indexing, even hw-related one. devlink_port structure
1042eec1e5eaSJiri Pirko  *	is convenient to be embedded inside user driver private structure.
1043eec1e5eaSJiri Pirko  *	Note that the caller should take care of zeroing the devlink_port
1044eec1e5eaSJiri Pirko  *	structure.
1045eec1e5eaSJiri Pirko  *
1046eec1e5eaSJiri Pirko  *	Context: Takes and release devlink->lock <mutex>.
1047eec1e5eaSJiri Pirko  */
devlink_port_register_with_ops(struct devlink * devlink,struct devlink_port * devlink_port,unsigned int port_index,const struct devlink_port_ops * ops)1048eec1e5eaSJiri Pirko int devlink_port_register_with_ops(struct devlink *devlink,
1049eec1e5eaSJiri Pirko 				   struct devlink_port *devlink_port,
1050eec1e5eaSJiri Pirko 				   unsigned int port_index,
1051eec1e5eaSJiri Pirko 				   const struct devlink_port_ops *ops)
1052eec1e5eaSJiri Pirko {
1053eec1e5eaSJiri Pirko 	int err;
1054eec1e5eaSJiri Pirko 
1055eec1e5eaSJiri Pirko 	devl_lock(devlink);
1056eec1e5eaSJiri Pirko 	err = devl_port_register_with_ops(devlink, devlink_port,
1057eec1e5eaSJiri Pirko 					  port_index, ops);
1058eec1e5eaSJiri Pirko 	devl_unlock(devlink);
1059eec1e5eaSJiri Pirko 	return err;
1060eec1e5eaSJiri Pirko }
1061eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_register_with_ops);
1062eec1e5eaSJiri Pirko 
1063eec1e5eaSJiri Pirko /**
1064eec1e5eaSJiri Pirko  * devl_port_unregister() - Unregister devlink port
1065eec1e5eaSJiri Pirko  *
1066eec1e5eaSJiri Pirko  * @devlink_port: devlink port
1067eec1e5eaSJiri Pirko  */
devl_port_unregister(struct devlink_port * devlink_port)1068eec1e5eaSJiri Pirko void devl_port_unregister(struct devlink_port *devlink_port)
1069eec1e5eaSJiri Pirko {
1070eec1e5eaSJiri Pirko 	lockdep_assert_held(&devlink_port->devlink->lock);
1071eec1e5eaSJiri Pirko 	WARN_ON(devlink_port->type != DEVLINK_PORT_TYPE_NOTSET);
1072eec1e5eaSJiri Pirko 
1073eec1e5eaSJiri Pirko 	devlink_port_type_warn_cancel(devlink_port);
1074eec1e5eaSJiri Pirko 	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
1075eec1e5eaSJiri Pirko 	xa_erase(&devlink_port->devlink->ports, devlink_port->index);
1076eec1e5eaSJiri Pirko 	WARN_ON(!list_empty(&devlink_port->reporter_list));
1077eec1e5eaSJiri Pirko 	devlink_port->registered = false;
1078eec1e5eaSJiri Pirko }
1079eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devl_port_unregister);
1080eec1e5eaSJiri Pirko 
1081eec1e5eaSJiri Pirko /**
1082eec1e5eaSJiri Pirko  *	devlink_port_unregister - Unregister devlink port
1083eec1e5eaSJiri Pirko  *
1084eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1085eec1e5eaSJiri Pirko  *
1086eec1e5eaSJiri Pirko  *	Context: Takes and release devlink->lock <mutex>.
1087eec1e5eaSJiri Pirko  */
devlink_port_unregister(struct devlink_port * devlink_port)1088eec1e5eaSJiri Pirko void devlink_port_unregister(struct devlink_port *devlink_port)
1089eec1e5eaSJiri Pirko {
1090eec1e5eaSJiri Pirko 	struct devlink *devlink = devlink_port->devlink;
1091eec1e5eaSJiri Pirko 
1092eec1e5eaSJiri Pirko 	devl_lock(devlink);
1093eec1e5eaSJiri Pirko 	devl_port_unregister(devlink_port);
1094eec1e5eaSJiri Pirko 	devl_unlock(devlink);
1095eec1e5eaSJiri Pirko }
1096eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_unregister);
1097eec1e5eaSJiri Pirko 
devlink_port_type_netdev_checks(struct devlink_port * devlink_port,struct net_device * netdev)1098eec1e5eaSJiri Pirko static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
1099eec1e5eaSJiri Pirko 					    struct net_device *netdev)
1100eec1e5eaSJiri Pirko {
1101eec1e5eaSJiri Pirko 	const struct net_device_ops *ops = netdev->netdev_ops;
1102eec1e5eaSJiri Pirko 
1103eec1e5eaSJiri Pirko 	/* If driver registers devlink port, it should set devlink port
1104eec1e5eaSJiri Pirko 	 * attributes accordingly so the compat functions are called
1105eec1e5eaSJiri Pirko 	 * and the original ops are not used.
1106eec1e5eaSJiri Pirko 	 */
1107eec1e5eaSJiri Pirko 	if (ops->ndo_get_phys_port_name) {
1108eec1e5eaSJiri Pirko 		/* Some drivers use the same set of ndos for netdevs
1109eec1e5eaSJiri Pirko 		 * that have devlink_port registered and also for
1110eec1e5eaSJiri Pirko 		 * those who don't. Make sure that ndo_get_phys_port_name
1111eec1e5eaSJiri Pirko 		 * returns -EOPNOTSUPP here in case it is defined.
1112eec1e5eaSJiri Pirko 		 * Warn if not.
1113eec1e5eaSJiri Pirko 		 */
1114eec1e5eaSJiri Pirko 		char name[IFNAMSIZ];
1115eec1e5eaSJiri Pirko 		int err;
1116eec1e5eaSJiri Pirko 
1117eec1e5eaSJiri Pirko 		err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
1118eec1e5eaSJiri Pirko 		WARN_ON(err != -EOPNOTSUPP);
1119eec1e5eaSJiri Pirko 	}
1120eec1e5eaSJiri Pirko 	if (ops->ndo_get_port_parent_id) {
1121eec1e5eaSJiri Pirko 		/* Some drivers use the same set of ndos for netdevs
1122eec1e5eaSJiri Pirko 		 * that have devlink_port registered and also for
1123eec1e5eaSJiri Pirko 		 * those who don't. Make sure that ndo_get_port_parent_id
1124eec1e5eaSJiri Pirko 		 * returns -EOPNOTSUPP here in case it is defined.
1125eec1e5eaSJiri Pirko 		 * Warn if not.
1126eec1e5eaSJiri Pirko 		 */
1127eec1e5eaSJiri Pirko 		struct netdev_phys_item_id ppid;
1128eec1e5eaSJiri Pirko 		int err;
1129eec1e5eaSJiri Pirko 
1130eec1e5eaSJiri Pirko 		err = ops->ndo_get_port_parent_id(netdev, &ppid);
1131eec1e5eaSJiri Pirko 		WARN_ON(err != -EOPNOTSUPP);
1132eec1e5eaSJiri Pirko 	}
1133eec1e5eaSJiri Pirko }
1134eec1e5eaSJiri Pirko 
__devlink_port_type_set(struct devlink_port * devlink_port,enum devlink_port_type type,void * type_dev)1135eec1e5eaSJiri Pirko static void __devlink_port_type_set(struct devlink_port *devlink_port,
1136eec1e5eaSJiri Pirko 				    enum devlink_port_type type,
1137eec1e5eaSJiri Pirko 				    void *type_dev)
1138eec1e5eaSJiri Pirko {
1139eec1e5eaSJiri Pirko 	struct net_device *netdev = type_dev;
1140eec1e5eaSJiri Pirko 
1141eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_REGISTERED(devlink_port);
1142eec1e5eaSJiri Pirko 
1143eec1e5eaSJiri Pirko 	if (type == DEVLINK_PORT_TYPE_NOTSET) {
1144eec1e5eaSJiri Pirko 		devlink_port_type_warn_schedule(devlink_port);
1145eec1e5eaSJiri Pirko 	} else {
1146eec1e5eaSJiri Pirko 		devlink_port_type_warn_cancel(devlink_port);
1147eec1e5eaSJiri Pirko 		if (type == DEVLINK_PORT_TYPE_ETH && netdev)
1148eec1e5eaSJiri Pirko 			devlink_port_type_netdev_checks(devlink_port, netdev);
1149eec1e5eaSJiri Pirko 	}
1150eec1e5eaSJiri Pirko 
1151eec1e5eaSJiri Pirko 	spin_lock_bh(&devlink_port->type_lock);
1152eec1e5eaSJiri Pirko 	devlink_port->type = type;
1153eec1e5eaSJiri Pirko 	switch (type) {
1154eec1e5eaSJiri Pirko 	case DEVLINK_PORT_TYPE_ETH:
1155eec1e5eaSJiri Pirko 		devlink_port->type_eth.netdev = netdev;
1156eec1e5eaSJiri Pirko 		if (netdev) {
1157eec1e5eaSJiri Pirko 			ASSERT_RTNL();
1158eec1e5eaSJiri Pirko 			devlink_port->type_eth.ifindex = netdev->ifindex;
1159eec1e5eaSJiri Pirko 			BUILD_BUG_ON(sizeof(devlink_port->type_eth.ifname) !=
1160eec1e5eaSJiri Pirko 				     sizeof(netdev->name));
1161eec1e5eaSJiri Pirko 			strcpy(devlink_port->type_eth.ifname, netdev->name);
1162eec1e5eaSJiri Pirko 		}
1163eec1e5eaSJiri Pirko 		break;
1164eec1e5eaSJiri Pirko 	case DEVLINK_PORT_TYPE_IB:
1165eec1e5eaSJiri Pirko 		devlink_port->type_ib.ibdev = type_dev;
1166eec1e5eaSJiri Pirko 		break;
1167eec1e5eaSJiri Pirko 	default:
1168eec1e5eaSJiri Pirko 		break;
1169eec1e5eaSJiri Pirko 	}
1170eec1e5eaSJiri Pirko 	spin_unlock_bh(&devlink_port->type_lock);
1171eec1e5eaSJiri Pirko 	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
1172eec1e5eaSJiri Pirko }
1173eec1e5eaSJiri Pirko 
1174eec1e5eaSJiri Pirko /**
1175eec1e5eaSJiri Pirko  *	devlink_port_type_eth_set - Set port type to Ethernet
1176eec1e5eaSJiri Pirko  *
1177eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1178eec1e5eaSJiri Pirko  *
1179eec1e5eaSJiri Pirko  *	If driver is calling this, most likely it is doing something wrong.
1180eec1e5eaSJiri Pirko  */
devlink_port_type_eth_set(struct devlink_port * devlink_port)1181eec1e5eaSJiri Pirko void devlink_port_type_eth_set(struct devlink_port *devlink_port)
1182eec1e5eaSJiri Pirko {
1183eec1e5eaSJiri Pirko 	dev_warn(devlink_port->devlink->dev,
1184eec1e5eaSJiri Pirko 		 "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
1185eec1e5eaSJiri Pirko 		 devlink_port->index);
1186eec1e5eaSJiri Pirko 	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, NULL);
1187eec1e5eaSJiri Pirko }
1188eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
1189eec1e5eaSJiri Pirko 
1190eec1e5eaSJiri Pirko /**
1191eec1e5eaSJiri Pirko  *	devlink_port_type_ib_set - Set port type to InfiniBand
1192eec1e5eaSJiri Pirko  *
1193eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1194eec1e5eaSJiri Pirko  *	@ibdev: related IB device
1195eec1e5eaSJiri Pirko  */
devlink_port_type_ib_set(struct devlink_port * devlink_port,struct ib_device * ibdev)1196eec1e5eaSJiri Pirko void devlink_port_type_ib_set(struct devlink_port *devlink_port,
1197eec1e5eaSJiri Pirko 			      struct ib_device *ibdev)
1198eec1e5eaSJiri Pirko {
1199eec1e5eaSJiri Pirko 	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
1200eec1e5eaSJiri Pirko }
1201eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
1202eec1e5eaSJiri Pirko 
1203eec1e5eaSJiri Pirko /**
1204eec1e5eaSJiri Pirko  *	devlink_port_type_clear - Clear port type
1205eec1e5eaSJiri Pirko  *
1206eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1207eec1e5eaSJiri Pirko  *
1208eec1e5eaSJiri Pirko  *	If driver is calling this for clearing Ethernet type, most likely
1209eec1e5eaSJiri Pirko  *	it is doing something wrong.
1210eec1e5eaSJiri Pirko  */
devlink_port_type_clear(struct devlink_port * devlink_port)1211eec1e5eaSJiri Pirko void devlink_port_type_clear(struct devlink_port *devlink_port)
1212eec1e5eaSJiri Pirko {
1213eec1e5eaSJiri Pirko 	if (devlink_port->type == DEVLINK_PORT_TYPE_ETH)
1214eec1e5eaSJiri Pirko 		dev_warn(devlink_port->devlink->dev,
1215eec1e5eaSJiri Pirko 			 "devlink port type for port %d cleared without a software interface reference, device type not supported by the kernel?\n",
1216eec1e5eaSJiri Pirko 			 devlink_port->index);
1217eec1e5eaSJiri Pirko 	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
1218eec1e5eaSJiri Pirko }
1219eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_type_clear);
1220eec1e5eaSJiri Pirko 
devlink_port_netdevice_event(struct notifier_block * nb,unsigned long event,void * ptr)1221eec1e5eaSJiri Pirko int devlink_port_netdevice_event(struct notifier_block *nb,
1222eec1e5eaSJiri Pirko 				 unsigned long event, void *ptr)
1223eec1e5eaSJiri Pirko {
1224eec1e5eaSJiri Pirko 	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
1225eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port = netdev->devlink_port;
1226eec1e5eaSJiri Pirko 	struct devlink *devlink;
1227eec1e5eaSJiri Pirko 
1228eec1e5eaSJiri Pirko 	if (!devlink_port)
1229eec1e5eaSJiri Pirko 		return NOTIFY_OK;
1230eec1e5eaSJiri Pirko 	devlink = devlink_port->devlink;
1231eec1e5eaSJiri Pirko 
1232eec1e5eaSJiri Pirko 	switch (event) {
1233eec1e5eaSJiri Pirko 	case NETDEV_POST_INIT:
1234eec1e5eaSJiri Pirko 		/* Set the type but not netdev pointer. It is going to be set
1235eec1e5eaSJiri Pirko 		 * later on by NETDEV_REGISTER event. Happens once during
1236eec1e5eaSJiri Pirko 		 * netdevice register
1237eec1e5eaSJiri Pirko 		 */
1238eec1e5eaSJiri Pirko 		__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH,
1239eec1e5eaSJiri Pirko 					NULL);
1240eec1e5eaSJiri Pirko 		break;
1241eec1e5eaSJiri Pirko 	case NETDEV_REGISTER:
1242eec1e5eaSJiri Pirko 	case NETDEV_CHANGENAME:
1243eec1e5eaSJiri Pirko 		if (devlink_net(devlink) != dev_net(netdev))
1244eec1e5eaSJiri Pirko 			return NOTIFY_OK;
1245eec1e5eaSJiri Pirko 		/* Set the netdev on top of previously set type. Note this
1246eec1e5eaSJiri Pirko 		 * event happens also during net namespace change so here
1247eec1e5eaSJiri Pirko 		 * we take into account netdev pointer appearing in this
1248eec1e5eaSJiri Pirko 		 * namespace.
1249eec1e5eaSJiri Pirko 		 */
1250eec1e5eaSJiri Pirko 		__devlink_port_type_set(devlink_port, devlink_port->type,
1251eec1e5eaSJiri Pirko 					netdev);
1252eec1e5eaSJiri Pirko 		break;
1253eec1e5eaSJiri Pirko 	case NETDEV_UNREGISTER:
1254eec1e5eaSJiri Pirko 		if (devlink_net(devlink) != dev_net(netdev))
1255eec1e5eaSJiri Pirko 			return NOTIFY_OK;
1256eec1e5eaSJiri Pirko 		/* Clear netdev pointer, but not the type. This event happens
1257eec1e5eaSJiri Pirko 		 * also during net namespace change so we need to clear
1258eec1e5eaSJiri Pirko 		 * pointer to netdev that is going to another net namespace.
1259eec1e5eaSJiri Pirko 		 */
1260eec1e5eaSJiri Pirko 		__devlink_port_type_set(devlink_port, devlink_port->type,
1261eec1e5eaSJiri Pirko 					NULL);
1262eec1e5eaSJiri Pirko 		break;
1263eec1e5eaSJiri Pirko 	case NETDEV_PRE_UNINIT:
1264eec1e5eaSJiri Pirko 		/* Clear the type and the netdev pointer. Happens one during
1265eec1e5eaSJiri Pirko 		 * netdevice unregister.
1266eec1e5eaSJiri Pirko 		 */
1267eec1e5eaSJiri Pirko 		__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET,
1268eec1e5eaSJiri Pirko 					NULL);
1269eec1e5eaSJiri Pirko 		break;
1270eec1e5eaSJiri Pirko 	}
1271eec1e5eaSJiri Pirko 
1272eec1e5eaSJiri Pirko 	return NOTIFY_OK;
1273eec1e5eaSJiri Pirko }
1274eec1e5eaSJiri Pirko 
__devlink_port_attrs_set(struct devlink_port * devlink_port,enum devlink_port_flavour flavour)1275eec1e5eaSJiri Pirko static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
1276eec1e5eaSJiri Pirko 				    enum devlink_port_flavour flavour)
1277eec1e5eaSJiri Pirko {
1278eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
1279eec1e5eaSJiri Pirko 
1280eec1e5eaSJiri Pirko 	devlink_port->attrs_set = true;
1281eec1e5eaSJiri Pirko 	attrs->flavour = flavour;
1282eec1e5eaSJiri Pirko 	if (attrs->switch_id.id_len) {
1283eec1e5eaSJiri Pirko 		devlink_port->switch_port = true;
1284eec1e5eaSJiri Pirko 		if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
1285eec1e5eaSJiri Pirko 			attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
1286eec1e5eaSJiri Pirko 	} else {
1287eec1e5eaSJiri Pirko 		devlink_port->switch_port = false;
1288eec1e5eaSJiri Pirko 	}
1289eec1e5eaSJiri Pirko 	return 0;
1290eec1e5eaSJiri Pirko }
1291eec1e5eaSJiri Pirko 
1292eec1e5eaSJiri Pirko /**
1293eec1e5eaSJiri Pirko  *	devlink_port_attrs_set - Set port attributes
1294eec1e5eaSJiri Pirko  *
1295eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1296eec1e5eaSJiri Pirko  *	@attrs: devlink port attrs
1297eec1e5eaSJiri Pirko  */
devlink_port_attrs_set(struct devlink_port * devlink_port,struct devlink_port_attrs * attrs)1298eec1e5eaSJiri Pirko void devlink_port_attrs_set(struct devlink_port *devlink_port,
1299eec1e5eaSJiri Pirko 			    struct devlink_port_attrs *attrs)
1300eec1e5eaSJiri Pirko {
1301eec1e5eaSJiri Pirko 	int ret;
1302eec1e5eaSJiri Pirko 
1303eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1304eec1e5eaSJiri Pirko 
1305eec1e5eaSJiri Pirko 	devlink_port->attrs = *attrs;
1306eec1e5eaSJiri Pirko 	ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
1307eec1e5eaSJiri Pirko 	if (ret)
1308eec1e5eaSJiri Pirko 		return;
1309eec1e5eaSJiri Pirko 	WARN_ON(attrs->splittable && attrs->split);
1310eec1e5eaSJiri Pirko }
1311eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
1312eec1e5eaSJiri Pirko 
1313eec1e5eaSJiri Pirko /**
1314eec1e5eaSJiri Pirko  *	devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
1315eec1e5eaSJiri Pirko  *
1316eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1317eec1e5eaSJiri Pirko  *	@controller: associated controller number for the devlink port instance
1318eec1e5eaSJiri Pirko  *	@pf: associated PF for the devlink port instance
1319eec1e5eaSJiri Pirko  *	@external: indicates if the port is for an external controller
1320eec1e5eaSJiri Pirko  */
devlink_port_attrs_pci_pf_set(struct devlink_port * devlink_port,u32 controller,u16 pf,bool external)1321eec1e5eaSJiri Pirko void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
1322eec1e5eaSJiri Pirko 				   u16 pf, bool external)
1323eec1e5eaSJiri Pirko {
1324eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
1325eec1e5eaSJiri Pirko 	int ret;
1326eec1e5eaSJiri Pirko 
1327eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1328eec1e5eaSJiri Pirko 
1329eec1e5eaSJiri Pirko 	ret = __devlink_port_attrs_set(devlink_port,
1330eec1e5eaSJiri Pirko 				       DEVLINK_PORT_FLAVOUR_PCI_PF);
1331eec1e5eaSJiri Pirko 	if (ret)
1332eec1e5eaSJiri Pirko 		return;
1333eec1e5eaSJiri Pirko 	attrs->pci_pf.controller = controller;
1334eec1e5eaSJiri Pirko 	attrs->pci_pf.pf = pf;
1335eec1e5eaSJiri Pirko 	attrs->pci_pf.external = external;
1336eec1e5eaSJiri Pirko }
1337eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
1338eec1e5eaSJiri Pirko 
1339eec1e5eaSJiri Pirko /**
1340eec1e5eaSJiri Pirko  *	devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
1341eec1e5eaSJiri Pirko  *
1342eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1343eec1e5eaSJiri Pirko  *	@controller: associated controller number for the devlink port instance
1344eec1e5eaSJiri Pirko  *	@pf: associated PF for the devlink port instance
1345eec1e5eaSJiri Pirko  *	@vf: associated VF of a PF for the devlink port instance
1346eec1e5eaSJiri Pirko  *	@external: indicates if the port is for an external controller
1347eec1e5eaSJiri Pirko  */
devlink_port_attrs_pci_vf_set(struct devlink_port * devlink_port,u32 controller,u16 pf,u16 vf,bool external)1348eec1e5eaSJiri Pirko void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
1349eec1e5eaSJiri Pirko 				   u16 pf, u16 vf, bool external)
1350eec1e5eaSJiri Pirko {
1351eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
1352eec1e5eaSJiri Pirko 	int ret;
1353eec1e5eaSJiri Pirko 
1354eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1355eec1e5eaSJiri Pirko 
1356eec1e5eaSJiri Pirko 	ret = __devlink_port_attrs_set(devlink_port,
1357eec1e5eaSJiri Pirko 				       DEVLINK_PORT_FLAVOUR_PCI_VF);
1358eec1e5eaSJiri Pirko 	if (ret)
1359eec1e5eaSJiri Pirko 		return;
1360eec1e5eaSJiri Pirko 	attrs->pci_vf.controller = controller;
1361eec1e5eaSJiri Pirko 	attrs->pci_vf.pf = pf;
1362eec1e5eaSJiri Pirko 	attrs->pci_vf.vf = vf;
1363eec1e5eaSJiri Pirko 	attrs->pci_vf.external = external;
1364eec1e5eaSJiri Pirko }
1365eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
1366eec1e5eaSJiri Pirko 
1367eec1e5eaSJiri Pirko /**
1368eec1e5eaSJiri Pirko  *	devlink_port_attrs_pci_sf_set - Set PCI SF port attributes
1369eec1e5eaSJiri Pirko  *
1370eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1371eec1e5eaSJiri Pirko  *	@controller: associated controller number for the devlink port instance
1372eec1e5eaSJiri Pirko  *	@pf: associated PF for the devlink port instance
1373eec1e5eaSJiri Pirko  *	@sf: associated SF of a PF for the devlink port instance
1374eec1e5eaSJiri Pirko  *	@external: indicates if the port is for an external controller
1375eec1e5eaSJiri Pirko  */
devlink_port_attrs_pci_sf_set(struct devlink_port * devlink_port,u32 controller,u16 pf,u32 sf,bool external)1376eec1e5eaSJiri Pirko void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 controller,
1377eec1e5eaSJiri Pirko 				   u16 pf, u32 sf, bool external)
1378eec1e5eaSJiri Pirko {
1379eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
1380eec1e5eaSJiri Pirko 	int ret;
1381eec1e5eaSJiri Pirko 
1382eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1383eec1e5eaSJiri Pirko 
1384eec1e5eaSJiri Pirko 	ret = __devlink_port_attrs_set(devlink_port,
1385eec1e5eaSJiri Pirko 				       DEVLINK_PORT_FLAVOUR_PCI_SF);
1386eec1e5eaSJiri Pirko 	if (ret)
1387eec1e5eaSJiri Pirko 		return;
1388eec1e5eaSJiri Pirko 	attrs->pci_sf.controller = controller;
1389eec1e5eaSJiri Pirko 	attrs->pci_sf.pf = pf;
1390eec1e5eaSJiri Pirko 	attrs->pci_sf.sf = sf;
1391eec1e5eaSJiri Pirko 	attrs->pci_sf.external = external;
1392eec1e5eaSJiri Pirko }
1393eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set);
1394eec1e5eaSJiri Pirko 
1395eec1e5eaSJiri Pirko /**
1396eec1e5eaSJiri Pirko  *	devlink_port_linecard_set - Link port with a linecard
1397eec1e5eaSJiri Pirko  *
1398eec1e5eaSJiri Pirko  *	@devlink_port: devlink port
1399eec1e5eaSJiri Pirko  *	@linecard: devlink linecard
1400eec1e5eaSJiri Pirko  */
devlink_port_linecard_set(struct devlink_port * devlink_port,struct devlink_linecard * linecard)1401eec1e5eaSJiri Pirko void devlink_port_linecard_set(struct devlink_port *devlink_port,
1402eec1e5eaSJiri Pirko 			       struct devlink_linecard *linecard)
1403eec1e5eaSJiri Pirko {
1404eec1e5eaSJiri Pirko 	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
1405eec1e5eaSJiri Pirko 
1406eec1e5eaSJiri Pirko 	devlink_port->linecard = linecard;
1407eec1e5eaSJiri Pirko }
1408eec1e5eaSJiri Pirko EXPORT_SYMBOL_GPL(devlink_port_linecard_set);
1409eec1e5eaSJiri Pirko 
__devlink_port_phys_port_name_get(struct devlink_port * devlink_port,char * name,size_t len)1410eec1e5eaSJiri Pirko static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
1411eec1e5eaSJiri Pirko 					     char *name, size_t len)
1412eec1e5eaSJiri Pirko {
1413eec1e5eaSJiri Pirko 	struct devlink_port_attrs *attrs = &devlink_port->attrs;
1414eec1e5eaSJiri Pirko 	int n = 0;
1415eec1e5eaSJiri Pirko 
1416eec1e5eaSJiri Pirko 	if (!devlink_port->attrs_set)
1417eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
1418eec1e5eaSJiri Pirko 
1419eec1e5eaSJiri Pirko 	switch (attrs->flavour) {
1420eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PHYSICAL:
1421eec1e5eaSJiri Pirko 		if (devlink_port->linecard)
1422eec1e5eaSJiri Pirko 			n = snprintf(name, len, "l%u",
1423eec1e5eaSJiri Pirko 				     devlink_port->linecard->index);
1424eec1e5eaSJiri Pirko 		if (n < len)
1425eec1e5eaSJiri Pirko 			n += snprintf(name + n, len - n, "p%u",
1426eec1e5eaSJiri Pirko 				      attrs->phys.port_number);
1427eec1e5eaSJiri Pirko 		if (n < len && attrs->split)
1428eec1e5eaSJiri Pirko 			n += snprintf(name + n, len - n, "s%u",
1429eec1e5eaSJiri Pirko 				      attrs->phys.split_subport_number);
1430eec1e5eaSJiri Pirko 		break;
1431eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_CPU:
1432eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_DSA:
1433eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_UNUSED:
1434eec1e5eaSJiri Pirko 		/* As CPU and DSA ports do not have a netdevice associated
1435eec1e5eaSJiri Pirko 		 * case should not ever happen.
1436eec1e5eaSJiri Pirko 		 */
1437eec1e5eaSJiri Pirko 		WARN_ON(1);
1438eec1e5eaSJiri Pirko 		return -EINVAL;
1439eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_PF:
1440eec1e5eaSJiri Pirko 		if (attrs->pci_pf.external) {
1441eec1e5eaSJiri Pirko 			n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
1442eec1e5eaSJiri Pirko 			if (n >= len)
1443eec1e5eaSJiri Pirko 				return -EINVAL;
1444eec1e5eaSJiri Pirko 			len -= n;
1445eec1e5eaSJiri Pirko 			name += n;
1446eec1e5eaSJiri Pirko 		}
1447eec1e5eaSJiri Pirko 		n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
1448eec1e5eaSJiri Pirko 		break;
1449eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_VF:
1450eec1e5eaSJiri Pirko 		if (attrs->pci_vf.external) {
1451eec1e5eaSJiri Pirko 			n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
1452eec1e5eaSJiri Pirko 			if (n >= len)
1453eec1e5eaSJiri Pirko 				return -EINVAL;
1454eec1e5eaSJiri Pirko 			len -= n;
1455eec1e5eaSJiri Pirko 			name += n;
1456eec1e5eaSJiri Pirko 		}
1457eec1e5eaSJiri Pirko 		n = snprintf(name, len, "pf%uvf%u",
1458eec1e5eaSJiri Pirko 			     attrs->pci_vf.pf, attrs->pci_vf.vf);
1459eec1e5eaSJiri Pirko 		break;
1460eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_PCI_SF:
1461eec1e5eaSJiri Pirko 		if (attrs->pci_sf.external) {
1462eec1e5eaSJiri Pirko 			n = snprintf(name, len, "c%u", attrs->pci_sf.controller);
1463eec1e5eaSJiri Pirko 			if (n >= len)
1464eec1e5eaSJiri Pirko 				return -EINVAL;
1465eec1e5eaSJiri Pirko 			len -= n;
1466eec1e5eaSJiri Pirko 			name += n;
1467eec1e5eaSJiri Pirko 		}
1468eec1e5eaSJiri Pirko 		n = snprintf(name, len, "pf%usf%u", attrs->pci_sf.pf,
1469eec1e5eaSJiri Pirko 			     attrs->pci_sf.sf);
1470eec1e5eaSJiri Pirko 		break;
1471eec1e5eaSJiri Pirko 	case DEVLINK_PORT_FLAVOUR_VIRTUAL:
1472eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
1473eec1e5eaSJiri Pirko 	}
1474eec1e5eaSJiri Pirko 
1475eec1e5eaSJiri Pirko 	if (n >= len)
1476eec1e5eaSJiri Pirko 		return -EINVAL;
1477eec1e5eaSJiri Pirko 
1478eec1e5eaSJiri Pirko 	return 0;
1479eec1e5eaSJiri Pirko }
1480eec1e5eaSJiri Pirko 
devlink_compat_phys_port_name_get(struct net_device * dev,char * name,size_t len)1481eec1e5eaSJiri Pirko int devlink_compat_phys_port_name_get(struct net_device *dev,
1482eec1e5eaSJiri Pirko 				      char *name, size_t len)
1483eec1e5eaSJiri Pirko {
1484eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port;
1485eec1e5eaSJiri Pirko 
1486eec1e5eaSJiri Pirko 	/* RTNL mutex is held here which ensures that devlink_port
1487eec1e5eaSJiri Pirko 	 * instance cannot disappear in the middle. No need to take
1488eec1e5eaSJiri Pirko 	 * any devlink lock as only permanent values are accessed.
1489eec1e5eaSJiri Pirko 	 */
1490eec1e5eaSJiri Pirko 	ASSERT_RTNL();
1491eec1e5eaSJiri Pirko 
1492eec1e5eaSJiri Pirko 	devlink_port = dev->devlink_port;
1493eec1e5eaSJiri Pirko 	if (!devlink_port)
1494eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
1495eec1e5eaSJiri Pirko 
1496eec1e5eaSJiri Pirko 	return __devlink_port_phys_port_name_get(devlink_port, name, len);
1497eec1e5eaSJiri Pirko }
1498eec1e5eaSJiri Pirko 
devlink_compat_switch_id_get(struct net_device * dev,struct netdev_phys_item_id * ppid)1499eec1e5eaSJiri Pirko int devlink_compat_switch_id_get(struct net_device *dev,
1500eec1e5eaSJiri Pirko 				 struct netdev_phys_item_id *ppid)
1501eec1e5eaSJiri Pirko {
1502eec1e5eaSJiri Pirko 	struct devlink_port *devlink_port;
1503eec1e5eaSJiri Pirko 
1504eec1e5eaSJiri Pirko 	/* Caller must hold RTNL mutex or reference to dev, which ensures that
1505eec1e5eaSJiri Pirko 	 * devlink_port instance cannot disappear in the middle. No need to take
1506eec1e5eaSJiri Pirko 	 * any devlink lock as only permanent values are accessed.
1507eec1e5eaSJiri Pirko 	 */
1508eec1e5eaSJiri Pirko 	devlink_port = dev->devlink_port;
1509eec1e5eaSJiri Pirko 	if (!devlink_port || !devlink_port->switch_port)
1510eec1e5eaSJiri Pirko 		return -EOPNOTSUPP;
1511eec1e5eaSJiri Pirko 
1512eec1e5eaSJiri Pirko 	memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
1513eec1e5eaSJiri Pirko 
1514eec1e5eaSJiri Pirko 	return 0;
1515eec1e5eaSJiri Pirko }
1516