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