1/*
2 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
3 * Permission to use, copy, modify, and/or distribute this software for
4 * any purpose with or without fee is hereby granted, provided that the
5 * above copyright notice and this permission notice appear in all copies.
6 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
7 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
8 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
9 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
10 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
11 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
12 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13 */
14
15
16
17/**
18 * @defgroup garuda_fdb GARUDA_FDB
19 * @{
20 */
21#include "sw.h"
22#include "hsl.h"
23#include "hsl_dev.h"
24#include "hsl_port_prop.h"
25#include "garuda_fdb.h"
26#include "garuda_reg.h"
27
28#define ARL_FLUSH_ALL             1
29#define ARL_LOAD_ENTRY            2
30#define ARL_PURGE_ENTRY           3
31#define ARL_FLUSH_ALL_UNLOCK      4
32#define ARL_FLUSH_PORT_UNICAST    5
33#define ARL_NEXT_ENTRY            6
34#define ARL_FIND_ENTRY            7
35
36#define ARL_FIRST_ENTRY           1001
37#define ARL_FLUSH_PORT_NO_STATIC  1002
38#define ARL_FLUSH_PORT_AND_STATIC 1003
39
40static a_bool_t
41garuda_fdb_is_zeroaddr(fal_mac_addr_t addr)
42{
43    a_uint32_t i;
44
45    for (i = 0; i < 6; i++)
46    {
47        if (addr.uc[i])
48        {
49            return A_FALSE;
50        }
51    }
52
53    return A_TRUE;
54}
55
56static void
57garuda_fdb_fill_addr(fal_mac_addr_t addr, a_uint32_t * reg0, a_uint32_t * reg1)
58{
59    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE0, addr.uc[0], *reg1);
60    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE1, addr.uc[1], *reg1);
61    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE2, addr.uc[2], *reg1);
62    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE3, addr.uc[3], *reg1);
63
64    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE4, addr.uc[4], *reg0);
65    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE5, addr.uc[5], *reg0);
66
67    return;
68}
69
70static sw_error_t
71garuda_atu_sw_to_hw(a_uint32_t dev_id, const fal_fdb_entry_t * entry,
72                    a_uint32_t reg[])
73{
74    a_uint32_t port;
75
76    if (A_FALSE == entry->portmap_en)
77    {
78        if (A_TRUE !=
79                hsl_port_prop_check(dev_id, entry->port.id, HSL_PP_INCL_CPU))
80        {
81            return SW_BAD_PARAM;
82        }
83
84        port = 0x1UL << entry->port.id;
85    }
86    else
87    {
88        if (A_FALSE ==
89                hsl_mports_prop_check(dev_id, entry->port.map, HSL_PP_INCL_CPU))
90        {
91            return SW_BAD_PARAM;
92        }
93
94        port = entry->port.map;
95    }
96
97    if (FAL_MAC_CPY_TO_CPU == entry->dacmd)
98    {
99        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, COPY_TO_CPU, 1, reg[2]);
100    }
101    else if (FAL_MAC_RDT_TO_CPU == entry->dacmd)
102    {
103        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, REDRCT_TO_CPU, 1, reg[2]);
104    }
105    else if (FAL_MAC_FRWRD != entry->dacmd)
106    {
107        return SW_NOT_SUPPORTED;
108    }
109
110    if (FAL_MAC_DROP == entry->sacmd)
111    {
112        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, SA_DROP_EN, 1, reg[2]);
113    }
114    else if (FAL_MAC_FRWRD != entry->sacmd)
115    {
116        return SW_NOT_SUPPORTED;
117    }
118
119    if (A_TRUE == entry->leaky_en)
120    {
121        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, LEAKY_EN, 1, reg[2]);
122    }
123    else
124    {
125        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, LEAKY_EN, 0, reg[2]);
126    }
127
128    if (A_TRUE == entry->static_en)
129    {
130        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_STATUS, 15, reg[2]);
131    }
132    else
133    {
134        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_STATUS, 7, reg[2]);
135    }
136
137    if (A_TRUE == entry->mirror_en)
138    {
139        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, MIRROR_EN, 1, reg[2]);
140    }
141
142    if (A_TRUE == entry->clone_en)
143    {
144        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, CLONE_EN, 1, reg[2]);
145    }
146
147    if (A_TRUE == entry->da_pri_en)
148    {
149        hsl_dev_t *p_dev;
150
151        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_PRI_EN, 1, reg[2]);
152
153        SW_RTN_ON_NULL(p_dev = hsl_dev_ptr_get(dev_id));
154
155        if (entry->da_queue > (p_dev->nr_queue - 1))
156            return SW_BAD_PARAM;
157
158        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_PRI, entry->da_queue, reg[2]);
159    }
160
161    if (A_TRUE == entry->cross_pt_state)
162    {
163        return SW_NOT_SUPPORTED;
164    }
165
166    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, DES_PORT, port, reg[2]);
167    garuda_fdb_fill_addr(entry->addr, &reg[0], &reg[1]);
168
169    return SW_OK;
170}
171
172static void
173garuda_atu_hw_to_sw(const a_uint32_t reg[], fal_fdb_entry_t * entry)
174{
175    a_uint32_t i, data;
176
177    aos_mem_zero(entry, sizeof (fal_fdb_entry_t));
178
179    entry->dacmd = FAL_MAC_FRWRD;
180    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, COPY_TO_CPU, data, reg[2]);
181    if (1 == data)
182    {
183        entry->dacmd = FAL_MAC_CPY_TO_CPU;
184    }
185
186    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, REDRCT_TO_CPU, data, reg[2]);
187    if (1 == data)
188    {
189        entry->dacmd = FAL_MAC_RDT_TO_CPU;
190    }
191
192    entry->sacmd = FAL_MAC_FRWRD;
193    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, SA_DROP_EN, data, reg[2]);
194    if (1 == data)
195    {
196        entry->sacmd = FAL_MAC_DROP;
197    }
198
199    entry->leaky_en = A_FALSE;
200    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, LEAKY_EN, data, reg[2]);
201    if (1 == data)
202    {
203        entry->leaky_en = A_TRUE;
204    }
205
206    entry->static_en = A_FALSE;
207    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_STATUS, data, reg[2]);
208    if (0xf == data)
209    {
210        entry->static_en = A_TRUE;
211    }
212
213    entry->mirror_en = A_FALSE;
214    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, MIRROR_EN, data, reg[2]);
215    if (1 == data)
216    {
217        entry->mirror_en = A_TRUE;
218    }
219
220    entry->clone_en = A_FALSE;
221    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, CLONE_EN, data, reg[2]);
222    if (1 == data)
223    {
224        entry->clone_en = A_TRUE;
225    }
226
227    entry->da_pri_en = A_FALSE;
228    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_PRI_EN, data, reg[2]);
229    if (1 == data)
230    {
231        SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_PRI, data, reg[2]);
232        entry->da_pri_en = A_TRUE;
233        entry->da_queue = data & 0x3;
234    }
235
236    entry->cross_pt_state = A_FALSE;
237
238    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, DES_PORT, data, reg[2]);
239
240    entry->portmap_en = A_TRUE;
241    entry->port.map = data;
242
243    for (i = 0; i < 4; i++)
244    {
245        entry->addr.uc[i] = (reg[1] >> ((3 - i) << 3)) & 0xff;
246    }
247
248    for (i = 4; i < 6; i++)
249    {
250        entry->addr.uc[i] = (reg[0] >> ((7 - i) << 3)) & 0xff;
251    }
252
253    return;
254}
255
256static sw_error_t
257garuda_fdb_commit(a_uint32_t dev_id, a_uint32_t op)
258{
259    sw_error_t rv;
260    a_uint32_t busy = 1;
261    a_uint32_t full_vio;
262    a_uint32_t i = 1000;
263    a_uint32_t entry;
264    a_uint32_t hwop = op;
265
266    while (busy && --i)
267    {
268        HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0, AT_BUSY,
269                          (a_uint8_t *) (&busy), sizeof (a_uint32_t));
270        SW_RTN_ON_ERROR(rv);
271        aos_udelay(5);
272    }
273
274    if (0 == i)
275    {
276        return SW_BUSY;
277    }
278
279    HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
280                      (a_uint8_t *) (&entry), sizeof (a_uint32_t));
281    SW_RTN_ON_ERROR(rv);
282
283    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_BUSY, 1, entry);
284
285    if (ARL_FLUSH_PORT_AND_STATIC == hwop)
286    {
287        hwop = ARL_FLUSH_PORT_UNICAST;
288        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, FLUSH_ST_EN, 1, entry);
289    }
290
291    if (ARL_FLUSH_PORT_NO_STATIC == hwop)
292    {
293        hwop = ARL_FLUSH_PORT_UNICAST;
294        SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, FLUSH_ST_EN, 0, entry);
295    }
296
297    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_FUNC, hwop, entry);
298
299    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
300                      (a_uint8_t *) (&entry), sizeof (a_uint32_t));
301    SW_RTN_ON_ERROR(rv);
302
303    busy = 1;
304    i = 1000;
305    while (busy && --i)
306    {
307        HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0, AT_BUSY,
308                          (a_uint8_t *) (&busy), sizeof (a_uint32_t));
309        SW_RTN_ON_ERROR(rv);
310        aos_udelay(5);
311    }
312
313    if (0 == i)
314    {
315        return SW_FAIL;
316    }
317
318    HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0, AT_FULL_VIO,
319                      (a_uint8_t *) (&full_vio), sizeof (a_uint32_t));
320    SW_RTN_ON_ERROR(rv);
321
322    if (full_vio)
323    {
324        /* must clear AT_FULL_VOI bit */
325        entry = 0x1000;
326        HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
327                          (a_uint8_t *) (&entry), sizeof (a_uint32_t));
328        SW_RTN_ON_ERROR(rv);
329
330        if (ARL_LOAD_ENTRY == hwop)
331        {
332            return SW_FULL;
333        }
334        else if ((ARL_PURGE_ENTRY == hwop)
335                 || (ARL_FLUSH_PORT_UNICAST == hwop))
336        {
337            return SW_NOT_FOUND;
338        }
339        else
340        {
341            return SW_FAIL;
342        }
343    }
344
345    return SW_OK;
346}
347
348static sw_error_t
349garuda_atu_get(a_uint32_t dev_id, fal_fdb_entry_t * entry, a_uint32_t op)
350{
351    sw_error_t rv;
352    a_uint32_t reg[3] = { 0 };
353    a_uint32_t status = 0;
354    a_uint32_t hwop = op;
355
356    if ((ARL_NEXT_ENTRY == op)
357            || (ARL_FIND_ENTRY == op))
358    {
359        garuda_fdb_fill_addr(entry->addr, &reg[0], &reg[1]);
360    }
361
362    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
363                      (a_uint8_t *) (&reg[0]), sizeof (a_uint32_t));
364    SW_RTN_ON_ERROR(rv);
365
366    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
367                      (a_uint8_t *) (&reg[1]), sizeof (a_uint32_t));
368    SW_RTN_ON_ERROR(rv);
369
370    /* set status not zero */
371    if (ARL_NEXT_ENTRY == op)
372    {
373        reg[2] = 0xf0000;
374    }
375
376    if (ARL_FIRST_ENTRY == op)
377    {
378        hwop = ARL_NEXT_ENTRY;
379    }
380
381    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC2, 0,
382                      (a_uint8_t *) (&reg[2]), sizeof (a_uint32_t));
383    SW_RTN_ON_ERROR(rv);
384
385    rv = garuda_fdb_commit(dev_id, hwop);
386    SW_RTN_ON_ERROR(rv);
387
388    /* get hardware enrety */
389    HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
390                      (a_uint8_t *) (&reg[0]), sizeof (a_uint32_t));
391
392    SW_RTN_ON_ERROR(rv);
393
394    HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
395                      (a_uint8_t *) (&reg[1]), sizeof (a_uint32_t));
396
397    SW_RTN_ON_ERROR(rv);
398
399    HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC2, 0,
400                      (a_uint8_t *) (&reg[2]), sizeof (a_uint32_t));
401
402    SW_RTN_ON_ERROR(rv);
403
404    SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_STATUS, status, reg[2]);
405
406    garuda_atu_hw_to_sw(reg, entry);
407
408    /* If hardware return back with address and status all zero,
409       that means no other next valid entry in fdb table */
410    if ((A_TRUE == garuda_fdb_is_zeroaddr(entry->addr))
411            && (0 == status))
412    {
413        if (ARL_NEXT_ENTRY == op)
414        {
415            return SW_NO_MORE;
416        }
417        else if ((ARL_FIND_ENTRY == op)
418                 || (ARL_FIRST_ENTRY == op))
419        {
420            return SW_NOT_FOUND;
421        }
422        else
423        {
424            return SW_FAIL;
425        }
426    }
427    else
428    {
429        return SW_OK;
430    }
431}
432
433static sw_error_t
434_garuda_fdb_add(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
435{
436    sw_error_t rv;
437    a_uint32_t reg[3] = { 0, 0, 0 };
438
439    HSL_DEV_ID_CHECK(dev_id);
440
441    rv = garuda_atu_sw_to_hw(dev_id, entry, reg);
442    SW_RTN_ON_ERROR(rv);
443
444    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC2, 0,
445                      (a_uint8_t *) (&reg[2]), sizeof (a_uint32_t));
446    SW_RTN_ON_ERROR(rv);
447
448    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0, (a_uint8_t *) (&reg[1]),
449                      sizeof (a_uint32_t));
450    SW_RTN_ON_ERROR(rv);
451
452    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0, (a_uint8_t *) (&reg[0]),
453                      sizeof (a_uint32_t));
454    SW_RTN_ON_ERROR(rv);
455
456    rv = garuda_fdb_commit(dev_id, ARL_LOAD_ENTRY);
457
458    return rv;
459}
460
461
462static sw_error_t
463_garuda_fdb_del_all(a_uint32_t dev_id, a_uint32_t flag)
464{
465    sw_error_t rv;
466
467    HSL_DEV_ID_CHECK(dev_id);
468
469    if (FAL_FDB_DEL_STATIC & flag)
470    {
471        rv = garuda_fdb_commit(dev_id, ARL_FLUSH_ALL);
472    }
473    else
474    {
475        rv = garuda_fdb_commit(dev_id, ARL_FLUSH_ALL_UNLOCK);
476    }
477
478    return rv;
479}
480
481
482static sw_error_t
483_garuda_fdb_del_by_port(a_uint32_t dev_id, fal_port_t port_id, a_uint32_t flag)
484{
485    sw_error_t rv;
486    a_uint32_t reg = 0;
487
488    HSL_DEV_ID_CHECK(dev_id);
489
490    if (A_FALSE == hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
491    {
492        return SW_BAD_PARAM;
493    }
494
495    SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_PORT_NUM, port_id, reg);
496
497    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0, (a_uint8_t *) (&reg),
498                      sizeof (a_uint32_t));
499    SW_RTN_ON_ERROR(rv);
500
501    if (FAL_FDB_DEL_STATIC & flag)
502    {
503        rv = garuda_fdb_commit(dev_id, ARL_FLUSH_PORT_AND_STATIC);
504    }
505    else
506    {
507        rv = garuda_fdb_commit(dev_id, ARL_FLUSH_PORT_NO_STATIC);
508    }
509
510    return rv;
511}
512
513
514static sw_error_t
515_garuda_fdb_del_by_mac(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
516{
517    sw_error_t rv;
518    a_uint32_t reg0 = 0, reg1 = 0;
519
520    HSL_DEV_ID_CHECK(dev_id);
521
522    garuda_fdb_fill_addr(entry->addr, &reg0, &reg1);
523
524    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0, (a_uint8_t *) (&reg1),
525                      sizeof (a_uint32_t));
526    SW_RTN_ON_ERROR(rv);
527
528    HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0, (a_uint8_t *) (&reg0),
529                      sizeof (a_uint32_t));
530    SW_RTN_ON_ERROR(rv);
531
532    rv = garuda_fdb_commit(dev_id, ARL_PURGE_ENTRY);
533    return rv;
534}
535
536
537static sw_error_t
538_garuda_fdb_next(a_uint32_t dev_id, fal_fdb_entry_t * entry)
539{
540    sw_error_t rv;
541
542    HSL_DEV_ID_CHECK(dev_id);
543
544    rv = garuda_atu_get(dev_id, entry, ARL_NEXT_ENTRY);
545    return rv;
546}
547
548
549static sw_error_t
550_garuda_fdb_first(a_uint32_t dev_id, fal_fdb_entry_t * entry)
551{
552    sw_error_t rv;
553
554    HSL_DEV_ID_CHECK(dev_id);
555
556    rv = garuda_atu_get(dev_id, entry, ARL_FIRST_ENTRY);
557    return rv;
558}
559
560
561static sw_error_t
562_garuda_fdb_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
563{
564    sw_error_t rv;
565
566    HSL_DEV_ID_CHECK(dev_id);
567
568    rv = garuda_atu_get(dev_id, entry, ARL_FIND_ENTRY);
569    return rv;
570}
571
572
573static sw_error_t
574_garuda_fdb_port_learn_set(a_uint32_t dev_id, fal_port_t port_id,
575                           a_bool_t enable)
576{
577    a_uint32_t data;
578    sw_error_t rv;
579
580    HSL_DEV_ID_CHECK(dev_id);
581
582    if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
583    {
584        return SW_BAD_PARAM;
585    }
586
587    if (A_TRUE == enable)
588    {
589        data = 1;
590    }
591    else if (A_FALSE == enable)
592    {
593        data = 0;
594    }
595    else
596    {
597        return SW_BAD_PARAM;
598    }
599
600    HSL_REG_FIELD_SET(rv, dev_id, PORT_CTL, port_id, LEARN_EN,
601                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
602    return rv;
603}
604
605
606static sw_error_t
607_garuda_fdb_port_learn_get(a_uint32_t dev_id, fal_port_t port_id,
608                           a_bool_t *enable)
609{
610    a_uint32_t data;
611    sw_error_t rv;
612
613    HSL_DEV_ID_CHECK(dev_id);
614
615    if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
616    {
617        return SW_BAD_PARAM;
618    }
619
620    HSL_REG_FIELD_GET(rv, dev_id, PORT_CTL, port_id, LEARN_EN,
621                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
622    SW_RTN_ON_ERROR(rv);
623
624    if (1 == data)
625    {
626        *enable = A_TRUE;
627    }
628    else
629    {
630        *enable = A_FALSE;
631    }
632
633    return SW_OK;
634}
635
636static sw_error_t
637_garuda_fdb_age_ctrl_set(a_uint32_t dev_id, a_bool_t enable)
638{
639    a_uint32_t data;
640    sw_error_t rv;
641
642    HSL_DEV_ID_CHECK(dev_id);
643
644    if (A_TRUE == enable)
645    {
646        data = 1;
647    }
648    else if (A_FALSE == enable)
649    {
650        data = 0;
651    }
652    else
653    {
654        return SW_BAD_PARAM;
655    }
656
657    HSL_REG_FIELD_SET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_EN,
658                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
659    return rv;
660}
661
662
663static sw_error_t
664_garuda_fdb_age_ctrl_get(a_uint32_t dev_id, a_bool_t *enable)
665{
666    a_uint32_t data;
667    sw_error_t rv;
668
669    HSL_DEV_ID_CHECK(dev_id);
670
671    HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_EN,
672                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
673    SW_RTN_ON_ERROR(rv);
674
675    if (1 == data)
676    {
677        *enable = A_TRUE;
678    }
679    else
680    {
681        *enable = A_FALSE;
682    }
683
684    return SW_OK;
685}
686
687
688static sw_error_t
689_garuda_fdb_age_time_set(a_uint32_t dev_id, a_uint32_t * time)
690{
691    a_uint32_t data;
692    sw_error_t rv;
693
694    HSL_DEV_ID_CHECK(dev_id);
695
696    if ((65535 * 7 < *time) || (7 > *time))
697    {
698        return SW_BAD_PARAM;
699    }
700    data = *time / 7;
701    *time = data * 7;
702    HSL_REG_FIELD_SET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_TIME,
703                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
704    return rv;
705}
706
707
708static sw_error_t
709_garuda_fdb_age_time_get(a_uint32_t dev_id, a_uint32_t *time)
710{
711    a_uint32_t data;
712    sw_error_t rv;
713
714    HSL_DEV_ID_CHECK(dev_id);
715
716    HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_TIME,
717                      (a_uint8_t *) (&data), sizeof (a_uint32_t));
718    SW_RTN_ON_ERROR(rv);
719
720    *time = data * 7;
721    return SW_OK;
722}
723
724/**
725 * @brief Add a Fdb entry
726 * @param[in] dev_id device id
727 * @param[in] entry fdb entry
728 * @return SW_OK or error code
729 */
730HSL_LOCAL sw_error_t
731garuda_fdb_add(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
732{
733    sw_error_t rv;
734
735    HSL_API_LOCK;
736    rv = _garuda_fdb_add(dev_id, entry);
737    HSL_API_UNLOCK;
738    return rv;
739}
740
741/**
742 * @brief Delete all Fdb entries
743 *   @details   Comments:
744 *         If set FAL_FDB_DEL_STATIC bit in flag which means delete all fdb
745 *       entries otherwise only delete dynamic entries.
746 * @param[in] dev_id device id
747 * @param[in] flag delete operation option
748 * @return SW_OK or error code
749 */
750HSL_LOCAL sw_error_t
751garuda_fdb_del_all(a_uint32_t dev_id, a_uint32_t flag)
752{
753    sw_error_t rv;
754
755    HSL_API_LOCK;
756    rv = _garuda_fdb_del_all(dev_id, flag);
757    HSL_API_UNLOCK;
758    return rv;
759}
760
761/**
762 * @brief Delete Fdb entries on a particular port
763 *   @details   Comments:
764 *       If set FAL_FDB_DEL_STATIC bit in flag which means delete all fdb
765 *       entries otherwise only delete dynamic entries.
766 * @param[in] dev_id device id
767 * @param[in] port_id port id
768 * @param[in] flag delete operation option
769 * @return SW_OK or error code
770 */
771HSL_LOCAL sw_error_t
772garuda_fdb_del_by_port(a_uint32_t dev_id, fal_port_t port_id, a_uint32_t flag)
773{
774    sw_error_t rv;
775
776    HSL_API_LOCK;
777    rv = _garuda_fdb_del_by_port(dev_id, port_id, flag);
778    HSL_API_UNLOCK;
779    return rv;
780}
781
782/**
783 * @brief Delete a particular Fdb entry through mac address
784 *   @details   Comments:
785 *       Only addr field in entry is meaning. For IVL learning vid or fid field
786 *       also is meaning.
787 * @param[in] dev_id device id
788 * @param[in] entry fdb entry
789 * @return SW_OK or error code
790 */
791HSL_LOCAL sw_error_t
792garuda_fdb_del_by_mac(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
793{
794    sw_error_t rv;
795
796    HSL_API_LOCK;
797    rv = _garuda_fdb_del_by_mac(dev_id, entry);
798    HSL_API_UNLOCK;
799    return rv;
800}
801
802/**
803 * @brief Get next Fdb entry from particular device
804 *   @details   Comments:
805 *    For input parameter only addr field in entry is meaning.
806 * @param[in] dev_id device id
807 * @param entry fdb entry
808 * @return SW_OK or error code
809 */
810HSL_LOCAL sw_error_t
811garuda_fdb_next(a_uint32_t dev_id, fal_fdb_entry_t * entry)
812{
813    sw_error_t rv;
814
815    HSL_API_LOCK;
816    rv = _garuda_fdb_next(dev_id, entry);
817    HSL_API_UNLOCK;
818    return rv;
819}
820
821/**
822 * @brief Get first Fdb entry from particular device
823 * @param[in] dev_id device id
824 * @param[out] entry fdb entry
825 * @return SW_OK or error code
826 */
827HSL_LOCAL sw_error_t
828garuda_fdb_first(a_uint32_t dev_id, fal_fdb_entry_t * entry)
829{
830    sw_error_t rv;
831
832    HSL_API_LOCK;
833    rv = _garuda_fdb_first(dev_id, entry);
834    HSL_API_UNLOCK;
835    return rv;
836}
837
838/**
839 * @brief Find a particular Fdb entry from device through mac address.
840 *    @details  Comments:
841    For input parameter only addr field in entry is meaning.
842 * @param[in] dev_id device id
843 * @param[in] entry fdb entry
844 * @param[out] entry fdb entry
845 * @return SW_OK or error code
846 */
847HSL_LOCAL sw_error_t
848garuda_fdb_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
849{
850    sw_error_t rv;
851
852    HSL_API_LOCK;
853    rv = _garuda_fdb_find(dev_id, entry);
854    HSL_API_UNLOCK;
855    return rv;
856}
857
858/**
859 * @brief Set dynamic address learning status on a particular port.
860 *    @details  Comments:
861 *       This operation will enable or disable dynamic address learning
862 *       feature on a particular port.
863 * @param[in] dev_id device id
864 * @param[in] port_id port id
865 * @param[in] enable enable or disable
866 * @return SW_OK or error code
867 */
868HSL_LOCAL sw_error_t
869garuda_fdb_port_learn_set(a_uint32_t dev_id, fal_port_t port_id,
870                          a_bool_t enable)
871{
872    sw_error_t rv;
873
874    HSL_API_LOCK;
875    rv = _garuda_fdb_port_learn_set(dev_id, port_id, enable);
876    HSL_API_UNLOCK;
877    return rv;
878}
879
880/**
881 * @brief Get dynamic address learning status on a particular port.
882 * @param[in] dev_id device id
883 * @param[in] port_id port id
884 * @param[out] enable A_TRUE or A_FALSE
885 * @return SW_OK or error code
886 */
887HSL_LOCAL sw_error_t
888garuda_fdb_port_learn_get(a_uint32_t dev_id, fal_port_t port_id,
889                          a_bool_t *enable)
890{
891    sw_error_t rv;
892
893    HSL_API_LOCK;
894    rv = _garuda_fdb_port_learn_get(dev_id, port_id, enable);
895    HSL_API_UNLOCK;
896    return rv;
897}
898
899/**
900 * @brief Set dynamic address aging status on particular device.
901 *   @details  Comments:
902 *       This operation will enable or disable dynamic address aging
903 *       feature on particular device.
904 * @param[in] dev_id device id
905 * @param[in] enable enable or disable
906 * @return SW_OK or error code
907 */
908HSL_LOCAL sw_error_t
909garuda_fdb_age_ctrl_set(a_uint32_t dev_id, a_bool_t enable)
910{
911    sw_error_t rv;
912
913    HSL_API_LOCK;
914    rv = _garuda_fdb_age_ctrl_set(dev_id, enable);
915    HSL_API_UNLOCK;
916    return rv;
917}
918
919/**
920 * @brief Get dynamic address aging status on particular device.
921 * @param[in] dev_id device id
922 * @param[in] enable enable or disable
923 * @return SW_OK or error code
924 */
925HSL_LOCAL sw_error_t
926garuda_fdb_age_ctrl_get(a_uint32_t dev_id, a_bool_t *enable)
927{
928    sw_error_t rv;
929
930    HSL_API_LOCK;
931    rv = _garuda_fdb_age_ctrl_get(dev_id, enable);
932    HSL_API_UNLOCK;
933    return rv;
934}
935
936/**
937 * @brief Set dynamic address aging time on a particular device.
938 * @details   Comments:
939 *       This operation will set dynamic address aging time on a particular device.
940 *       The unit of time is second. Because different device has differnet
941 *       hardware granularity function will return actual time in hardware.
942 * @param[in] dev_id device id
943 * @param time aging time
944 * @return SW_OK or error code
945 */
946HSL_LOCAL sw_error_t
947garuda_fdb_age_time_set(a_uint32_t dev_id, a_uint32_t * time)
948{
949    sw_error_t rv;
950
951    HSL_API_LOCK;
952    rv = _garuda_fdb_age_time_set(dev_id, time);
953    HSL_API_UNLOCK;
954    return rv;
955}
956
957/**
958 * @brief Get dynamic address aging time on a particular device.
959 * @param[in] dev_id device id
960 * @param[out] time aging time
961 * @return SW_OK or error code
962 */
963HSL_LOCAL sw_error_t
964garuda_fdb_age_time_get(a_uint32_t dev_id, a_uint32_t *time)
965{
966    sw_error_t rv;
967
968    HSL_API_LOCK;
969    rv = _garuda_fdb_age_time_get(dev_id, time);
970    HSL_API_UNLOCK;
971    return rv;
972}
973
974sw_error_t
975garuda_fdb_init(a_uint32_t dev_id)
976{
977    HSL_DEV_ID_CHECK(dev_id);
978
979#ifndef HSL_STANDALONG
980    {
981        hsl_api_t *p_api;
982
983        SW_RTN_ON_NULL(p_api = hsl_api_ptr_get(dev_id));
984
985        p_api->fdb_add = garuda_fdb_add;
986        p_api->fdb_del_all = garuda_fdb_del_all;
987        p_api->fdb_del_by_port = garuda_fdb_del_by_port;
988        p_api->fdb_del_by_mac = garuda_fdb_del_by_mac;
989        p_api->fdb_first = garuda_fdb_first;
990        p_api->fdb_next = garuda_fdb_next;
991        p_api->fdb_find = garuda_fdb_find;
992        p_api->port_learn_set = garuda_fdb_port_learn_set;
993        p_api->port_learn_get = garuda_fdb_port_learn_get;
994        p_api->age_ctrl_set = garuda_fdb_age_ctrl_set;
995        p_api->age_ctrl_get = garuda_fdb_age_ctrl_get;
996        p_api->age_time_set = garuda_fdb_age_time_set;
997        p_api->age_time_get = garuda_fdb_age_time_get;
998    }
999#endif
1000
1001    return SW_OK;
1002}
1003
1004/**
1005 * @}
1006 */
1007
1008