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 	unsigned int max_sfs;
18 	phys_addr_t base_address;
19 	u64 sf_bar_length;
20 	struct notifier_block nb;
21 	struct mlx5_core_dev *dev;
22 };
23 
24 static bool mlx5_sf_dev_supported(const struct mlx5_core_dev *dev)
25 {
26 	return MLX5_CAP_GEN(dev, sf) && mlx5_vhca_event_supported(dev);
27 }
28 
29 bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev)
30 {
31 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
32 
33 	if (!mlx5_sf_dev_supported(dev))
34 		return false;
35 
36 	return !xa_empty(&table->devices);
37 }
38 
39 static ssize_t sfnum_show(struct device *dev, struct device_attribute *attr, char *buf)
40 {
41 	struct auxiliary_device *adev = container_of(dev, struct auxiliary_device, dev);
42 	struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
43 
44 	return sysfs_emit(buf, "%u\n", sf_dev->sfnum);
45 }
46 static DEVICE_ATTR_RO(sfnum);
47 
48 static struct attribute *sf_device_attrs[] = {
49 	&dev_attr_sfnum.attr,
50 	NULL,
51 };
52 
53 static const struct attribute_group sf_attr_group = {
54 	.attrs = sf_device_attrs,
55 };
56 
57 static const struct attribute_group *sf_attr_groups[2] = {
58 	&sf_attr_group,
59 	NULL
60 };
61 
62 static void mlx5_sf_dev_release(struct device *device)
63 {
64 	struct auxiliary_device *adev = container_of(device, struct auxiliary_device, dev);
65 	struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
66 
67 	mlx5_adev_idx_free(adev->id);
68 	kfree(sf_dev);
69 }
70 
71 static void mlx5_sf_dev_remove(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev)
72 {
73 	int id;
74 
75 	id = sf_dev->adev.id;
76 	trace_mlx5_sf_dev_del(dev, sf_dev, id);
77 
78 	auxiliary_device_delete(&sf_dev->adev);
79 	auxiliary_device_uninit(&sf_dev->adev);
80 }
81 
82 static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u16 fn_id, u32 sfnum)
83 {
84 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
85 	struct mlx5_sf_dev *sf_dev;
86 	struct pci_dev *pdev;
87 	int err;
88 	int id;
89 
90 	id = mlx5_adev_idx_alloc();
91 	if (id < 0) {
92 		err = id;
93 		goto add_err;
94 	}
95 
96 	sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL);
97 	if (!sf_dev) {
98 		mlx5_adev_idx_free(id);
99 		err = -ENOMEM;
100 		goto add_err;
101 	}
102 	pdev = dev->pdev;
103 	sf_dev->adev.id = id;
104 	sf_dev->adev.name = MLX5_SF_DEV_ID_NAME;
105 	sf_dev->adev.dev.release = mlx5_sf_dev_release;
106 	sf_dev->adev.dev.parent = &pdev->dev;
107 	sf_dev->adev.dev.groups = sf_attr_groups;
108 	sf_dev->sfnum = sfnum;
109 	sf_dev->parent_mdev = dev;
110 	sf_dev->fn_id = fn_id;
111 
112 	if (!table->max_sfs) {
113 		mlx5_adev_idx_free(id);
114 		kfree(sf_dev);
115 		err = -EOPNOTSUPP;
116 		goto add_err;
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 		put_device(&sf_dev->adev.dev);
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(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 
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(dev, sf_dev);
153 }
154 
155 static int
156 mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_code, void *data)
157 {
158 	struct mlx5_sf_dev_table *table = container_of(nb, struct mlx5_sf_dev_table, nb);
159 	const struct mlx5_vhca_state_event *event = data;
160 	struct mlx5_sf_dev *sf_dev;
161 	u16 max_functions;
162 	u16 sf_index;
163 	u16 base_id;
164 
165 	max_functions = mlx5_sf_max_functions(table->dev);
166 	if (!max_functions)
167 		return 0;
168 
169 	base_id = MLX5_CAP_GEN(table->dev, sf_base_id);
170 	if (event->function_id < base_id || event->function_id >= (base_id + max_functions))
171 		return 0;
172 
173 	sf_index = event->function_id - base_id;
174 	sf_dev = xa_load(&table->devices, sf_index);
175 	switch (event->new_vhca_state) {
176 	case MLX5_VHCA_STATE_INVALID:
177 	case MLX5_VHCA_STATE_ALLOCATED:
178 		if (sf_dev)
179 			mlx5_sf_dev_del(table->dev, sf_dev, sf_index);
180 		break;
181 	case MLX5_VHCA_STATE_TEARDOWN_REQUEST:
182 		if (sf_dev)
183 			mlx5_sf_dev_del(table->dev, sf_dev, sf_index);
184 		else
185 			mlx5_core_err(table->dev,
186 				      "SF DEV: teardown state for invalid dev index=%d fn_id=0x%x\n",
187 				      sf_index, event->sw_function_id);
188 		break;
189 	case MLX5_VHCA_STATE_ACTIVE:
190 		if (!sf_dev)
191 			mlx5_sf_dev_add(table->dev, sf_index, event->function_id,
192 					event->sw_function_id);
193 		break;
194 	default:
195 		break;
196 	}
197 	return 0;
198 }
199 
200 static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table)
201 {
202 	struct mlx5_core_dev *dev = table->dev;
203 	u16 max_functions;
204 	u16 function_id;
205 	int err = 0;
206 	int i;
207 
208 	max_functions = mlx5_sf_max_functions(dev);
209 	function_id = MLX5_CAP_GEN(dev, sf_base_id);
210 	/* Arm the vhca context as the vhca event notifier */
211 	for (i = 0; i < max_functions; i++) {
212 		err = mlx5_vhca_event_arm(dev, function_id);
213 		if (err)
214 			return err;
215 
216 		function_id++;
217 	}
218 	return 0;
219 }
220 
221 void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
222 {
223 	struct mlx5_sf_dev_table *table;
224 	unsigned int max_sfs;
225 	int err;
226 
227 	if (!mlx5_sf_dev_supported(dev) || !mlx5_vhca_event_supported(dev))
228 		return;
229 
230 	table = kzalloc(sizeof(*table), GFP_KERNEL);
231 	if (!table) {
232 		err = -ENOMEM;
233 		goto table_err;
234 	}
235 
236 	table->nb.notifier_call = mlx5_sf_dev_state_change_handler;
237 	table->dev = dev;
238 	if (MLX5_CAP_GEN(dev, max_num_sf))
239 		max_sfs = MLX5_CAP_GEN(dev, max_num_sf);
240 	else
241 		max_sfs = 1 << MLX5_CAP_GEN(dev, log_max_sf);
242 	table->sf_bar_length = 1 << (MLX5_CAP_GEN(dev, log_min_sf_size) + 12);
243 	table->base_address = pci_resource_start(dev->pdev, 2);
244 	table->max_sfs = max_sfs;
245 	xa_init(&table->devices);
246 	dev->priv.sf_dev_table = table;
247 
248 	err = mlx5_vhca_event_notifier_register(dev, &table->nb);
249 	if (err)
250 		goto vhca_err;
251 	err = mlx5_sf_dev_vhca_arm_all(table);
252 	if (err)
253 		goto arm_err;
254 	mlx5_core_dbg(dev, "SF DEV: max sf devices=%d\n", max_sfs);
255 	return;
256 
257 arm_err:
258 	mlx5_vhca_event_notifier_unregister(dev, &table->nb);
259 vhca_err:
260 	table->max_sfs = 0;
261 	kfree(table);
262 	dev->priv.sf_dev_table = NULL;
263 table_err:
264 	mlx5_core_err(dev, "SF DEV table create err = %d\n", err);
265 }
266 
267 static void mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table *table)
268 {
269 	struct mlx5_sf_dev *sf_dev;
270 	unsigned long index;
271 
272 	xa_for_each(&table->devices, index, sf_dev) {
273 		xa_erase(&table->devices, index);
274 		mlx5_sf_dev_remove(table->dev, sf_dev);
275 	}
276 }
277 
278 void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev)
279 {
280 	struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
281 
282 	if (!table)
283 		return;
284 
285 	mlx5_vhca_event_notifier_unregister(dev, &table->nb);
286 
287 	/* Now that event handler is not running, it is safe to destroy
288 	 * the sf device without race.
289 	 */
290 	mlx5_sf_dev_destroy_all(table);
291 
292 	WARN_ON(!xa_empty(&table->devices));
293 	kfree(table);
294 	dev->priv.sf_dev_table = NULL;
295 }
296