xref: /linux/drivers/net/dsa/mv88e6xxx/devlink.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <net/dsa.h>
3 
4 #include "chip.h"
5 #include "devlink.h"
6 #include "global1.h"
7 #include "global2.h"
8 #include "port.h"
9 
mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip * chip,u8 * hash)10 static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
11 {
12 	if (chip->info->ops->atu_get_hash)
13 		return chip->info->ops->atu_get_hash(chip, hash);
14 
15 	return -EOPNOTSUPP;
16 }
17 
mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip * chip,u8 hash)18 static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
19 {
20 	if (chip->info->ops->atu_set_hash)
21 		return chip->info->ops->atu_set_hash(chip, hash);
22 
23 	return -EOPNOTSUPP;
24 }
25 
26 enum mv88e6xxx_devlink_param_id {
27 	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
28 	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
29 };
30 
mv88e6xxx_devlink_param_get(struct dsa_switch * ds,u32 id,struct devlink_param_gset_ctx * ctx)31 int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
32 				struct devlink_param_gset_ctx *ctx)
33 {
34 	struct mv88e6xxx_chip *chip = ds->priv;
35 	int err;
36 
37 	mv88e6xxx_reg_lock(chip);
38 
39 	switch (id) {
40 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
41 		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
42 		break;
43 	default:
44 		err = -EOPNOTSUPP;
45 		break;
46 	}
47 
48 	mv88e6xxx_reg_unlock(chip);
49 
50 	return err;
51 }
52 
mv88e6xxx_devlink_param_set(struct dsa_switch * ds,u32 id,struct devlink_param_gset_ctx * ctx)53 int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
54 				struct devlink_param_gset_ctx *ctx)
55 {
56 	struct mv88e6xxx_chip *chip = ds->priv;
57 	int err;
58 
59 	mv88e6xxx_reg_lock(chip);
60 
61 	switch (id) {
62 	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
63 		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
64 		break;
65 	default:
66 		err = -EOPNOTSUPP;
67 		break;
68 	}
69 
70 	mv88e6xxx_reg_unlock(chip);
71 
72 	return err;
73 }
74 
75 static const struct devlink_param mv88e6xxx_devlink_params[] = {
76 	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
77 				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
78 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
79 };
80 
mv88e6xxx_setup_devlink_params(struct dsa_switch * ds)81 int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
82 {
83 	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
84 					   ARRAY_SIZE(mv88e6xxx_devlink_params));
85 }
86 
mv88e6xxx_teardown_devlink_params(struct dsa_switch * ds)87 void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
88 {
89 	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
90 				      ARRAY_SIZE(mv88e6xxx_devlink_params));
91 }
92 
93 enum mv88e6xxx_devlink_resource_id {
94 	MV88E6XXX_RESOURCE_ID_ATU,
95 	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
96 	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
97 	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
98 	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
99 };
100 
mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip * chip,u16 bin)101 static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
102 					 u16 bin)
103 {
104 	u16 occupancy = 0;
105 	int err;
106 
107 	mv88e6xxx_reg_lock(chip);
108 
109 	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
110 					 bin);
111 	if (err) {
112 		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
113 		goto unlock;
114 	}
115 
116 	err = mv88e6xxx_g1_atu_get_next(chip, 0);
117 	if (err) {
118 		dev_err(chip->dev, "failed to perform ATU get next\n");
119 		goto unlock;
120 	}
121 
122 	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
123 	if (err) {
124 		dev_err(chip->dev, "failed to get ATU stats\n");
125 		goto unlock;
126 	}
127 
128 	occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
129 
130 unlock:
131 	mv88e6xxx_reg_unlock(chip);
132 
133 	return occupancy;
134 }
135 
mv88e6xxx_devlink_atu_bin_0_get(void * priv)136 static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
137 {
138 	struct mv88e6xxx_chip *chip = priv;
139 
140 	return mv88e6xxx_devlink_atu_bin_get(chip,
141 					     MV88E6XXX_G2_ATU_STATS_BIN_0);
142 }
143 
mv88e6xxx_devlink_atu_bin_1_get(void * priv)144 static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
145 {
146 	struct mv88e6xxx_chip *chip = priv;
147 
148 	return mv88e6xxx_devlink_atu_bin_get(chip,
149 					     MV88E6XXX_G2_ATU_STATS_BIN_1);
150 }
151 
mv88e6xxx_devlink_atu_bin_2_get(void * priv)152 static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
153 {
154 	struct mv88e6xxx_chip *chip = priv;
155 
156 	return mv88e6xxx_devlink_atu_bin_get(chip,
157 					     MV88E6XXX_G2_ATU_STATS_BIN_2);
158 }
159 
mv88e6xxx_devlink_atu_bin_3_get(void * priv)160 static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
161 {
162 	struct mv88e6xxx_chip *chip = priv;
163 
164 	return mv88e6xxx_devlink_atu_bin_get(chip,
165 					     MV88E6XXX_G2_ATU_STATS_BIN_3);
166 }
167 
mv88e6xxx_devlink_atu_get(void * priv)168 static u64 mv88e6xxx_devlink_atu_get(void *priv)
169 {
170 	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
171 		mv88e6xxx_devlink_atu_bin_1_get(priv) +
172 		mv88e6xxx_devlink_atu_bin_2_get(priv) +
173 		mv88e6xxx_devlink_atu_bin_3_get(priv);
174 }
175 
mv88e6xxx_setup_devlink_resources(struct dsa_switch * ds)176 int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
177 {
178 	struct devlink_resource_size_params size_params;
179 	struct mv88e6xxx_chip *chip = ds->priv;
180 	int err;
181 
182 	devlink_resource_size_params_init(&size_params,
183 					  mv88e6xxx_num_macs(chip),
184 					  mv88e6xxx_num_macs(chip),
185 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
186 
187 	err = dsa_devlink_resource_register(ds, "ATU",
188 					    mv88e6xxx_num_macs(chip),
189 					    MV88E6XXX_RESOURCE_ID_ATU,
190 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
191 					    &size_params);
192 	if (err)
193 		goto out;
194 
195 	devlink_resource_size_params_init(&size_params,
196 					  mv88e6xxx_num_macs(chip) / 4,
197 					  mv88e6xxx_num_macs(chip) / 4,
198 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
199 
200 	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
201 					    mv88e6xxx_num_macs(chip) / 4,
202 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
203 					    MV88E6XXX_RESOURCE_ID_ATU,
204 					    &size_params);
205 	if (err)
206 		goto out;
207 
208 	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
209 					    mv88e6xxx_num_macs(chip) / 4,
210 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
211 					    MV88E6XXX_RESOURCE_ID_ATU,
212 					    &size_params);
213 	if (err)
214 		goto out;
215 
216 	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
217 					    mv88e6xxx_num_macs(chip) / 4,
218 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
219 					    MV88E6XXX_RESOURCE_ID_ATU,
220 					    &size_params);
221 	if (err)
222 		goto out;
223 
224 	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
225 					    mv88e6xxx_num_macs(chip) / 4,
226 					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
227 					    MV88E6XXX_RESOURCE_ID_ATU,
228 					    &size_params);
229 	if (err)
230 		goto out;
231 
232 	dsa_devlink_resource_occ_get_register(ds,
233 					      MV88E6XXX_RESOURCE_ID_ATU,
234 					      mv88e6xxx_devlink_atu_get,
235 					      chip);
236 
237 	dsa_devlink_resource_occ_get_register(ds,
238 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
239 					      mv88e6xxx_devlink_atu_bin_0_get,
240 					      chip);
241 
242 	dsa_devlink_resource_occ_get_register(ds,
243 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
244 					      mv88e6xxx_devlink_atu_bin_1_get,
245 					      chip);
246 
247 	dsa_devlink_resource_occ_get_register(ds,
248 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
249 					      mv88e6xxx_devlink_atu_bin_2_get,
250 					      chip);
251 
252 	dsa_devlink_resource_occ_get_register(ds,
253 					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
254 					      mv88e6xxx_devlink_atu_bin_3_get,
255 					      chip);
256 
257 	return 0;
258 
259 out:
260 	dsa_devlink_resources_unregister(ds);
261 	return err;
262 }
263 
mv88e6xxx_region_global_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)264 static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
265 					    const struct devlink_region_ops *ops,
266 					    struct netlink_ext_ack *extack,
267 					    u8 **data)
268 {
269 	struct mv88e6xxx_region_priv *region_priv = ops->priv;
270 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
271 	struct mv88e6xxx_chip *chip = ds->priv;
272 	u16 *registers;
273 	int i, err;
274 
275 	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
276 	if (!registers)
277 		return -ENOMEM;
278 
279 	mv88e6xxx_reg_lock(chip);
280 	for (i = 0; i < 32; i++) {
281 		switch (region_priv->id) {
282 		case MV88E6XXX_REGION_GLOBAL1:
283 			err = mv88e6xxx_g1_read(chip, i, &registers[i]);
284 			break;
285 		case MV88E6XXX_REGION_GLOBAL2:
286 			err = mv88e6xxx_g2_read(chip, i, &registers[i]);
287 			break;
288 		default:
289 			err = -EOPNOTSUPP;
290 		}
291 
292 		if (err) {
293 			kfree(registers);
294 			goto out;
295 		}
296 	}
297 	*data = (u8 *)registers;
298 out:
299 	mv88e6xxx_reg_unlock(chip);
300 
301 	return err;
302 }
303 
304 /* The ATU entry varies between mv88e6xxx chipset generations. Define
305  * a generic format which covers all the current and hopefully future
306  * mv88e6xxx generations
307  */
308 
309 struct mv88e6xxx_devlink_atu_entry {
310 	/* The FID is scattered over multiple registers. */
311 	u16 fid;
312 	u16 atu_op;
313 	u16 atu_data;
314 	u16 atu_01;
315 	u16 atu_23;
316 	u16 atu_45;
317 };
318 
mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip * chip,int fid,struct mv88e6xxx_devlink_atu_entry * table,int * count)319 static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
320 					     int fid,
321 					     struct mv88e6xxx_devlink_atu_entry *table,
322 					     int *count)
323 {
324 	u16 atu_op, atu_data, atu_01, atu_23, atu_45;
325 	struct mv88e6xxx_atu_entry addr;
326 	int err;
327 
328 	addr.state = 0;
329 	eth_broadcast_addr(addr.mac);
330 
331 	do {
332 		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
333 		if (err)
334 			return err;
335 
336 		if (!addr.state)
337 			break;
338 
339 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
340 		if (err)
341 			return err;
342 
343 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
344 		if (err)
345 			return err;
346 
347 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
348 		if (err)
349 			return err;
350 
351 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
352 		if (err)
353 			return err;
354 
355 		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
356 		if (err)
357 			return err;
358 
359 		table[*count].fid = fid;
360 		table[*count].atu_op = atu_op;
361 		table[*count].atu_data = atu_data;
362 		table[*count].atu_01 = atu_01;
363 		table[*count].atu_23 = atu_23;
364 		table[*count].atu_45 = atu_45;
365 		(*count)++;
366 	} while (!is_broadcast_ether_addr(addr.mac));
367 
368 	return 0;
369 }
370 
mv88e6xxx_region_atu_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)371 static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
372 					 const struct devlink_region_ops *ops,
373 					 struct netlink_ext_ack *extack,
374 					 u8 **data)
375 {
376 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
377 	struct mv88e6xxx_devlink_atu_entry *table;
378 	struct mv88e6xxx_chip *chip = ds->priv;
379 	int fid = -1, err = 0, count = 0;
380 
381 	table = kcalloc(mv88e6xxx_num_databases(chip),
382 			sizeof(struct mv88e6xxx_devlink_atu_entry),
383 			GFP_KERNEL);
384 	if (!table)
385 		return -ENOMEM;
386 
387 	mv88e6xxx_reg_lock(chip);
388 
389 	while (1) {
390 		fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1);
391 		if (fid == MV88E6XXX_N_FID)
392 			break;
393 
394 		err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
395 							 &count);
396 		if (err) {
397 			kfree(table);
398 			goto out;
399 		}
400 	}
401 	*data = (u8 *)table;
402 out:
403 	mv88e6xxx_reg_unlock(chip);
404 
405 	return err;
406 }
407 
408 /**
409  * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
410  * @fid:   Global1/2:   FID and VLAN policy.
411  * @sid:   Global1/3:   SID, unknown filters and learning.
412  * @op:    Global1/5:   FID (old chipsets).
413  * @vid:   Global1/6:   VID, valid, and page.
414  * @data:  Global1/7-9: Membership data and priority override.
415  * @resvd: Reserved. Also happens to align the size to 16B.
416  *
417  * The VTU entry format varies between chipset generations, the
418  * descriptions above represent the superset of all possible
419  * information, not all fields are valid on all devices. Since this is
420  * a low-level debug interface, copy all data verbatim and defer
421  * parsing to the consumer.
422  */
423 struct mv88e6xxx_devlink_vtu_entry {
424 	u16 fid;
425 	u16 sid;
426 	u16 op;
427 	u16 vid;
428 	u16 data[3];
429 	u16 resvd;
430 };
431 
mv88e6xxx_region_vtu_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)432 static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
433 					 const struct devlink_region_ops *ops,
434 					 struct netlink_ext_ack *extack,
435 					 u8 **data)
436 {
437 	struct mv88e6xxx_devlink_vtu_entry *table, *entry;
438 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
439 	struct mv88e6xxx_chip *chip = ds->priv;
440 	struct mv88e6xxx_vtu_entry vlan;
441 	int err;
442 
443 	table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
444 			sizeof(struct mv88e6xxx_devlink_vtu_entry),
445 			GFP_KERNEL);
446 	if (!table)
447 		return -ENOMEM;
448 
449 	entry = table;
450 	vlan.vid = mv88e6xxx_max_vid(chip);
451 	vlan.valid = false;
452 
453 	mv88e6xxx_reg_lock(chip);
454 
455 	do {
456 		err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
457 		if (err)
458 			break;
459 
460 		if (!vlan.valid)
461 			break;
462 
463 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
464 						&entry->fid);
465 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
466 						&entry->sid);
467 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
468 						&entry->op);
469 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
470 						&entry->vid);
471 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
472 						&entry->data[0]);
473 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
474 						&entry->data[1]);
475 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
476 						&entry->data[2]);
477 		if (err)
478 			break;
479 
480 		entry++;
481 	} while (vlan.vid < mv88e6xxx_max_vid(chip));
482 
483 	mv88e6xxx_reg_unlock(chip);
484 
485 	if (err) {
486 		kfree(table);
487 		return err;
488 	}
489 
490 	*data = (u8 *)table;
491 	return 0;
492 }
493 
494 /**
495  * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
496  * @sid:   Global1/3:   SID, unknown filters and learning.
497  * @vid:   Global1/6:   Valid bit.
498  * @data:  Global1/7-9: Membership data and priority override.
499  * @resvd: Reserved. In case we forgot something.
500  *
501  * The STU entry format varies between chipset generations. Peridot
502  * and Amethyst packs the STU data into Global1/7-8. Older silicon
503  * spreads the information across all three VTU data registers -
504  * inheriting the layout of even older hardware that had no STU at
505  * all. Since this is a low-level debug interface, copy all data
506  * verbatim and defer parsing to the consumer.
507  */
508 struct mv88e6xxx_devlink_stu_entry {
509 	u16 sid;
510 	u16 vid;
511 	u16 data[3];
512 	u16 resvd;
513 };
514 
mv88e6xxx_region_stu_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)515 static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
516 					 const struct devlink_region_ops *ops,
517 					 struct netlink_ext_ack *extack,
518 					 u8 **data)
519 {
520 	struct mv88e6xxx_devlink_stu_entry *table, *entry;
521 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
522 	struct mv88e6xxx_chip *chip = ds->priv;
523 	struct mv88e6xxx_stu_entry stu;
524 	int err;
525 
526 	table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
527 			sizeof(struct mv88e6xxx_devlink_stu_entry),
528 			GFP_KERNEL);
529 	if (!table)
530 		return -ENOMEM;
531 
532 	entry = table;
533 	stu.sid = mv88e6xxx_max_sid(chip);
534 	stu.valid = false;
535 
536 	mv88e6xxx_reg_lock(chip);
537 
538 	do {
539 		err = mv88e6xxx_g1_stu_getnext(chip, &stu);
540 		if (err)
541 			break;
542 
543 		if (!stu.valid)
544 			break;
545 
546 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
547 						&entry->sid);
548 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
549 						&entry->vid);
550 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
551 						&entry->data[0]);
552 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
553 						&entry->data[1]);
554 		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
555 						&entry->data[2]);
556 		if (err)
557 			break;
558 
559 		entry++;
560 	} while (stu.sid < mv88e6xxx_max_sid(chip));
561 
562 	mv88e6xxx_reg_unlock(chip);
563 
564 	if (err) {
565 		kfree(table);
566 		return err;
567 	}
568 
569 	*data = (u8 *)table;
570 	return 0;
571 }
572 
mv88e6xxx_region_pvt_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)573 static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
574 					 const struct devlink_region_ops *ops,
575 					 struct netlink_ext_ack *extack,
576 					 u8 **data)
577 {
578 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
579 	struct mv88e6xxx_chip *chip = ds->priv;
580 	int dev, port, err;
581 	u16 *pvt, *cur;
582 
583 	pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
584 	if (!pvt)
585 		return -ENOMEM;
586 
587 	mv88e6xxx_reg_lock(chip);
588 
589 	cur = pvt;
590 	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
591 		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
592 			err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
593 			if (err)
594 				break;
595 
596 			cur++;
597 		}
598 	}
599 
600 	mv88e6xxx_reg_unlock(chip);
601 
602 	if (err) {
603 		kfree(pvt);
604 		return err;
605 	}
606 
607 	*data = (u8 *)pvt;
608 	return 0;
609 }
610 
mv88e6xxx_region_port_snapshot(struct devlink_port * devlink_port,const struct devlink_port_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)611 static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
612 					  const struct devlink_port_region_ops *ops,
613 					  struct netlink_ext_ack *extack,
614 					  u8 **data)
615 {
616 	struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
617 	int port = dsa_devlink_port_to_port(devlink_port);
618 	struct mv88e6xxx_chip *chip = ds->priv;
619 	u16 *registers;
620 	int i, err;
621 
622 	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
623 	if (!registers)
624 		return -ENOMEM;
625 
626 	mv88e6xxx_reg_lock(chip);
627 	for (i = 0; i < 32; i++) {
628 		err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
629 		if (err) {
630 			kfree(registers);
631 			goto out;
632 		}
633 	}
634 	*data = (u8 *)registers;
635 out:
636 	mv88e6xxx_reg_unlock(chip);
637 
638 	return err;
639 }
640 
641 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
642 	.id = MV88E6XXX_REGION_GLOBAL1,
643 };
644 
645 static const struct devlink_region_ops mv88e6xxx_region_global1_ops = {
646 	.name = "global1",
647 	.snapshot = mv88e6xxx_region_global_snapshot,
648 	.destructor = kfree,
649 	.priv = &mv88e6xxx_region_global1_priv,
650 };
651 
652 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
653 	.id = MV88E6XXX_REGION_GLOBAL2,
654 };
655 
656 static const struct devlink_region_ops mv88e6xxx_region_global2_ops = {
657 	.name = "global2",
658 	.snapshot = mv88e6xxx_region_global_snapshot,
659 	.destructor = kfree,
660 	.priv = &mv88e6xxx_region_global2_priv,
661 };
662 
663 static const struct devlink_region_ops mv88e6xxx_region_atu_ops = {
664 	.name = "atu",
665 	.snapshot = mv88e6xxx_region_atu_snapshot,
666 	.destructor = kfree,
667 };
668 
669 static const struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
670 	.name = "vtu",
671 	.snapshot = mv88e6xxx_region_vtu_snapshot,
672 	.destructor = kfree,
673 };
674 
675 static const struct devlink_region_ops mv88e6xxx_region_stu_ops = {
676 	.name = "stu",
677 	.snapshot = mv88e6xxx_region_stu_snapshot,
678 	.destructor = kfree,
679 };
680 
681 static const struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
682 	.name = "pvt",
683 	.snapshot = mv88e6xxx_region_pvt_snapshot,
684 	.destructor = kfree,
685 };
686 
687 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
688 	.name = "port",
689 	.snapshot = mv88e6xxx_region_port_snapshot,
690 	.destructor = kfree,
691 };
692 
693 struct mv88e6xxx_region {
694 	const struct devlink_region_ops *ops;
695 	u64 size;
696 
697 	bool (*cond)(struct mv88e6xxx_chip *chip);
698 };
699 
700 static const struct mv88e6xxx_region mv88e6xxx_regions[] = {
701 	[MV88E6XXX_REGION_GLOBAL1] = {
702 		.ops = &mv88e6xxx_region_global1_ops,
703 		.size = 32 * sizeof(u16)
704 	},
705 	[MV88E6XXX_REGION_GLOBAL2] = {
706 		.ops = &mv88e6xxx_region_global2_ops,
707 		.size = 32 * sizeof(u16) },
708 	[MV88E6XXX_REGION_ATU] = {
709 		.ops = &mv88e6xxx_region_atu_ops
710 	  /* calculated at runtime */
711 	},
712 	[MV88E6XXX_REGION_VTU] = {
713 		.ops = &mv88e6xxx_region_vtu_ops
714 	  /* calculated at runtime */
715 	},
716 	[MV88E6XXX_REGION_STU] = {
717 		.ops = &mv88e6xxx_region_stu_ops,
718 		.cond = mv88e6xxx_has_stu,
719 	  /* calculated at runtime */
720 	},
721 	[MV88E6XXX_REGION_PVT] = {
722 		.ops = &mv88e6xxx_region_pvt_ops,
723 		.size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
724 		.cond = mv88e6xxx_has_pvt,
725 	},
726 };
727 
mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch * ds)728 void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
729 {
730 	struct mv88e6xxx_chip *chip = ds->priv;
731 	int i;
732 
733 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
734 		if (chip->regions[i])
735 			dsa_devlink_region_destroy(chip->regions[i]);
736 }
737 
mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch * ds,int port)738 void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
739 {
740 	struct mv88e6xxx_chip *chip = ds->priv;
741 
742 	dsa_devlink_region_destroy(chip->ports[port].region);
743 }
744 
mv88e6xxx_setup_devlink_regions_port(struct dsa_switch * ds,int port)745 int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
746 {
747 	struct mv88e6xxx_chip *chip = ds->priv;
748 	struct devlink_region *region;
749 
750 	region = dsa_devlink_port_region_create(ds,
751 						port,
752 						&mv88e6xxx_region_port_ops, 1,
753 						32 * sizeof(u16));
754 	if (IS_ERR(region))
755 		return PTR_ERR(region);
756 
757 	chip->ports[port].region = region;
758 
759 	return 0;
760 }
761 
mv88e6xxx_setup_devlink_regions_global(struct dsa_switch * ds)762 int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
763 {
764 	bool (*cond)(struct mv88e6xxx_chip *chip);
765 	struct mv88e6xxx_chip *chip = ds->priv;
766 	const struct devlink_region_ops *ops;
767 	struct devlink_region *region;
768 	u64 size;
769 	int i, j;
770 
771 	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
772 		ops = mv88e6xxx_regions[i].ops;
773 		size = mv88e6xxx_regions[i].size;
774 		cond = mv88e6xxx_regions[i].cond;
775 
776 		if (cond && !cond(chip))
777 			continue;
778 
779 		switch (i) {
780 		case MV88E6XXX_REGION_ATU:
781 			size = mv88e6xxx_num_databases(chip) *
782 				sizeof(struct mv88e6xxx_devlink_atu_entry);
783 			break;
784 		case MV88E6XXX_REGION_VTU:
785 			size = (mv88e6xxx_max_vid(chip) + 1) *
786 				sizeof(struct mv88e6xxx_devlink_vtu_entry);
787 			break;
788 		case MV88E6XXX_REGION_STU:
789 			size = (mv88e6xxx_max_sid(chip) + 1) *
790 				sizeof(struct mv88e6xxx_devlink_stu_entry);
791 			break;
792 		}
793 
794 		region = dsa_devlink_region_create(ds, ops, 1, size);
795 		if (IS_ERR(region))
796 			goto out;
797 		chip->regions[i] = region;
798 	}
799 	return 0;
800 
801 out:
802 	for (j = 0; j < i; j++)
803 		dsa_devlink_region_destroy(chip->regions[j]);
804 
805 	return PTR_ERR(region);
806 }
807 
mv88e6xxx_devlink_info_get(struct dsa_switch * ds,struct devlink_info_req * req,struct netlink_ext_ack * extack)808 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
809 			       struct devlink_info_req *req,
810 			       struct netlink_ext_ack *extack)
811 {
812 	struct mv88e6xxx_chip *chip = ds->priv;
813 
814 	return devlink_info_version_fixed_put(req,
815 					      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
816 					      chip->info->name);
817 }
818