xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies Ltd. */
3 
4 #include <linux/mlx5/driver.h>
5 #include "eswitch.h"
6 #include "devlink.h"
7 
8 static void
mlx5_esw_get_port_parent_id(struct mlx5_core_dev * dev,struct netdev_phys_item_id * ppid)9 mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
10 {
11 	mlx5_query_nic_sw_system_image_guid(dev, ppid->id, &ppid->id_len);
12 }
13 
mlx5_esw_devlink_port_supported(struct mlx5_eswitch * esw,u16 vport_num)14 static bool mlx5_esw_devlink_port_supported(struct mlx5_eswitch *esw, u16 vport_num)
15 {
16 	return (mlx5_core_is_ecpf(esw->dev) &&
17 		vport_num == MLX5_VPORT_HOST_PF) ||
18 	       mlx5_eswitch_is_vf_vport(esw, vport_num) ||
19 	       mlx5_core_is_ec_vf_vport(esw->dev, vport_num) ||
20 	       mlx5_esw_is_spf_vport(esw, vport_num);
21 }
22 
mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(struct mlx5_eswitch * esw,u16 vport_num,struct devlink_port * dl_port)23 static void mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(struct mlx5_eswitch *esw,
24 							   u16 vport_num,
25 							   struct devlink_port *dl_port)
26 {
27 	struct mlx5_core_dev *dev = esw->dev;
28 	struct netdev_phys_item_id ppid = {};
29 	struct mlx5_vport *vport;
30 	u32 controller_num = 0;
31 	bool external;
32 	u16 pfnum;
33 
34 	mlx5_esw_get_port_parent_id(dev, &ppid);
35 	pfnum = PCI_FUNC(dev->pdev->devfn);
36 	external = mlx5_core_is_ecpf_esw_manager(dev);
37 	if (external)
38 		controller_num = mlx5_esw_get_hpf_host_number(dev) + 1;
39 
40 	if (vport_num == MLX5_VPORT_HOST_PF) {
41 		if (external)
42 			pfnum = mlx5_esw_get_hpf_pf_num(dev);
43 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
44 		dl_port->attrs.switch_id.id_len = ppid.id_len;
45 		devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum, external);
46 	} else if (mlx5_eswitch_is_vf_vport(esw, vport_num)) {
47 		u16 func_id = vport_num - 1;
48 
49 		vport = mlx5_eswitch_get_vport(esw, vport_num);
50 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
51 		dl_port->attrs.switch_id.id_len = ppid.id_len;
52 		if (vport->adjacent) {
53 			func_id = vport->adj_info.function_id;
54 			pfnum = vport->adj_info.parent_pci_devfn;
55 		} else if (external) {
56 			pfnum = mlx5_esw_get_hpf_pf_num(dev);
57 		}
58 
59 		devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum,
60 					      func_id, external);
61 	}  else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) {
62 		u16 base_vport = mlx5_core_ec_vf_vport_base(dev);
63 
64 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
65 		dl_port->attrs.switch_id.id_len = ppid.id_len;
66 		devlink_port_attrs_pci_vf_set(dl_port, 0, pfnum,
67 					      vport_num - base_vport, false);
68 	} else if (mlx5_esw_is_spf_vport(esw, vport_num)) {
69 		int spf_idx = mlx5_esw_spf_vport_to_idx(esw, vport_num);
70 
71 		controller_num = esw->esw_funcs.spfs[spf_idx].host_number + 1;
72 		pfnum = esw->esw_funcs.spfs[spf_idx].pf_num;
73 
74 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
75 		dl_port->attrs.switch_id.id_len = ppid.id_len;
76 		devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum,
77 					      false);
78 	}
79 }
80 
mlx5_esw_offloads_pf_vf_devlink_port_init(struct mlx5_eswitch * esw,struct mlx5_vport * vport)81 int mlx5_esw_offloads_pf_vf_devlink_port_init(struct mlx5_eswitch *esw,
82 					      struct mlx5_vport *vport)
83 {
84 	struct mlx5_devlink_port *dl_port;
85 	u16 vport_num = vport->vport;
86 
87 	if (!mlx5_esw_devlink_port_supported(esw, vport_num))
88 		return 0;
89 
90 	dl_port = kzalloc_obj(*dl_port);
91 	if (!dl_port)
92 		return -ENOMEM;
93 
94 	mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(esw, vport_num,
95 						       &dl_port->dl_port);
96 
97 	vport->dl_port = dl_port;
98 	mlx5_devlink_port_init(dl_port, vport);
99 	return 0;
100 }
101 
mlx5_esw_offloads_pf_vf_devlink_port_cleanup(struct mlx5_eswitch * esw,struct mlx5_vport * vport)102 void mlx5_esw_offloads_pf_vf_devlink_port_cleanup(struct mlx5_eswitch *esw,
103 						  struct mlx5_vport *vport)
104 {
105 	if (!vport->dl_port)
106 		return;
107 
108 	kfree(vport->dl_port);
109 	vport->dl_port = NULL;
110 }
111 
112 static const struct devlink_port_ops mlx5_esw_pf_vf_dl_port_ops = {
113 	.port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
114 	.port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
115 	.port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
116 	.port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
117 	.port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get,
118 	.port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set,
119 	.port_fn_state_get = mlx5_devlink_pf_port_fn_state_get,
120 	.port_fn_state_set = mlx5_devlink_pf_port_fn_state_set,
121 #ifdef CONFIG_XFRM_OFFLOAD
122 	.port_fn_ipsec_crypto_get = mlx5_devlink_port_fn_ipsec_crypto_get,
123 	.port_fn_ipsec_crypto_set = mlx5_devlink_port_fn_ipsec_crypto_set,
124 	.port_fn_ipsec_packet_get = mlx5_devlink_port_fn_ipsec_packet_get,
125 	.port_fn_ipsec_packet_set = mlx5_devlink_port_fn_ipsec_packet_set,
126 #endif /* CONFIG_XFRM_OFFLOAD */
127 	.port_fn_max_io_eqs_get = mlx5_devlink_port_fn_max_io_eqs_get,
128 	.port_fn_max_io_eqs_set = mlx5_devlink_port_fn_max_io_eqs_set,
129 };
130 
mlx5_esw_offloads_sf_devlink_port_attrs_set(struct mlx5_eswitch * esw,struct devlink_port * dl_port,u32 controller,u32 sfnum)131 static void mlx5_esw_offloads_sf_devlink_port_attrs_set(struct mlx5_eswitch *esw,
132 							struct devlink_port *dl_port,
133 							u32 controller, u32 sfnum)
134 {
135 	struct mlx5_core_dev *dev = esw->dev;
136 	struct netdev_phys_item_id ppid = {};
137 	u32 hpf_ctrl;
138 	u16 pfnum;
139 
140 	pfnum = mlx5_esw_sf_controller_to_pfnum(dev, controller);
141 	hpf_ctrl = mlx5_esw_get_hpf_host_number(dev) + 1;
142 	mlx5_esw_get_port_parent_id(dev, &ppid);
143 	memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len);
144 	dl_port->attrs.switch_id.id_len = ppid.id_len;
145 	devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum,
146 				      controller == hpf_ctrl);
147 }
148 
mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch * esw,struct mlx5_vport * vport,struct mlx5_devlink_port * dl_port,u32 controller,u32 sfnum)149 int mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
150 					   struct mlx5_devlink_port *dl_port,
151 					   u32 controller, u32 sfnum)
152 {
153 	mlx5_esw_offloads_sf_devlink_port_attrs_set(esw, &dl_port->dl_port, controller, sfnum);
154 
155 	vport->dl_port = dl_port;
156 	mlx5_devlink_port_init(dl_port, vport);
157 	return 0;
158 }
159 
mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch * esw,struct mlx5_vport * vport)160 void mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
161 {
162 	vport->dl_port = NULL;
163 }
164 
165 static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
166 #ifdef CONFIG_MLX5_SF_MANAGER
167 	.port_del = mlx5_devlink_sf_port_del,
168 #endif
169 	.port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
170 	.port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
171 	.port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
172 	.port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
173 #ifdef CONFIG_MLX5_SF_MANAGER
174 	.port_fn_state_get = mlx5_devlink_sf_port_fn_state_get,
175 	.port_fn_state_set = mlx5_devlink_sf_port_fn_state_set,
176 #endif
177 	.port_fn_max_io_eqs_get = mlx5_devlink_port_fn_max_io_eqs_get,
178 	.port_fn_max_io_eqs_set = mlx5_devlink_port_fn_max_io_eqs_set,
179 };
180 
mlx5_esw_devlink_port_res_register(struct mlx5_eswitch * esw,struct devlink_port * dl_port,u16 vport_num)181 static int mlx5_esw_devlink_port_res_register(struct mlx5_eswitch *esw,
182 					      struct devlink_port *dl_port,
183 					      u16 vport_num)
184 {
185 	struct devlink_resource_size_params size_params;
186 	struct mlx5_core_dev *dev = esw->dev;
187 	u16 max_sfs, sf_base_id;
188 	int err;
189 
190 	if (vport_num != MLX5_VPORT_HOST_PF &&
191 	    !mlx5_esw_is_spf_vport(esw, vport_num))
192 		return 0;
193 
194 	if (vport_num == MLX5_VPORT_HOST_PF) {
195 		err = mlx5_esw_sf_max_hpf_functions(dev, &max_sfs,
196 						    &sf_base_id);
197 	} else {
198 		int spf_idx = mlx5_esw_spf_vport_to_idx(esw, vport_num);
199 
200 		err = mlx5_esw_sf_max_spf_functions(dev, spf_idx, &max_sfs,
201 						    &sf_base_id);
202 	}
203 
204 	if (err)
205 		return err;
206 
207 	devlink_resource_size_params_init(&size_params, max_sfs, max_sfs, 1,
208 					  DEVLINK_RESOURCE_UNIT_ENTRY);
209 
210 	return devl_port_resource_register(dl_port, "max_SFs", max_sfs,
211 					   MLX5_DL_PORT_RES_MAX_SFS,
212 					   DEVLINK_RESOURCE_ID_PARENT_TOP,
213 					   &size_params);
214 }
215 
mlx5_esw_devlink_port_res_unregister(struct devlink_port * dl_port)216 static void mlx5_esw_devlink_port_res_unregister(struct devlink_port *dl_port)
217 {
218 	devl_port_resources_unregister(dl_port);
219 }
220 
mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch * esw,struct mlx5_vport * vport)221 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
222 {
223 	struct mlx5_core_dev *dev = esw->dev;
224 	const struct devlink_port_ops *ops;
225 	struct mlx5_devlink_port *dl_port;
226 	u16 vport_num = vport->vport;
227 	unsigned int dl_port_index;
228 	struct devlink *devlink;
229 	int err;
230 
231 	dl_port = vport->dl_port;
232 	if (!dl_port)
233 		return 0;
234 
235 	if (mlx5_esw_is_sf_vport(esw, vport_num))
236 		ops = &mlx5_esw_dl_sf_port_ops;
237 	else if (mlx5_eswitch_is_pf_vf_vport(esw, vport_num))
238 		ops = &mlx5_esw_pf_vf_dl_port_ops;
239 	else
240 		ops = NULL;
241 
242 	devlink = priv_to_devlink(dev);
243 	dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
244 	err = devl_port_register_with_ops(devlink, &dl_port->dl_port, dl_port_index, ops);
245 	if (err)
246 		return err;
247 
248 	err = devl_rate_leaf_create(&dl_port->dl_port, vport, NULL);
249 	if (err)
250 		goto rate_err;
251 
252 	err = mlx5_esw_devlink_port_res_register(esw, &dl_port->dl_port,
253 						 vport_num);
254 	if (err)
255 		mlx5_core_dbg(dev, "Failed to register port resources: %d\n",
256 			      err);
257 
258 	return 0;
259 
260 rate_err:
261 	devl_port_unregister(&dl_port->dl_port);
262 	return err;
263 }
264 
mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport * vport)265 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
266 {
267 	struct mlx5_devlink_port *dl_port;
268 
269 	if (!vport->dl_port)
270 		return;
271 	dl_port = vport->dl_port;
272 	mlx5_esw_devlink_port_res_unregister(&dl_port->dl_port);
273 
274 	devl_rate_leaf_destroy(&dl_port->dl_port);
275 
276 	devl_port_unregister(&dl_port->dl_port);
277 }
278 
mlx5_esw_offloads_devlink_port(struct mlx5_eswitch * esw,u16 vport_num)279 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num)
280 {
281 	struct mlx5_vport *vport;
282 
283 	vport = mlx5_eswitch_get_vport(esw, vport_num);
284 	if (IS_ERR(vport))
285 		return ERR_CAST(vport);
286 	if (!vport->dl_port)
287 		return ERR_PTR(-ENODEV);
288 
289 	return &vport->dl_port->dl_port;
290 }
291