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 
7 static void
8 mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
9 {
10 	u64 parent_id;
11 
12 	parent_id = mlx5_query_nic_system_image_guid(dev);
13 	ppid->id_len = sizeof(parent_id);
14 	memcpy(ppid->id, &parent_id, sizeof(parent_id));
15 }
16 
17 static bool mlx5_esw_devlink_port_supported(struct mlx5_eswitch *esw, u16 vport_num)
18 {
19 	return vport_num == MLX5_VPORT_UPLINK ||
20 	       (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) ||
21 	       mlx5_eswitch_is_vf_vport(esw, vport_num) ||
22 	       mlx5_core_is_ec_vf_vport(esw->dev, vport_num);
23 }
24 
25 static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 vport_num)
26 {
27 	struct mlx5_core_dev *dev = esw->dev;
28 	struct devlink_port_attrs attrs = {};
29 	struct netdev_phys_item_id ppid = {};
30 	struct devlink_port *dl_port;
31 	u32 controller_num = 0;
32 	bool external;
33 	u16 pfnum;
34 
35 	dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
36 	if (!dl_port)
37 		return NULL;
38 
39 	mlx5_esw_get_port_parent_id(dev, &ppid);
40 	pfnum = mlx5_get_dev_index(dev);
41 	external = mlx5_core_is_ecpf_esw_manager(dev);
42 	if (external)
43 		controller_num = dev->priv.eswitch->offloads.host_number + 1;
44 
45 	if (vport_num == MLX5_VPORT_UPLINK) {
46 		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
47 		attrs.phys.port_number = pfnum;
48 		memcpy(attrs.switch_id.id, ppid.id, ppid.id_len);
49 		attrs.switch_id.id_len = ppid.id_len;
50 		devlink_port_attrs_set(dl_port, &attrs);
51 	} else if (vport_num == MLX5_VPORT_PF) {
52 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
53 		dl_port->attrs.switch_id.id_len = ppid.id_len;
54 		devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum, external);
55 	} else if (mlx5_eswitch_is_vf_vport(esw, vport_num)) {
56 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
57 		dl_port->attrs.switch_id.id_len = ppid.id_len;
58 		devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum,
59 					      vport_num - 1, external);
60 	}  else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) {
61 		memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
62 		dl_port->attrs.switch_id.id_len = ppid.id_len;
63 		devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum,
64 					      vport_num - 1, false);
65 	}
66 	return dl_port;
67 }
68 
69 static void mlx5_esw_dl_port_free(struct devlink_port *dl_port)
70 {
71 	kfree(dl_port);
72 }
73 
74 static const struct devlink_port_ops mlx5_esw_dl_port_ops = {
75 	.port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
76 	.port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
77 	.port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
78 	.port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
79 	.port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get,
80 	.port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set,
81 };
82 
83 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num)
84 {
85 	struct mlx5_core_dev *dev = esw->dev;
86 	struct devlink_port *dl_port;
87 	unsigned int dl_port_index;
88 	struct mlx5_vport *vport;
89 	struct devlink *devlink;
90 	int err;
91 
92 	if (!mlx5_esw_devlink_port_supported(esw, vport_num))
93 		return 0;
94 
95 	vport = mlx5_eswitch_get_vport(esw, vport_num);
96 	if (IS_ERR(vport))
97 		return PTR_ERR(vport);
98 
99 	dl_port = mlx5_esw_dl_port_alloc(esw, vport_num);
100 	if (!dl_port)
101 		return -ENOMEM;
102 
103 	devlink = priv_to_devlink(dev);
104 	dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
105 	err = devl_port_register_with_ops(devlink, dl_port, dl_port_index,
106 					  &mlx5_esw_dl_port_ops);
107 	if (err)
108 		goto reg_err;
109 
110 	err = devl_rate_leaf_create(dl_port, vport, NULL);
111 	if (err)
112 		goto rate_err;
113 
114 	vport->dl_port = dl_port;
115 	return 0;
116 
117 rate_err:
118 	devl_port_unregister(dl_port);
119 reg_err:
120 	mlx5_esw_dl_port_free(dl_port);
121 	return err;
122 }
123 
124 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num)
125 {
126 	struct mlx5_vport *vport;
127 
128 	if (!mlx5_esw_devlink_port_supported(esw, vport_num))
129 		return;
130 
131 	vport = mlx5_eswitch_get_vport(esw, vport_num);
132 	if (IS_ERR(vport))
133 		return;
134 
135 	if (vport->dl_port->devlink_rate) {
136 		mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
137 		devl_rate_leaf_destroy(vport->dl_port);
138 	}
139 
140 	devl_port_unregister(vport->dl_port);
141 	mlx5_esw_dl_port_free(vport->dl_port);
142 	vport->dl_port = NULL;
143 }
144 
145 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num)
146 {
147 	struct mlx5_vport *vport;
148 
149 	vport = mlx5_eswitch_get_vport(esw, vport_num);
150 	return IS_ERR(vport) ? ERR_CAST(vport) : vport->dl_port;
151 }
152 
153 static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
154 #ifdef CONFIG_MLX5_SF_MANAGER
155 	.port_del = mlx5_devlink_sf_port_del,
156 #endif
157 	.port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
158 	.port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
159 	.port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
160 	.port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
161 #ifdef CONFIG_MLX5_SF_MANAGER
162 	.port_fn_state_get = mlx5_devlink_sf_port_fn_state_get,
163 	.port_fn_state_set = mlx5_devlink_sf_port_fn_state_set,
164 #endif
165 };
166 
167 int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
168 				      u16 vport_num, u32 controller, u32 sfnum)
169 {
170 	struct mlx5_core_dev *dev = esw->dev;
171 	struct netdev_phys_item_id ppid = {};
172 	unsigned int dl_port_index;
173 	struct mlx5_vport *vport;
174 	struct devlink *devlink;
175 	u16 pfnum;
176 	int err;
177 
178 	vport = mlx5_eswitch_get_vport(esw, vport_num);
179 	if (IS_ERR(vport))
180 		return PTR_ERR(vport);
181 
182 	pfnum = mlx5_get_dev_index(dev);
183 	mlx5_esw_get_port_parent_id(dev, &ppid);
184 	memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len);
185 	dl_port->attrs.switch_id.id_len = ppid.id_len;
186 	devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller);
187 	devlink = priv_to_devlink(dev);
188 	dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
189 	err = devl_port_register_with_ops(devlink, dl_port, dl_port_index,
190 					  &mlx5_esw_dl_sf_port_ops);
191 	if (err)
192 		return err;
193 
194 	err = devl_rate_leaf_create(dl_port, vport, NULL);
195 	if (err)
196 		goto rate_err;
197 
198 	vport->dl_port = dl_port;
199 	return 0;
200 
201 rate_err:
202 	devl_port_unregister(dl_port);
203 	return err;
204 }
205 
206 void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num)
207 {
208 	struct mlx5_vport *vport;
209 
210 	vport = mlx5_eswitch_get_vport(esw, vport_num);
211 	if (IS_ERR(vport))
212 		return;
213 
214 	if (vport->dl_port->devlink_rate) {
215 		mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
216 		devl_rate_leaf_destroy(vport->dl_port);
217 	}
218 
219 	devl_port_unregister(vport->dl_port);
220 	vport->dl_port = NULL;
221 }
222