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
10static 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
18static 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
26enum mv88e6xxx_devlink_param_id {
27	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
28	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
29};
30
31int 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
53int 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
75static 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
81int 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
87void 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
93enum 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
101static 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
130unlock:
131	mv88e6xxx_reg_unlock(chip);
132
133	return occupancy;
134}
135
136static 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
144static 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
152static 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
160static 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
168static 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
176int 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
259out:
260	dsa_devlink_resources_unregister(ds);
261	return err;
262}
263
264static 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;
298out:
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
309struct 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
319static 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
371static 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	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
378	struct mv88e6xxx_devlink_atu_entry *table;
379	struct mv88e6xxx_chip *chip = ds->priv;
380	int fid = -1, count, err;
381
382	table = kmalloc_array(mv88e6xxx_num_databases(chip),
383			      sizeof(struct mv88e6xxx_devlink_atu_entry),
384			      GFP_KERNEL);
385	if (!table)
386		return -ENOMEM;
387
388	memset(table, 0, mv88e6xxx_num_databases(chip) *
389	       sizeof(struct mv88e6xxx_devlink_atu_entry));
390
391	count = 0;
392
393	mv88e6xxx_reg_lock(chip);
394
395	err = mv88e6xxx_fid_map(chip, fid_bitmap);
396	if (err) {
397		kfree(table);
398		goto out;
399	}
400
401	while (1) {
402		fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
403		if (fid == MV88E6XXX_N_FID)
404			break;
405
406		err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
407							 &count);
408		if (err) {
409			kfree(table);
410			goto out;
411		}
412	}
413	*data = (u8 *)table;
414out:
415	mv88e6xxx_reg_unlock(chip);
416
417	return err;
418}
419
420/**
421 * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
422 * @fid:   Global1/2:   FID and VLAN policy.
423 * @sid:   Global1/3:   SID, unknown filters and learning.
424 * @op:    Global1/5:   FID (old chipsets).
425 * @vid:   Global1/6:   VID, valid, and page.
426 * @data:  Global1/7-9: Membership data and priority override.
427 * @resvd: Reserved. Also happens to align the size to 16B.
428 *
429 * The VTU entry format varies between chipset generations, the
430 * descriptions above represent the superset of all possible
431 * information, not all fields are valid on all devices. Since this is
432 * a low-level debug interface, copy all data verbatim and defer
433 * parsing to the consumer.
434 */
435struct mv88e6xxx_devlink_vtu_entry {
436	u16 fid;
437	u16 sid;
438	u16 op;
439	u16 vid;
440	u16 data[3];
441	u16 resvd;
442};
443
444static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
445					 const struct devlink_region_ops *ops,
446					 struct netlink_ext_ack *extack,
447					 u8 **data)
448{
449	struct mv88e6xxx_devlink_vtu_entry *table, *entry;
450	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
451	struct mv88e6xxx_chip *chip = ds->priv;
452	struct mv88e6xxx_vtu_entry vlan;
453	int err;
454
455	table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
456			sizeof(struct mv88e6xxx_devlink_vtu_entry),
457			GFP_KERNEL);
458	if (!table)
459		return -ENOMEM;
460
461	entry = table;
462	vlan.vid = mv88e6xxx_max_vid(chip);
463	vlan.valid = false;
464
465	mv88e6xxx_reg_lock(chip);
466
467	do {
468		err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
469		if (err)
470			break;
471
472		if (!vlan.valid)
473			break;
474
475		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
476						&entry->fid);
477		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
478						&entry->sid);
479		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
480						&entry->op);
481		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
482						&entry->vid);
483		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
484						&entry->data[0]);
485		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
486						&entry->data[1]);
487		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
488						&entry->data[2]);
489		if (err)
490			break;
491
492		entry++;
493	} while (vlan.vid < mv88e6xxx_max_vid(chip));
494
495	mv88e6xxx_reg_unlock(chip);
496
497	if (err) {
498		kfree(table);
499		return err;
500	}
501
502	*data = (u8 *)table;
503	return 0;
504}
505
506/**
507 * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
508 * @sid:   Global1/3:   SID, unknown filters and learning.
509 * @vid:   Global1/6:   Valid bit.
510 * @data:  Global1/7-9: Membership data and priority override.
511 * @resvd: Reserved. In case we forgot something.
512 *
513 * The STU entry format varies between chipset generations. Peridot
514 * and Amethyst packs the STU data into Global1/7-8. Older silicon
515 * spreads the information across all three VTU data registers -
516 * inheriting the layout of even older hardware that had no STU at
517 * all. Since this is a low-level debug interface, copy all data
518 * verbatim and defer parsing to the consumer.
519 */
520struct mv88e6xxx_devlink_stu_entry {
521	u16 sid;
522	u16 vid;
523	u16 data[3];
524	u16 resvd;
525};
526
527static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
528					 const struct devlink_region_ops *ops,
529					 struct netlink_ext_ack *extack,
530					 u8 **data)
531{
532	struct mv88e6xxx_devlink_stu_entry *table, *entry;
533	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
534	struct mv88e6xxx_chip *chip = ds->priv;
535	struct mv88e6xxx_stu_entry stu;
536	int err;
537
538	table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
539			sizeof(struct mv88e6xxx_devlink_stu_entry),
540			GFP_KERNEL);
541	if (!table)
542		return -ENOMEM;
543
544	entry = table;
545	stu.sid = mv88e6xxx_max_sid(chip);
546	stu.valid = false;
547
548	mv88e6xxx_reg_lock(chip);
549
550	do {
551		err = mv88e6xxx_g1_stu_getnext(chip, &stu);
552		if (err)
553			break;
554
555		if (!stu.valid)
556			break;
557
558		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
559						&entry->sid);
560		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
561						&entry->vid);
562		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
563						&entry->data[0]);
564		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
565						&entry->data[1]);
566		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
567						&entry->data[2]);
568		if (err)
569			break;
570
571		entry++;
572	} while (stu.sid < mv88e6xxx_max_sid(chip));
573
574	mv88e6xxx_reg_unlock(chip);
575
576	if (err) {
577		kfree(table);
578		return err;
579	}
580
581	*data = (u8 *)table;
582	return 0;
583}
584
585static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
586					 const struct devlink_region_ops *ops,
587					 struct netlink_ext_ack *extack,
588					 u8 **data)
589{
590	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
591	struct mv88e6xxx_chip *chip = ds->priv;
592	int dev, port, err;
593	u16 *pvt, *cur;
594
595	pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
596	if (!pvt)
597		return -ENOMEM;
598
599	mv88e6xxx_reg_lock(chip);
600
601	cur = pvt;
602	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
603		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
604			err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
605			if (err)
606				break;
607
608			cur++;
609		}
610	}
611
612	mv88e6xxx_reg_unlock(chip);
613
614	if (err) {
615		kfree(pvt);
616		return err;
617	}
618
619	*data = (u8 *)pvt;
620	return 0;
621}
622
623static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
624					  const struct devlink_port_region_ops *ops,
625					  struct netlink_ext_ack *extack,
626					  u8 **data)
627{
628	struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
629	int port = dsa_devlink_port_to_port(devlink_port);
630	struct mv88e6xxx_chip *chip = ds->priv;
631	u16 *registers;
632	int i, err;
633
634	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
635	if (!registers)
636		return -ENOMEM;
637
638	mv88e6xxx_reg_lock(chip);
639	for (i = 0; i < 32; i++) {
640		err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
641		if (err) {
642			kfree(registers);
643			goto out;
644		}
645	}
646	*data = (u8 *)registers;
647out:
648	mv88e6xxx_reg_unlock(chip);
649
650	return err;
651}
652
653static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
654	.id = MV88E6XXX_REGION_GLOBAL1,
655};
656
657static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
658	.name = "global1",
659	.snapshot = mv88e6xxx_region_global_snapshot,
660	.destructor = kfree,
661	.priv = &mv88e6xxx_region_global1_priv,
662};
663
664static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
665	.id = MV88E6XXX_REGION_GLOBAL2,
666};
667
668static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
669	.name = "global2",
670	.snapshot = mv88e6xxx_region_global_snapshot,
671	.destructor = kfree,
672	.priv = &mv88e6xxx_region_global2_priv,
673};
674
675static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
676	.name = "atu",
677	.snapshot = mv88e6xxx_region_atu_snapshot,
678	.destructor = kfree,
679};
680
681static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
682	.name = "vtu",
683	.snapshot = mv88e6xxx_region_vtu_snapshot,
684	.destructor = kfree,
685};
686
687static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
688	.name = "stu",
689	.snapshot = mv88e6xxx_region_stu_snapshot,
690	.destructor = kfree,
691};
692
693static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
694	.name = "pvt",
695	.snapshot = mv88e6xxx_region_pvt_snapshot,
696	.destructor = kfree,
697};
698
699static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
700	.name = "port",
701	.snapshot = mv88e6xxx_region_port_snapshot,
702	.destructor = kfree,
703};
704
705struct mv88e6xxx_region {
706	struct devlink_region_ops *ops;
707	u64 size;
708
709	bool (*cond)(struct mv88e6xxx_chip *chip);
710};
711
712static struct mv88e6xxx_region mv88e6xxx_regions[] = {
713	[MV88E6XXX_REGION_GLOBAL1] = {
714		.ops = &mv88e6xxx_region_global1_ops,
715		.size = 32 * sizeof(u16)
716	},
717	[MV88E6XXX_REGION_GLOBAL2] = {
718		.ops = &mv88e6xxx_region_global2_ops,
719		.size = 32 * sizeof(u16) },
720	[MV88E6XXX_REGION_ATU] = {
721		.ops = &mv88e6xxx_region_atu_ops
722	  /* calculated at runtime */
723	},
724	[MV88E6XXX_REGION_VTU] = {
725		.ops = &mv88e6xxx_region_vtu_ops
726	  /* calculated at runtime */
727	},
728	[MV88E6XXX_REGION_STU] = {
729		.ops = &mv88e6xxx_region_stu_ops,
730		.cond = mv88e6xxx_has_stu,
731	  /* calculated at runtime */
732	},
733	[MV88E6XXX_REGION_PVT] = {
734		.ops = &mv88e6xxx_region_pvt_ops,
735		.size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
736		.cond = mv88e6xxx_has_pvt,
737	},
738};
739
740void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
741{
742	struct mv88e6xxx_chip *chip = ds->priv;
743	int i;
744
745	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
746		dsa_devlink_region_destroy(chip->regions[i]);
747}
748
749void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
750{
751	struct mv88e6xxx_chip *chip = ds->priv;
752
753	dsa_devlink_region_destroy(chip->ports[port].region);
754}
755
756int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
757{
758	struct mv88e6xxx_chip *chip = ds->priv;
759	struct devlink_region *region;
760
761	region = dsa_devlink_port_region_create(ds,
762						port,
763						&mv88e6xxx_region_port_ops, 1,
764						32 * sizeof(u16));
765	if (IS_ERR(region))
766		return PTR_ERR(region);
767
768	chip->ports[port].region = region;
769
770	return 0;
771}
772
773int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
774{
775	bool (*cond)(struct mv88e6xxx_chip *chip);
776	struct mv88e6xxx_chip *chip = ds->priv;
777	struct devlink_region_ops *ops;
778	struct devlink_region *region;
779	u64 size;
780	int i, j;
781
782	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
783		ops = mv88e6xxx_regions[i].ops;
784		size = mv88e6xxx_regions[i].size;
785		cond = mv88e6xxx_regions[i].cond;
786
787		if (cond && !cond(chip))
788			continue;
789
790		switch (i) {
791		case MV88E6XXX_REGION_ATU:
792			size = mv88e6xxx_num_databases(chip) *
793				sizeof(struct mv88e6xxx_devlink_atu_entry);
794			break;
795		case MV88E6XXX_REGION_VTU:
796			size = (mv88e6xxx_max_vid(chip) + 1) *
797				sizeof(struct mv88e6xxx_devlink_vtu_entry);
798			break;
799		case MV88E6XXX_REGION_STU:
800			size = (mv88e6xxx_max_sid(chip) + 1) *
801				sizeof(struct mv88e6xxx_devlink_stu_entry);
802			break;
803		}
804
805		region = dsa_devlink_region_create(ds, ops, 1, size);
806		if (IS_ERR(region))
807			goto out;
808		chip->regions[i] = region;
809	}
810	return 0;
811
812out:
813	for (j = 0; j < i; j++)
814		dsa_devlink_region_destroy(chip->regions[j]);
815
816	return PTR_ERR(region);
817}
818
819int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
820			       struct devlink_info_req *req,
821			       struct netlink_ext_ack *extack)
822{
823	struct mv88e6xxx_chip *chip = ds->priv;
824
825	return devlink_info_version_fixed_put(req,
826					      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
827					      chip->info->name);
828}
829