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

ipoll.c (14231B)


      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  * Functions for polling IRQs instead of using hardware interrupts.
      8  * Primarily intended for board bringup and debugging.
      9  */
     10 
     11 #include <sal/core/libc.h>
     12 #include <sal/core/spl.h>
     13 #include <sal/core/sync.h>
     14 
     15 
     16 #ifdef BCM_DNX_SUPPORT
     17 #include <soc/dnx/dnx_err_recovery_manager_utils.h>
     18 #endif
     19 
     20 #include <soc/drv.h>
     21 #include <soc/ipoll.h>
     22 #ifdef BCM_CMICM_SUPPORT
     23 #include <soc/cmicm.h>
     24 #endif
     25 
     26 #ifndef IPOLL_THREAD_DELAY
     27 #define IPOLL_THREAD_DELAY      0
     28 #endif
     29 
     30 #ifndef IPOLL_THREAD_PRIO
     31 #define IPOLL_THREAD_PRIO       100
     32 #endif
     33 
     34 #ifdef SEPARATE_PKTDMA_INTR_HANDLER
     35 #ifndef IPOLL_PKTDMA_THREAD_PRIO
     36 #define IPOLL_PKTDMA_THREAD_PRIO       99
     37 #endif
     38 #endif
     39 
     40 
     41 typedef struct ipoll_ctrl_s {
     42     void *data;
     43     ipoll_handler_t handler;
     44     int paused;
     45 } ipoll_ctrl_t;
     46 
     47 static ipoll_ctrl_t _ictrl[SOC_MAX_NUM_DEVICES];
     48 static int _ihandlers;
     49 
     50 #define CMCx_IRQ0_STAT(_dev,_cmc) \
     51     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT0_OFFSET(_cmc))
     52 #define CMCx_IRQ1_STAT(_dev,_cmc) \
     53     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT1_OFFSET(_cmc))
     54 #define CMCx_IRQ2_STAT(_dev,_cmc) \
     55     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT2_OFFSET(_cmc))
     56 #define CMCx_IRQ3_STAT(_dev,_cmc) \
     57     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT3_OFFSET(_cmc))
     58 #define CMCx_IRQ4_STAT(_dev,_cmc) \
     59     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT4_OFFSET(_cmc))
     60 #define CMCx_IRQ5_STAT(_dev,_cmc) \
     61     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT5_OFFSET(_cmc))
     62 #define CMCx_IRQ6_STAT(_dev,_cmc) \
     63     soc_pci_read(_dev, CMIC_CMCx_IRQ_STAT6_OFFSET(_cmc))
     64 /*
     65  * Function:
     66  *      soc_cmic_ipoll_handler
     67  * Description:
     68  *      Main CMIC interrupt handler in polled IRQ mode
     69  * Parameters:
     70  *      dev - device number
     71  * Returns:
     72  *      Nothing
     73  */
     74 STATIC void
     75 soc_cmic_ipoll_handler(int dev)
     76 {
     77     if (soc_pci_read(dev, CMIC_IRQ_STAT) & SOC_IRQ_MASK(dev)) {
     78         _ictrl[dev].handler(_ictrl[dev].data);
     79     } else {
     80         if ((soc_feature(dev, soc_feature_extended_cmic_error)) ||
     81             (soc_feature(dev, soc_feature_short_cmic_error))) {
     82             if(soc_pci_read(dev, CMIC_IRQ_STAT_1) & SOC_IRQ1_MASK(dev) ||
     83                soc_pci_read(dev, CMIC_IRQ_STAT_2) & SOC_IRQ2_MASK(dev)) {
     84                 _ictrl[dev].handler(_ictrl[dev].data);
     85             } 
     86         }
     87     }
     88 }
     89 
     90 /*
     91  * Function:
     92  *      soc_cmicm_ipoll_handler
     93  * Description:
     94  *      Main CMICm interrupt handler in polled IRQ mode
     95  * Parameters:
     96  *      dev - device number
     97  * Returns:
     98  *      Nothing
     99  */
    100 STATIC void
    101 soc_cmicm_ipoll_handler(int dev)
    102 {
    103 #ifdef BCM_CMICM_SUPPORT
    104     int cmc;
    105 
    106     cmc = SOC_PCI_CMC(dev);
    107 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
    108     if ((CMCx_IRQ0_STAT(dev, cmc) & SOC_CMCx_IRQ0_MASK(dev, cmc)) || 
    109         (CMCx_IRQ1_STAT(dev, cmc) & SOC_CMCx_IRQ1_MASK(dev, cmc)) ||
    110         (CMCx_IRQ2_STAT(dev, cmc) & SOC_CMCx_IRQ2_MASK(dev, cmc))) {
    111         _ictrl[dev].handler(_ictrl[dev].data);
    112     } else {
    113         if (soc_feature(dev, soc_feature_cmicm_multi_dma_cmc)) {
    114             if ((CMCx_IRQ0_STAT(dev, SOC_ARM_CMC(dev, 0)) & 
    115                  SOC_CMCx_IRQ0_MASK(dev, SOC_ARM_CMC(dev, 0))) || 
    116                 (CMCx_IRQ0_STAT(dev, SOC_ARM_CMC(dev, 1)) &
    117                  SOC_CMCx_IRQ0_MASK(dev, SOC_ARM_CMC(dev, 1)))) {
    118                 _ictrl[dev].handler(_ictrl[dev].data);
    119             }
    120         }
    121         if (soc_feature(dev, soc_feature_extended_cmic_error) ||
    122             soc_feature(dev, soc_feature_short_cmic_error)) {
    123             if ((CMCx_IRQ3_STAT(dev, cmc) & SOC_CMCx_IRQ3_MASK(dev,cmc)) ||
    124                 (CMCx_IRQ4_STAT(dev, cmc) & SOC_CMCx_IRQ4_MASK(dev,cmc))) {
    125                 _ictrl[dev].handler(_ictrl[dev].data);
    126             }
    127             if (soc_feature(dev, soc_feature_cmicm_extended_interrupts)) {
    128                 if ((CMCx_IRQ5_STAT(dev, cmc) & SOC_CMCx_IRQ5_MASK(dev,cmc)) ||
    129                     (CMCx_IRQ6_STAT(dev, cmc) & SOC_CMCx_IRQ6_MASK(dev,cmc))) {
    130                     _ictrl[dev].handler(_ictrl[dev].data);
    131                 }
    132             }
    133         }
    134         if (soc_feature(dev, soc_feature_cmicm_extended_interrupts)) {
    135 #ifdef BCM_CMICDV2_SUPPORT
    136             if (soc_feature(dev, soc_feature_cmicd_v2)) {
    137                 if ((CMCx_IRQ3_STAT(dev, cmc) & SOC_CMCx_IRQ3_MASK(dev,cmc)) ||
    138                     (CMCx_IRQ4_STAT(dev, cmc) & SOC_CMCx_IRQ4_MASK(dev,cmc)) ||
    139                     (CMCx_IRQ5_STAT(dev, cmc) & SOC_CMCx_IRQ5_MASK(dev,cmc))) {
    140                     _ictrl[dev].handler(_ictrl[dev].data);
    141                 }
    142 #ifdef BCM_CMICDV4_SUPPORT
    143                 if (soc_feature(dev, soc_feature_cmicd_v4)) {
    144                     if (CMCx_IRQ6_STAT(dev, cmc) & SOC_CMCx_IRQ6_MASK(dev,cmc)) {
    145                         _ictrl[dev].handler(_ictrl[dev].data);
    146                     }
    147                 }
    148 #endif /* BCM_CMICDV4_SUPPORT */
    149             }
    150 #endif /* BCM_CMICDV2_SUPPORT */
    151         }
    152     }
    153 #endif
    154 #endif
    155 }
    156 
    157 
    158 /*
    159  * Function:
    160  *      soc_cmicx_ipoll_handler
    161  * Description:
    162  *      Main CMICx interrupt handler in polled IRQ mode
    163  * Parameters:
    164  *      dev - device number
    165  * Returns:
    166  *      Nothing
    167  */
    168 STATIC void
    169 soc_cmicx_ipoll_handler(int dev)
    170 {
    171 #ifdef BCM_CMICX_SUPPORT
    172     /*
    173      For cmicx, soc_cmicx_intr will check interrupt stat and mask
    174      */
    175     _ictrl[dev].handler(_ictrl[dev].data);
    176 #endif
    177 }
    178 
    179 /*
    180  * Function:
    181  *      soc_ipoll_thread
    182  * Description:
    183  *      Thread context for interrupt handlers in polled IRQ mode
    184  * Parameters:
    185  *      data - poll delay in usecs (passed as pointer)
    186  * Returns:
    187  *      Nothing
    188  */
    189 STATIC void
    190 soc_ipoll_thread(void *data)
    191 {
    192     int dev, spl, udelay;
    193 
    194     udelay = PTR_TO_INT(data);
    195 
    196 #ifdef BCM_DNX_SUPPORT
    197     DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS();
    198 #endif
    199 
    200     while (_ihandlers) {
    201 
    202         spl = sal_splhi();
    203 
    204         for (dev = 0; dev < SOC_MAX_NUM_DEVICES; dev++) {
    205             if (_ictrl[dev].handler != NULL && !_ictrl[dev].paused) {
    206                 if (soc_feature(dev, soc_feature_cmicm)) {
    207                     soc_cmicm_ipoll_handler(dev);
    208                 } else if (soc_feature(dev, soc_feature_cmicx)){
    209                     soc_cmicx_ipoll_handler(dev);
    210                 } else {
    211                     soc_cmic_ipoll_handler(dev);
    212                 }
    213             }
    214         }
    215 
    216         sal_spl(spl);
    217 
    218         if (udelay) {
    219             sal_usleep(udelay);
    220         } else {
    221             sal_thread_yield();
    222         }
    223     }
    224 
    225 #ifdef BCM_DNX_SUPPORT
    226     DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS();
    227 #endif
    228 
    229     sal_thread_exit(0);
    230 }
    231 
    232 /*
    233  * Function:
    234  *      soc_ipoll_connect
    235  * Description:
    236  *      Install interrupt handler in polled IRQ mode
    237  * Parameters:
    238  *      dev - device number
    239  *      handler - interrupt handler
    240  *      data - interrupt handler data
    241  * Return Value:
    242  *      BCM_E_NONE
    243  *      BCM_E_XXX - an error occurred
    244  * Notes:
    245  *      The first handler installed be cause the polling
    246  *      thread to be created.
    247  */
    248 int
    249 soc_ipoll_connect(int dev, ipoll_handler_t handler, void *data)
    250 {
    251     int spl;
    252     int udelay, prio;
    253     int start_thread = 0;
    254 
    255     if (dev >= SOC_MAX_NUM_DEVICES) {
    256         return SOC_E_PARAM;
    257     }
    258 
    259     spl = sal_splhi();
    260 
    261     if (_ictrl[dev].handler == NULL) {
    262         if (_ihandlers++ == 0) {
    263             /* Create thread if first handler */
    264             start_thread = 1;
    265         }
    266     }
    267     _ictrl[dev].handler = handler;
    268     _ictrl[dev].data = data;
    269     _ictrl[dev].paused = 0;
    270 
    271     sal_spl(spl);
    272 
    273     if (start_thread) {
    274         udelay = soc_property_get(dev, spn_POLLED_IRQ_DELAY, IPOLL_THREAD_DELAY);
    275         prio = soc_property_get(dev, spn_POLLED_IRQ_PRIORITY, IPOLL_THREAD_PRIO);
    276 #ifdef ADAPTER_SERVER_MODE
    277         if (SOC_IS_DNX(dev)) {
    278             /* reduce CPU overhead for CModel */
    279             udelay = udelay * 100;
    280         }
    281 #endif
    282 
    283     sal_thread_create("bcmPOLL",
    284                       SAL_THREAD_STKSZ, prio,
    285                       soc_ipoll_thread, INT_TO_PTR(udelay));
    286     }
    287 
    288     return SOC_E_NONE;
    289 }
    290 
    291 /*
    292  * Function:
    293  *      soc_ipoll_disconnect
    294  * Description:
    295  *      Uninstall interrupt handler from polled IRQ mode
    296  * Parameters:
    297  *      dev - device number
    298  * Return Value:
    299  *      BCM_E_NONE
    300  *      BCM_E_XXX - an error occurred
    301  * Notes:
    302  *      When the last handler is uninstalled the polling
    303  *      thread will terminate.
    304  */
    305 int
    306 soc_ipoll_disconnect(int dev)
    307 {
    308     int spl;
    309 
    310     if (dev >= SOC_MAX_NUM_DEVICES) {
    311         return SOC_E_PARAM;
    312     }
    313 
    314     spl = sal_splhi();
    315 
    316     if (_ictrl[dev].handler != NULL) {
    317         _ictrl[dev].handler = NULL;
    318         _ictrl[dev].data = NULL;
    319         _ihandlers--;
    320     }
    321 
    322     sal_spl(spl);
    323 
    324     return SOC_E_NONE;
    325 }
    326 
    327 /*
    328  * Function:
    329  *      soc_ipoll_pause
    330  * Description:
    331  *      Temporarily suspend IRQ polling
    332  * Parameters:
    333  *      dev - device number
    334  * Return Value:
    335  *      BCM_E_NONE
    336  *      BCM_E_XXX - an error occurred
    337  */
    338 int
    339 soc_ipoll_pause(int dev)
    340 {
    341     int spl;
    342 
    343     if (dev >= SOC_MAX_NUM_DEVICES) {
    344         return SOC_E_PARAM;
    345     }
    346 
    347     spl = sal_splhi();
    348 
    349     _ictrl[dev].paused++;
    350 
    351     sal_spl(spl);
    352 
    353     return SOC_E_NONE;
    354 }
    355 
    356 /*
    357  * Function:
    358  *      soc_ipoll_continue
    359  * Description:
    360  *      Resume suspended IRQ polling
    361  * Parameters:
    362  *      dev - device number
    363  * Return Value:
    364  *      BCM_E_NONE
    365  *      BCM_E_XXX - an error occurred
    366  */
    367 int
    368 soc_ipoll_continue(int dev)
    369 {
    370     int spl;
    371 
    372     if (dev >= SOC_MAX_NUM_DEVICES) {
    373         return SOC_E_PARAM;
    374     }
    375 
    376     spl = sal_splhi();
    377 
    378     _ictrl[dev].paused--;
    379 
    380     sal_spl(spl);
    381 
    382     return SOC_E_NONE;
    383 }
    384 
    385 #ifdef SEPARATE_PKTDMA_INTR_HANDLER
    386 static ipoll_ctrl_t _pktdma_ictrl[SOC_MAX_NUM_DEVICES];
    387 static int _pktdma_ihandlers;
    388 /*
    389  * Function:
    390  *      soc_cmicm_pktdma_ipoll_handler
    391  * Description:
    392  *      CMICm Packet DMA dedicated interrupt handler in polled IRQ mode
    393  * Parameters:
    394  *      dev - device number
    395  * Returns:
    396  *      Nothing
    397  */
    398 STATIC void
    399 soc_cmicm_pktdma_ipoll_handler(int dev)
    400 {
    401 #ifdef BCM_CMICM_SUPPORT
    402     int cmc;
    403 
    404     cmc = SOC_PCI_CMC(dev);
    405 #if defined(BCM_SAND_SUPPORT)
    406     if ((CMCx_IRQ0_STAT(dev, cmc) & SOC_CMCx_IRQ0_MASK(dev, cmc)) ||
    407         (CMCx_IRQ1_STAT(dev, cmc) & SOC_CMCx_IRQ1_MASK(dev, cmc)) ||
    408         (CMCx_IRQ2_STAT(dev, cmc) & SOC_CMCx_IRQ2_MASK(dev, cmc))) {
    409         _pktdma_ictrl[dev].handler(_pktdma_ictrl[dev].data);
    410     }
    411 #endif
    412 #endif
    413 }
    414 
    415 /*
    416  * Function:
    417  *      soc_cmicx_pktdma_ipoll_handler
    418  * Description:
    419  *      CMICx Packet DMA dedicated interrupt handler in polled IRQ mode
    420  * Parameters:
    421  *      dev - device number
    422  * Returns:
    423  *      Nothing
    424  */
    425 STATIC void
    426 soc_cmicx_pktdma_ipoll_handler(int dev)
    427 {
    428 #ifdef BCM_CMICX_SUPPORT
    429     _pktdma_ictrl[dev].handler(_pktdma_ictrl[dev].data);
    430 #endif
    431 }
    432 
    433 /*
    434  * Function:
    435  *      soc_ipoll_pktdma_thread
    436  * Description:
    437  *      Thread context for Packet DMA interrupt handlers in polled IRQ mode
    438  * Parameters:
    439  *      data - poll delay in usecs (passed as pointer)
    440  * Returns:
    441  *      Nothing
    442  */
    443 STATIC void
    444 soc_ipoll_pktdma_thread(void *data)
    445 {
    446     int dev, spl, udelay;
    447 
    448     udelay = PTR_TO_INT(data);
    449 
    450 #ifdef BCM_DNX_SUPPORT
    451     DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS();
    452 #endif
    453 
    454     while (_pktdma_ihandlers) {
    455 
    456         spl = sal_splhi();
    457 
    458         for (dev = 0; dev < SOC_MAX_NUM_DEVICES; dev++) {
    459             if (_pktdma_ictrl[dev].handler != NULL && !_pktdma_ictrl[dev].paused) {
    460                 if (soc_feature(dev, soc_feature_cmicm)) {
    461                     soc_cmicm_pktdma_ipoll_handler(dev);
    462                 } else if (soc_feature(dev, soc_feature_cmicx)){
    463                     soc_cmicx_pktdma_ipoll_handler(dev);
    464                 }
    465             }
    466         }
    467 
    468         sal_spl(spl);
    469 
    470         if (udelay) {
    471             sal_usleep(udelay);
    472         } else {
    473             sal_thread_yield();
    474         }
    475     }
    476 
    477 #ifdef BCM_DNX_SUPPORT
    478     DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS();
    479 #endif
    480 
    481     sal_thread_exit(0);
    482 }
    483 
    484 /*
    485  * Function:
    486  *      soc_ipoll_pktdma_connect
    487  * Description:
    488  *      Install Packet DMA interrupt handler in polled IRQ mode
    489  * Parameters:
    490  *      dev - device number
    491  *      handler - interrupt handler
    492  *      data - interrupt handler data
    493  * Return Value:
    494  *      BCM_E_NONE
    495  *      BCM_E_XXX - an error occurred
    496  * Notes:
    497  *      The first handler installed be cause the polling
    498  *      thread to be created.
    499  */
    500 int
    501 soc_ipoll_pktdma_connect(int dev, ipoll_handler_t handler, void *data)
    502 {
    503     int spl;
    504     int udelay, prio;
    505     int start_thread = 0;
    506 
    507     if (dev >= SOC_MAX_NUM_DEVICES) {
    508         return SOC_E_PARAM;
    509     }
    510 
    511     spl = sal_splhi();
    512 
    513     if (_pktdma_ictrl[dev].handler == NULL) {
    514         if (_pktdma_ihandlers++ == 0) {
    515             /* Create thread if first handler */
    516             start_thread = 1;
    517         }
    518     }
    519     _pktdma_ictrl[dev].handler = handler;
    520     _pktdma_ictrl[dev].data = data;
    521     _pktdma_ictrl[dev].paused = 0;
    522 
    523     sal_spl(spl);
    524 
    525     if (start_thread) {
    526         udelay = soc_property_suffix_num_get(dev, -1, spn_CUSTOM_FEATURE, "polled_pktdma_irq_delay", IPOLL_THREAD_DELAY);
    527         prio = soc_property_suffix_num_get(dev, -1, spn_CUSTOM_FEATURE, "polled_pktdma_irq_priority", IPOLL_PKTDMA_THREAD_PRIO);
    528 #ifdef ADAPTER_SERVER_MODE
    529         if (SOC_IS_DNX(dev)) {
    530             /* reduce CPU overhead for CModel */
    531             udelay = udelay * 100;
    532         }
    533 #endif
    534 
    535     sal_thread_create("bcmPKTDMAPOLL",
    536                       SAL_THREAD_STKSZ, prio,
    537                       soc_ipoll_pktdma_thread, INT_TO_PTR(udelay));
    538     }
    539 
    540     return SOC_E_NONE;
    541 }
    542 
    543 /*
    544  * Function:
    545  *      soc_ipoll_pktdma_disconnect
    546  * Description:
    547  *      Uninstall Packt DMA interrupt handler from polled IRQ mode
    548  * Parameters:
    549  *      dev - device number
    550  * Return Value:
    551  *      BCM_E_NONE
    552  *      BCM_E_XXX - an error occurred
    553  * Notes:
    554  *      When the last handler is uninstalled the polling
    555  *      thread will terminate.
    556  */
    557 int
    558 soc_ipoll_pktdma_disconnect(int dev)
    559 {
    560     int spl;
    561 
    562     if (dev >= SOC_MAX_NUM_DEVICES) {
    563         return SOC_E_PARAM;
    564     }
    565 
    566     spl = sal_splhi();
    567 
    568     if (_pktdma_ictrl[dev].handler != NULL) {
    569         _pktdma_ictrl[dev].handler = NULL;
    570         _pktdma_ictrl[dev].data = NULL;
    571         _pktdma_ihandlers--;
    572     }
    573 
    574     sal_spl(spl);
    575 
    576     return SOC_E_NONE;
    577 }
    578 #endif