xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
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 <linux/mlx5/device.h>
6 #include "mlx5_core.h"
7 #include "dev.h"
8 #include "sf/vhca_event.h"
9 #include "sf/sf.h"
10 #include "sf/mlx5_ifc_vhca_event.h"
11 #include "ecpf.h"
12 #define CREATE_TRACE_POINTS
13 #include "diag/dev_tracepoint.h"
14 
15 struct mlx5_sf_dev_table {
16 	struct xarray devices;
17 	phys_addr_t base_address;
18 	u64 sf_bar_length;
19 	struct workqueue_struct *active_wq;
20 	struct work_struct work;
21 	u8 stop_active_wq:1;
22 	struct mlx5_core_dev *dev;
23 };
24 
25 struct mlx5_sf_dev_active_work_ctx {
26 	struct work_struct work;
27 	struct mlx5_vhca_state_event event;
28 	struct mlx5_sf_dev_table *table;
29 	int sf_index;
30 };
31 
mlx5_sf_dev_supported(const struct mlx5_core_dev * dev)32 static bool mlx5_sf_dev_supported(const struct mlx5_core_dev *dev)
33 {
34 	return MLX5_CAP_GEN(dev, sf) && mlx5_vhca_event_supported(dev);
35 }
36 
mlx5_sf_dev_allocated(const struct mlx5_core_dev * dev)37 bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev)
38 {
39 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
40 
41 	return table && !xa_empty(&table->devices);
42 }
43 
sfnum_show(struct device * dev,struct device_attribute * attr,char * buf)44 static ssize_t sfnum_show(struct device *dev, struct device_attribute *attr, char *buf)
45 {
46 	struct auxiliary_device *adev = container_of(dev, struct auxiliary_device, dev);
47 	struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
48 
49 	return sysfs_emit(buf, "%u\n", sf_dev->sfnum);
50 }
51 static DEVICE_ATTR_RO(sfnum);
52 
53 static struct attribute *sf_device_attrs[] = {
54 	&dev_attr_sfnum.attr,
55 	NULL,
56 };
57 
58 static const struct attribute_group sf_attr_group = {
59 	.attrs = sf_device_attrs,
60 };
61 
62 static const struct attribute_group *sf_attr_groups[2] = {
63 	&sf_attr_group,
64 	NULL
65 };
66 
mlx5_sf_dev_release(struct device * device)67 static void mlx5_sf_dev_release(struct device *device)
68 {
69 	struct auxiliary_device *adev = container_of(device, struct auxiliary_device, dev);
70 	struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
71 
72 	mlx5_adev_idx_free(adev->id);
73 	kfree(sf_dev);
74 }
75 
mlx5_sf_dev_remove_aux(struct mlx5_core_dev * dev,struct mlx5_sf_dev * sf_dev)76 static void mlx5_sf_dev_remove_aux(struct mlx5_core_dev *dev,
77 				   struct mlx5_sf_dev *sf_dev)
78 {
79 	int id;
80 
81 	id = sf_dev->adev.id;
82 	trace_mlx5_sf_dev_del(dev, sf_dev, id);
83 
84 	auxiliary_device_delete(&sf_dev->adev);
85 	auxiliary_device_uninit(&sf_dev->adev);
86 }
87 
mlx5_sf_dev_add(struct mlx5_core_dev * dev,u16 sf_index,u16 fn_id,u32 sfnum)88 static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u16 fn_id, u32 sfnum)
89 {
90 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
91 	struct mlx5_sf_dev *sf_dev;
92 	struct pci_dev *pdev;
93 	int err;
94 	int id;
95 
96 	id = mlx5_adev_idx_alloc();
97 	if (id < 0) {
98 		err = id;
99 		goto add_err;
100 	}
101 
102 	sf_dev = kzalloc_obj(*sf_dev);
103 	if (!sf_dev) {
104 		mlx5_adev_idx_free(id);
105 		err = -ENOMEM;
106 		goto add_err;
107 	}
108 	pdev = dev->pdev;
109 	sf_dev->adev.id = id;
110 	sf_dev->adev.name = MLX5_SF_DEV_ID_NAME;
111 	sf_dev->adev.dev.release = mlx5_sf_dev_release;
112 	sf_dev->adev.dev.parent = &pdev->dev;
113 	sf_dev->adev.dev.groups = sf_attr_groups;
114 	sf_dev->sfnum = sfnum;
115 	sf_dev->parent_mdev = dev;
116 	sf_dev->fn_id = fn_id;
117 
118 	sf_dev->bar_base_addr = table->base_address + (sf_index * table->sf_bar_length);
119 
120 	trace_mlx5_sf_dev_add(dev, sf_dev, id);
121 
122 	err = auxiliary_device_init(&sf_dev->adev);
123 	if (err) {
124 		mlx5_adev_idx_free(id);
125 		kfree(sf_dev);
126 		goto add_err;
127 	}
128 
129 	err = auxiliary_device_add(&sf_dev->adev);
130 	if (err) {
131 		auxiliary_device_uninit(&sf_dev->adev);
132 		goto add_err;
133 	}
134 
135 	err = xa_insert(&table->devices, sf_index, sf_dev, GFP_KERNEL);
136 	if (err)
137 		goto xa_err;
138 	return;
139 
140 xa_err:
141 	mlx5_sf_dev_remove_aux(dev, sf_dev);
142 add_err:
143 	mlx5_core_err(dev, "SF DEV: fail device add for index=%d sfnum=%d err=%d\n",
144 		      sf_index, sfnum, err);
145 }
146 
mlx5_sf_dev_del(struct mlx5_core_dev * dev,struct mlx5_sf_dev * sf_dev,u16 sf_index)147 static void mlx5_sf_dev_del(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev, u16 sf_index)
148 {
149 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
150 
151 	xa_erase(&table->devices, sf_index);
152 	mlx5_sf_dev_remove_aux(dev, sf_dev);
153 }
154 
155 static int
mlx5_sf_dev_state_change_handler(struct notifier_block * nb,unsigned long event_code,void * data)156 mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_code, void *data)
157 {
158 	struct mlx5_core_dev *dev = container_of(nb, struct mlx5_core_dev,
159 						 priv.sf_dev_nb);
160 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
161 	const struct mlx5_vhca_state_event *event = data;
162 	struct mlx5_sf_dev *sf_dev;
163 	u16 max_functions;
164 	u16 sf_index;
165 	u16 base_id;
166 
167 	if (!table)
168 		return 0;
169 
170 	max_functions = mlx5_sf_max_functions(dev);
171 	if (!max_functions)
172 		return 0;
173 
174 	base_id = mlx5_sf_start_function_id(dev);
175 	if (event->function_id < base_id || event->function_id >= (base_id + max_functions))
176 		return 0;
177 
178 	sf_index = event->function_id - base_id;
179 	sf_dev = xa_load(&table->devices, sf_index);
180 	switch (event->new_vhca_state) {
181 	case MLX5_VHCA_STATE_INVALID:
182 	case MLX5_VHCA_STATE_ALLOCATED:
183 		if (sf_dev)
184 			mlx5_sf_dev_del(dev, sf_dev, sf_index);
185 		break;
186 	case MLX5_VHCA_STATE_TEARDOWN_REQUEST:
187 		if (sf_dev)
188 			mlx5_sf_dev_del(dev, sf_dev, sf_index);
189 		else
190 			mlx5_core_err(dev,
191 				      "SF DEV: teardown state for invalid dev index=%d sfnum=0x%x\n",
192 				      sf_index, event->sw_function_id);
193 		break;
194 	case MLX5_VHCA_STATE_ACTIVE:
195 		if (!sf_dev)
196 			mlx5_sf_dev_add(dev, sf_index, event->function_id,
197 					event->sw_function_id);
198 		break;
199 	default:
200 		break;
201 	}
202 	return 0;
203 }
204 
mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table * table)205 static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table)
206 {
207 	struct mlx5_core_dev *dev = table->dev;
208 	u16 max_functions;
209 	u16 function_id;
210 	int err = 0;
211 	int i;
212 
213 	max_functions = mlx5_sf_max_functions(dev);
214 	function_id = mlx5_sf_start_function_id(dev);
215 	/* Arm the vhca context as the vhca event notifier */
216 	for (i = 0; i < max_functions; i++) {
217 		err = mlx5_vhca_event_arm(dev, function_id);
218 		if (err)
219 			return err;
220 
221 		function_id++;
222 	}
223 	return 0;
224 }
225 
mlx5_sf_dev_add_active_work(struct work_struct * _work)226 static void mlx5_sf_dev_add_active_work(struct work_struct *_work)
227 {
228 	struct mlx5_sf_dev_active_work_ctx *work_ctx;
229 
230 	work_ctx = container_of(_work, struct mlx5_sf_dev_active_work_ctx, work);
231 	if (work_ctx->table->stop_active_wq)
232 		goto out;
233 	/* Don't probe device which is already probe */
234 	if (!xa_load(&work_ctx->table->devices, work_ctx->sf_index))
235 		mlx5_sf_dev_add(work_ctx->table->dev, work_ctx->sf_index,
236 				work_ctx->event.function_id, work_ctx->event.sw_function_id);
237 	/* There is a race where SF got inactive after the query
238 	 * above. e.g.: the query returns that the state of the
239 	 * SF is active, and after that the eswitch manager set it to
240 	 * inactive.
241 	 * This case cannot be managed in SW, since the probing of the
242 	 * SF is on one system, and the inactivation is on a different
243 	 * system.
244 	 * If the inactive is done after the SF perform init_hca(),
245 	 * the SF will fully probe and then removed. If it was
246 	 * done before init_hca(), the SF probe will fail.
247 	 */
248 out:
249 	kfree(work_ctx);
250 }
251 
252 /* In case SFs are generated externally, probe active SFs */
mlx5_sf_dev_queue_active_works(struct work_struct * _work)253 static void mlx5_sf_dev_queue_active_works(struct work_struct *_work)
254 {
255 	struct mlx5_sf_dev_table *table = container_of(_work, struct mlx5_sf_dev_table, work);
256 	u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {};
257 	struct mlx5_sf_dev_active_work_ctx *work_ctx;
258 	struct mlx5_core_dev *dev = table->dev;
259 	u16 max_functions;
260 	u16 function_id;
261 	u16 sw_func_id;
262 	int err = 0;
263 	int wq_idx;
264 	u8 state;
265 	int i;
266 
267 	max_functions = mlx5_sf_max_functions(dev);
268 	function_id = mlx5_sf_start_function_id(dev);
269 	for (i = 0; i < max_functions; i++, function_id++) {
270 		if (table->stop_active_wq)
271 			return;
272 		err = mlx5_cmd_query_vhca_state(dev, function_id, out, sizeof(out));
273 		if (err)
274 			/* A failure of specific vhca doesn't mean others will
275 			 * fail as well.
276 			 */
277 			continue;
278 		state = MLX5_GET(query_vhca_state_out, out, vhca_state_context.vhca_state);
279 		if (state != MLX5_VHCA_STATE_ACTIVE)
280 			continue;
281 
282 		sw_func_id = MLX5_GET(query_vhca_state_out, out, vhca_state_context.sw_function_id);
283 		work_ctx = kzalloc_obj(*work_ctx);
284 		if (!work_ctx)
285 			return;
286 
287 		INIT_WORK(&work_ctx->work, &mlx5_sf_dev_add_active_work);
288 		work_ctx->event.function_id = function_id;
289 		work_ctx->event.sw_function_id = sw_func_id;
290 		work_ctx->table = table;
291 		work_ctx->sf_index = i;
292 		wq_idx = work_ctx->event.function_id % MLX5_DEV_MAX_WQS;
293 		mlx5_vhca_events_work_enqueue(dev, wq_idx, &work_ctx->work);
294 	}
295 }
296 
297 /* In case SFs are generated externally, probe active SFs */
mlx5_sf_dev_create_active_works(struct mlx5_sf_dev_table * table)298 static int mlx5_sf_dev_create_active_works(struct mlx5_sf_dev_table *table)
299 {
300 	if (MLX5_CAP_GEN(table->dev, eswitch_manager))
301 		return 0; /* the table is local */
302 
303 	/* Use a workqueue to probe active SFs, which are in large
304 	 * quantity and may take up to minutes to probe.
305 	 */
306 	table->active_wq = create_singlethread_workqueue("mlx5_active_sf");
307 	if (!table->active_wq)
308 		return -ENOMEM;
309 	INIT_WORK(&table->work, &mlx5_sf_dev_queue_active_works);
310 	queue_work(table->active_wq, &table->work);
311 	return 0;
312 }
313 
mlx5_sf_dev_destroy_active_works(struct mlx5_sf_dev_table * table)314 static void mlx5_sf_dev_destroy_active_works(struct mlx5_sf_dev_table *table)
315 {
316 	if (table->active_wq) {
317 		table->stop_active_wq = true;
318 		destroy_workqueue(table->active_wq);
319 	}
320 }
321 
mlx5_sf_dev_notifier_init(struct mlx5_core_dev * dev)322 int mlx5_sf_dev_notifier_init(struct mlx5_core_dev *dev)
323 {
324 	if (mlx5_core_is_sf(dev))
325 		return 0;
326 
327 	dev->priv.sf_dev_nb.notifier_call = mlx5_sf_dev_state_change_handler;
328 	return mlx5_vhca_event_notifier_register(dev, &dev->priv.sf_dev_nb);
329 }
330 
mlx5_sf_dev_table_create(struct mlx5_core_dev * dev)331 void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
332 {
333 	struct mlx5_sf_dev_table *table;
334 	int err;
335 
336 	if (!mlx5_sf_dev_supported(dev))
337 		return;
338 
339 	table = kzalloc_obj(*table);
340 	if (!table) {
341 		err = -ENOMEM;
342 		goto table_err;
343 	}
344 
345 	table->dev = dev;
346 	table->sf_bar_length = 1 << (MLX5_CAP_GEN(dev, log_min_sf_size) + 12);
347 	table->base_address = pci_resource_start(dev->pdev, 2);
348 	xa_init(&table->devices);
349 	dev->priv.sf_dev_table = table;
350 
351 	err = mlx5_sf_dev_create_active_works(table);
352 	if (err)
353 		goto add_active_err;
354 
355 	err = mlx5_sf_dev_vhca_arm_all(table);
356 	if (err)
357 		goto arm_err;
358 	return;
359 
360 arm_err:
361 	mlx5_sf_dev_destroy_active_works(table);
362 	mlx5_vhca_event_work_queues_flush(dev);
363 add_active_err:
364 	kfree(table);
365 	dev->priv.sf_dev_table = NULL;
366 table_err:
367 	mlx5_core_err(dev, "SF DEV table create err = %d\n", err);
368 }
369 
mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table * table)370 static void mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table *table)
371 {
372 	struct mlx5_sf_dev *sf_dev;
373 	unsigned long index;
374 
375 	xa_for_each(&table->devices, index, sf_dev) {
376 		xa_erase(&table->devices, index);
377 		mlx5_sf_dev_remove_aux(table->dev, sf_dev);
378 	}
379 }
380 
mlx5_sf_dev_notifier_cleanup(struct mlx5_core_dev * dev)381 void mlx5_sf_dev_notifier_cleanup(struct mlx5_core_dev *dev)
382 {
383 	if (mlx5_core_is_sf(dev))
384 		return;
385 
386 	mlx5_vhca_event_notifier_unregister(dev, &dev->priv.sf_dev_nb);
387 }
388 
mlx5_sf_dev_table_destroy(struct mlx5_core_dev * dev)389 void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev)
390 {
391 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
392 
393 	if (!table)
394 		return;
395 
396 	mlx5_sf_dev_destroy_active_works(table);
397 
398 	/* Now that event handler is not running, it is safe to destroy
399 	 * the sf device without race.
400 	 */
401 	mlx5_sf_dev_destroy_all(table);
402 
403 	WARN_ON(!xa_empty(&table->devices));
404 	kfree(table);
405 	dev->priv.sf_dev_table = NULL;
406 }
407