openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

l2xmsg.c (11890B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:	l2xmsg.c
      8  * Purpose:	Provide a reliable stream of L2 insert/delete messages.
      9  *
     10  * This module monitors the L2X table for changes and performs callbacks
     11  * for each insert, delete, or port movement that is detected.
     12  *
     13  * There is a time lag from the actual table change to the callback
     14  * because the l2xmsg task scans the L2X table only periodically.
     15  */
     16 
     17 #include <sal/core/libc.h>
     18 #include <shared/alloc.h>
     19 #include <sal/core/spl.h>
     20 #include <sal/core/time.h>
     21 #include <shared/bsl.h>
     22 #include <soc/mem.h>
     23 #include <soc/debug.h>
     24 #include <soc/cm.h>
     25 #include <soc/drv.h>
     26 #include <soc/l2x.h>
     27 
     28 #ifdef BCM_HURRICANE3_SUPPORT
     29 
     30 #define L2_OVERFLOW_ENTRY_EQL(unit, e1, e2, sz, bits) \
     31     (!_soc_mem_cmp_l2x_sync(unit, (void *) e1, (void *) e2, sz, bits))
     32 
     33 #define L2_OVERFLOW_IS_VALID_ENTRY(_u, _mem, _e, bitf)  \
     34            soc_mem_field32_get((_u), (_mem), (_e), bitf)
     35 
     36 
     37 /* L2 overflow structure */
     38 typedef struct l2x_overflow_data_s {
     39     soc_mem_t                   mem;
     40     int                         entry_words;
     41     int                         entry_bytes;
     42     int                         count;
     43     uint32                      *shadow_tab;
     44     uint32                      *buf;
     45 } l2x_overflow_data_t;
     46 
     47 STATIC l2x_overflow_data_t *l2x_ovf_data[SOC_MAX_NUM_DEVICES];
     48 
     49 /*
     50  * Function:
     51  * 	soc_hr3_l2_overflow_entry_get
     52  * Purpose:
     53  *   Get the values of L2 non-learned entry. 
     54  * Parameters:
     55  *	unit - unit number.
     56  * Returns:
     57  *	SOC_E_XXX.
     58  */
     59 
     60 int
     61 soc_hr3_l2_overflow_entry_get(int unit, l2x_entry_t *entry)
     62 {
     63     sal_mac_addr_t  mac;
     64     uint64  mac_field;
     65     uint32  vlan_port, vlan, port;
     66 
     67     SOC_IF_ERROR_RETURN
     68         (READ_L2_NON_LEARNED_MESSAGE_MACSAr(unit, &mac_field));
     69     SOC_IF_ERROR_RETURN
     70         (READ_L2_NON_LEARNED_MESSAGE_VLAN_PORTr(unit, &vlan_port));
     71 
     72     SAL_MAC_ADDR_FROM_UINT64(mac, mac_field);
     73     soc_L2Xm_mac_addr_set(unit, entry, MAC_ADDRf, mac);
     74     vlan = soc_reg_field_get(unit, L2_NON_LEARNED_MESSAGE_VLAN_PORTr, 
     75                           vlan_port, VLANf);
     76     soc_L2Xm_field_set(unit, entry, VLAN_IDf, &vlan);
     77     port = soc_reg_field_get(unit, L2_NON_LEARNED_MESSAGE_VLAN_PORTr, 
     78                           vlan_port, PORTf);
     79     soc_L2Xm_field_set(unit, entry, PORT_NUMf, &port);
     80     
     81     return SOC_E_NONE;
     82 }
     83 
     84 /*
     85  * Function:
     86  * 	soc_hr3_l2_overflow_intr_disable
     87  * Purpose:
     88  *   Disable the interrupt of L2 non-learned event. 
     89  * Parameters:
     90  *	unit - unit number.
     91  * Returns:
     92  *	SOC_E_XXX.
     93  */
     94 
     95 int
     96 soc_hr3_l2_overflow_intr_disable(int unit)
     97 {
     98     SOC_IF_ERROR_RETURN
     99         (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY,
    100                                 L2_ENTRY_OVF_NO_LEARN_INTRf, 0));
    101     SOC_IF_ERROR_RETURN
    102         (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY,
    103                                 L2_ENTRY_NO_LEARN_INTRf, 0));
    104     /* Mark as inactive */
    105     SOC_CONTROL_LOCK(unit);
    106     SOC_CONTROL(unit)->l2_overflow_active = FALSE;
    107     SOC_CONTROL_UNLOCK(unit);
    108     /* But don't disable interrupt as its shared by various parity events */
    109     return SOC_E_NONE;
    110 }
    111 
    112 /*
    113  * Function:
    114  * 	soc_hr3_l2_overflow_intr_enable
    115  * Purpose:
    116  *   Enable the interrupt of L2 non-learned event. 
    117  * Parameters:
    118  *	unit - unit number.
    119  * Returns:
    120  *	SOC_E_XXX.
    121  */
    122 
    123 int
    124 soc_hr3_l2_overflow_intr_enable(int unit)
    125 {
    126     if (SOC_CONTROL(unit)->l2_overflow_bucket_enable) {
    127         /* clear status */
    128         SOC_IF_ERROR_RETURN(soc_reg32_set(
    129             unit, L2_ENTRY_OVF_NO_LEARN_STATUSr, REG_PORT_ANY, 0, 0));
    130         
    131         SOC_IF_ERROR_RETURN
    132             (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY,
    133                                 L2_ENTRY_OVF_NO_LEARN_INTRf, 1));
    134     } else {
    135         /* clear status */
    136         SOC_IF_ERROR_RETURN(soc_reg32_set(
    137             unit, L2_ENTRY_NO_LEARN_STATUSr, REG_PORT_ANY, 0, 0));
    138         
    139         SOC_IF_ERROR_RETURN
    140             (soc_reg_field32_modify(unit, IP1_INTR_ENABLEr, REG_PORT_ANY,
    141                                 L2_ENTRY_NO_LEARN_INTRf, 1));
    142     }
    143     /* Mark as active */
    144     SOC_CONTROL_LOCK(unit);
    145     SOC_CONTROL(unit)->l2_overflow_active = TRUE;
    146     SOC_CONTROL_UNLOCK(unit);
    147     return SOC_E_NONE;
    148 }
    149 
    150 
    151 /*
    152  * Function:
    153  * 	soc_hr3_l2_overflow_fill
    154  * Purpose:
    155  *   Fill the values of L2 non-learned entry. 
    156  * Parameters:
    157  *	unit - unit number.
    158  *    zeros_or_ones - value to be filled
    159  * Returns:
    160  *	SOC_E_XXX.
    161  */
    162 
    163 int
    164 soc_hr3_l2_overflow_fill(int unit, uint8 zeros_or_ones)
    165 {
    166     uint64  macsa;
    167     uint32  vlan_port;
    168     
    169     if (zeros_or_ones) {
    170         COMPILER_64_SET(macsa, 0xffffffff, 0xffffffff);
    171         vlan_port = 0xffffffff;
    172     } else {
    173         COMPILER_64_ZERO(macsa);
    174         vlan_port = 0;
    175     }
    176     SOC_IF_ERROR_RETURN
    177         (WRITE_L2_NON_LEARNED_MESSAGE_MACSAr(unit, macsa));
    178     SOC_IF_ERROR_RETURN
    179         (WRITE_L2_NON_LEARNED_MESSAGE_VLAN_PORTr(unit, vlan_port));
    180     
    181     return SOC_E_NONE;
    182 }
    183 
    184 
    185 /*
    186  * Function:
    187  * 	soc_hr3_l2_overflow_interrupt_handler
    188  * Purpose:
    189  *   The handler of l2 non-learned interrupts. 
    190  * Parameters:
    191  *	unit - unit number.
    192  * Returns:
    193  *	SOC_E_XXX.
    194  */
    195 
    196 void
    197 soc_hr3_l2_overflow_interrupt_handler(int unit)
    198 {
    199     l2x_entry_t l2x_entry;
    200 
    201     if (!SOC_CONTROL(unit)->l2_overflow_active) {
    202         LOG_ERROR(BSL_LS_SOC_L2,
    203                   (BSL_META_U(unit,
    204                       "Received L2 overflow event with no app handler or"   \
    205                       " processing inactive !!\n")));
    206     }
    207     if (soc_hr3_l2_overflow_intr_disable(unit)) {
    208         return;
    209     }
    210     sal_memset(&l2x_entry, 0, sizeof(l2x_entry_t));
    211     if (soc_hr3_l2_overflow_entry_get(unit, &l2x_entry)) {
    212         return;
    213     }
    214     /* Callback */
    215     soc_l2x_callback(unit, SOC_L2X_ENTRY_OVERFLOW, NULL, &l2x_entry);  
    216 }
    217 
    218 /*
    219  * Function:
    220  * 	soc_hr3_l2_overflow_start
    221  * Purpose:
    222  *   Start reporting the L2 overflow events. 
    223  * Parameters:
    224  *	unit - unit number.
    225  * Returns:
    226  *	SOC_E_XXX.
    227  */
    228 
    229 int
    230 soc_hr3_l2_overflow_start(int unit)
    231 {
    232     if (!SOC_CONTROL(unit)->l2_overflow_enable) {
    233         return SOC_E_NONE;
    234     }
    235     if (SOC_CONTROL(unit)->l2_overflow_active) {
    236         return SOC_E_NONE;
    237     }
    238 
    239     SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_fill(unit, 0));
    240     SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_intr_enable(unit));
    241     
    242     return SOC_E_NONE;
    243 }
    244 
    245 /*
    246  * Function:
    247  * 	soc_hr3_l2_overflow_stop
    248  * Purpose:
    249  *   Stop reporting the L2 overflow events. 
    250  * Parameters:
    251  *	unit - unit number.
    252  * Returns:
    253  *	SOC_E_XXX.
    254  */
    255 
    256 int
    257 soc_hr3_l2_overflow_stop(int unit)
    258 {
    259     if (!SOC_CONTROL(unit)->l2_overflow_enable) {
    260         return SOC_E_NONE;
    261     }
    262 
    263     SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_fill(unit, 0));
    264     SOC_IF_ERROR_RETURN(soc_hr3_l2_overflow_intr_disable(unit));
    265     
    266     return SOC_E_NONE;
    267 }
    268 
    269 
    270 /*
    271  * Function:
    272  * 	soc_hr3_l2_overflow_sync
    273  * Purpose:
    274  *   Synchronize the L2 overflow table and make any ARL callbacks that are necessary.
    275  *   It is called from _soc_l2x_thread.
    276  * Parameters:
    277  *	unit - unit number.
    278  * Returns:
    279  *	SOC_E_XXX.
    280  */
    281 
    282 void
    283 soc_hr3_l2_overflow_sync(int unit)
    284 {
    285     uint32              new_valid, old_valid;
    286     uint32              *new_p, *old_p;
    287     int                 i, count, rv = SOC_E_NONE;
    288 
    289     if (l2x_ovf_data[unit] == NULL) {
    290         return;
    291     }
    292     
    293     new_p = l2x_ovf_data[unit]->buf;
    294     if ((rv = soc_mem_read_range(unit, l2x_ovf_data[unit]->mem,
    295                                  MEM_BLOCK_ANY, 0,
    296                                  l2x_ovf_data[unit]->count - 1,
    297                                  new_p)) < 0) {
    298                                  
    299         LOG_ERROR(BSL_LS_SOC_L2,
    300               (BSL_META_U(unit,"soc_hr3_l2_overflow_sync: DMA failed: %s\n"),
    301                      soc_errmsg(rv)));
    302 
    303         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR, 
    304                            SOC_SWITCH_EVENT_THREAD_L2X, __LINE__, rv);
    305 
    306     } else {
    307 
    308         /*
    309          * Scan, compare, and sync the old and new chunks one bucket
    310          * at a time.
    311          */
    312 
    313         old_p = l2x_ovf_data[unit]->shadow_tab;
    314         count = l2x_ovf_data[unit]->count;
    315         for (i = 0; i < count; i++) {
    316             /* Check the new added entries of L2_ENTRY_OVERFLOW table */
    317             new_valid = L2_OVERFLOW_IS_VALID_ENTRY(unit, 
    318                             l2x_ovf_data[unit]->mem,
    319                             new_p, VALIDf);
    320             old_valid = L2_OVERFLOW_IS_VALID_ENTRY(unit, 
    321                             l2x_ovf_data[unit]->mem,
    322                             old_p, VALIDf);
    323            
    324             if (new_valid && !old_valid) {
    325                 /* Add */
    326                 soc_l2x_callback(unit, 0, 
    327                         NULL, (l2x_entry_t *) new_p);
    328             } else if (!new_valid && old_valid) {
    329                 /* Delete */
    330                 soc_l2x_callback(unit, 0, 
    331                         (l2x_entry_t *) old_p, NULL);
    332             } else if (new_valid && old_valid) {
    333                 if (!L2_OVERFLOW_ENTRY_EQL(unit, old_p, new_p, 
    334                                 WORDS2BYTES(l2x_ovf_data[unit]->entry_words), 0)) {
    335                     /* Change */
    336                     soc_l2x_callback(unit, 0, 
    337                         (l2x_entry_t *) old_p, (l2x_entry_t *) new_p);
    338                 }
    339             }
    340             
    341             new_p += l2x_ovf_data[unit]->entry_words;
    342             old_p += l2x_ovf_data[unit]->entry_words;
    343         }
    344 
    345         sal_memcpy(l2x_ovf_data[unit]->shadow_tab, l2x_ovf_data[unit]->buf,
    346             count * l2x_ovf_data[unit]->entry_words * 4);
    347     }
    348 
    349     return;
    350 }
    351 
    352 
    353 /*
    354  * Function:
    355  * 	soc_hr3_l2_overflow_sync_cleanup
    356  * Purpose:
    357  *   	Cleanup shadow table of L2 overflow table synchronization.
    358  * Parameters:
    359  *	unit - unit number.
    360  * Returns:
    361  *	SOC_E_XXX.
    362  */
    363 
    364 void
    365 soc_hr3_l2_overflow_sync_cleanup(int unit) 
    366 {
    367     if (l2x_ovf_data[unit]->shadow_tab) {
    368         sal_free(l2x_ovf_data[unit]->shadow_tab);
    369     }
    370 
    371     if (l2x_ovf_data[unit]->buf) {
    372         soc_cm_sfree(unit, l2x_ovf_data[unit]->buf);
    373     }
    374 
    375     if (l2x_ovf_data[unit]) {
    376         sal_free(l2x_ovf_data[unit]);
    377     }
    378 
    379     return;
    380 }
    381 
    382 /*
    383  * Function:
    384  * 	soc_hr3_l2_overflow_sync_init
    385  * Purpose:
    386  *   	Initialize shadow table and prepare for L2 overflow table synchronization.
    387  * Parameters:
    388  *	unit - unit number.
    389  * Returns:
    390  *	SOC_E_XXX.
    391  */
    392  
    393 int
    394 soc_hr3_l2_overflow_sync_init(int unit)
    395 {
    396     int index_count;
    397     
    398     /* soc_mem_clear(unit, L2_ENTRY_OVERFLOWm, MEM_BLOCK_ALL, FALSE); */
    399     l2x_ovf_data[unit] = sal_alloc(sizeof(l2x_overflow_data_t), "l2x_ovf_data");
    400     if (l2x_ovf_data[unit] == NULL) {
    401         return SOC_E_MEMORY;
    402     }
    403     
    404     l2x_ovf_data[unit]->mem = L2_ENTRY_OVERFLOWm;
    405     l2x_ovf_data[unit]->entry_words = soc_mem_entry_words(unit, 
    406                                         l2x_ovf_data[unit]->mem);
    407     l2x_ovf_data[unit]->entry_bytes = soc_mem_entry_bytes(unit, 
    408                                         l2x_ovf_data[unit]->mem);
    409 
    410     index_count = soc_mem_index_count(unit, 
    411                                         l2x_ovf_data[unit]->mem);
    412     
    413     l2x_ovf_data[unit]->count = index_count;
    414     
    415     if (l2x_ovf_data[unit]->count == 0) {
    416         return SOC_E_EMPTY;
    417     }
    418     
    419     l2x_ovf_data[unit]->shadow_tab = 
    420                 sal_alloc(index_count * l2x_ovf_data[unit]->entry_words * 4,
    421                            "l2x_ovf_old");
    422 
    423     l2x_ovf_data[unit]->buf = soc_cm_salloc(unit, 
    424                 index_count * l2x_ovf_data[unit]->entry_words * 4,
    425                            "l2x_ovf_new");
    426 
    427     if ((l2x_ovf_data[unit]->shadow_tab == NULL) ||
    428         (l2x_ovf_data[unit]->buf == NULL)) {
    429         return SOC_E_MEMORY;
    430     }
    431 
    432     sal_memset(l2x_ovf_data[unit]->shadow_tab, 0, 
    433                 index_count * l2x_ovf_data[unit]->entry_words * 4);
    434     
    435     return SOC_E_NONE;
    436 }
    437 
    438 #endif /* BCM_HURRICANE3_SUPPORT */