]> Git Repo - linux.git/blob - drivers/net/dsa/mv88e6xxx/devlink.c
net: wan: Add framer framework support
[linux.git] / drivers / net / dsa / mv88e6xxx / devlink.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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         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;
414 out:
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  */
435 struct 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
444 static 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  */
520 struct mv88e6xxx_devlink_stu_entry {
521         u16 sid;
522         u16 vid;
523         u16 data[3];
524         u16 resvd;
525 };
526
527 static 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
585 static 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
623 static 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;
647 out:
648         mv88e6xxx_reg_unlock(chip);
649
650         return err;
651 }
652
653 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
654         .id = MV88E6XXX_REGION_GLOBAL1,
655 };
656
657 static 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
664 static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
665         .id = MV88E6XXX_REGION_GLOBAL2,
666 };
667
668 static 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
675 static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
676         .name = "atu",
677         .snapshot = mv88e6xxx_region_atu_snapshot,
678         .destructor = kfree,
679 };
680
681 static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
682         .name = "vtu",
683         .snapshot = mv88e6xxx_region_vtu_snapshot,
684         .destructor = kfree,
685 };
686
687 static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
688         .name = "stu",
689         .snapshot = mv88e6xxx_region_stu_snapshot,
690         .destructor = kfree,
691 };
692
693 static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
694         .name = "pvt",
695         .snapshot = mv88e6xxx_region_pvt_snapshot,
696         .destructor = kfree,
697 };
698
699 static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
700         .name = "port",
701         .snapshot = mv88e6xxx_region_port_snapshot,
702         .destructor = kfree,
703 };
704
705 struct mv88e6xxx_region {
706         struct devlink_region_ops *ops;
707         u64 size;
708
709         bool (*cond)(struct mv88e6xxx_chip *chip);
710 };
711
712 static 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
740 void 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
749 void 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
756 int 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
773 int 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
812 out:
813         for (j = 0; j < i; j++)
814                 dsa_devlink_region_destroy(chip->regions[j]);
815
816         return PTR_ERR(region);
817 }
818
819 int 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 }
This page took 0.080416 seconds and 4 git commands to generate.