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