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

pscan.c (21452B)


      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:        pscan.c
      8  * Purpose:     uKernel based port scan common driver.
      9  *
     10  * Notes:      PSCAN functions will return SOC_E_UAVAIL unless these conditions
     11  *             are true:
     12  *               - BCM_CMICM_SUPPORT
     13  *               - soc_feature_cmicm
     14  */
     15 
     16 #include <shared/bsl.h>
     17 
     18 #include <soc/defs.h>
     19 
     20 #include <sal/types.h>
     21 #include <sal/core/alloc.h>
     22 #include <sal/core/boot.h>
     23 #include <sal/core/libc.h>
     24 #include <sal/core/sync.h>
     25 #include <sal/core/thread.h>
     26 #include <sal/core/time.h>
     27 
     28 #include <bcm/types.h>
     29 #include <soc/types.h>
     30 #include <soc/debug.h>
     31 #include <soc/drv.h>
     32 #include <soc/error.h>
     33 #include <soc/feature.h>
     34 #include <soc/uc_msg.h>
     35 #include <soc/shared/mos_msg_common.h>
     36 #include <soc/pscan.h>
     37 
     38 #ifdef BCM_CMICM_SUPPORT
     39 
     40 #define BCM_ESW_PSCAN_THREAD_PRI_DFLT   200
     41 
     42 #define PSCAN_PORT_BITMAP_BYTE_LEN      32
     43 #define PSCAN_DMA_BUFFER_LEN            PSCAN_PORT_BITMAP_BYTE_LEN
     44 
     45 /*
     46  * PSCAN Information SW Data
     47  */
     48 
     49 /* PSCAN Information SW Data Structure */
     50 typedef struct pscan_info_s {
     51     int unit;                   /* Unit number */
     52     int initialized;            /* If set, PSCAN has been initialized */
     53     int uc_num;                 /* uController number running PSCAN appl */
     54     sal_thread_t event_thread_id;            /* Event handler thread id */
     55     int event_thread_kill;                   /* Signal Event thread exit */
     56     uint8 bitmap[PSCAN_PORT_BITMAP_BYTE_LEN];
     57     int dma_buffer_len;         /* DMA max buffer size */
     58     uint8 *dma_buffer;          /* DMA buffer */
     59 } pscan_info_t;
     60 
     61 static pscan_info_t *soc_pscan_info[BCM_MAX_NUM_UNITS] = {0};
     62 
     63 #define PSCAN_INFO(u_)                     (soc_pscan_info[(u_)])
     64 
     65 /*
     66  * Utility macros
     67  */
     68 /* True if PSCAN module has been initialized */
     69 #define PSCAN_INIT(u_)                                        \
     70     ((PSCAN_INFO(u_) != NULL) && (PSCAN_INFO(u_)->initialized))
     71 
     72 /* Checks for 'null' argument */
     73 #define PARAM_NULL_CHECK(arg_)  \
     74     if ((arg_) == NULL) {       \
     75         return SOC_E_PARAM;     \
     76     }
     77 
     78 /* Checks that required feature(s) is available */
     79 #define FEATURE_CHECK(u_)                        \
     80     if (!soc_feature((u_), soc_feature_cmicm)) { \
     81         return SOC_E_UNAVAIL;                    \
     82     } 
     83 
     84 /* Checks that PSCAN module has been initialized */
     85 #define PSCAN_INIT_CHECK(u_)                                          \
     86     if ((PSCAN_INFO(u_) == NULL) || (!PSCAN_INFO(u_)->initialized)) {   \
     87         return SOC_E_INIT;                  \
     88     }
     89 
     90 /* Checks that required feature(s) is available and PSCAN has been initialized */
     91 #define PSCAN_FEATURE_INIT_CHECK(u_)              \
     92     do {                                        \
     93         FEATURE_CHECK(u_);                      \
     94         PSCAN_INIT_CHECK(u_);                     \
     95     } while (0)
     96 
     97 
     98 #undef PSCAN_DEBUG_DUMP
     99 
    100 #define PSCAN_SDK_VERSION         0
    101 #define PSCAN_UC_MIN_VERSION      0
    102 
    103 /* Timeout for Host <--> uC message */
    104 #define PSCAN_UC_MSG_TIMEOUT_USECS              2000000  /* 2 secs */
    105 #define PSCAN_UC_MSG_TIMEOUT_USECS_QUICKTURN  300000000  /* 5 mins */
    106 
    107 static sal_usecs_t pscan_uc_msg_timeout_usecs = PSCAN_UC_MSG_TIMEOUT_USECS;
    108 
    109 /*
    110  * Function:
    111  *      soc_pscan_alloc_clear
    112  * Purpose:
    113  *      Allocate memory block and set memory content to zeros.
    114  * Parameters:
    115  *      size        - (IN) Size of memory to allocate.
    116  *      description - (IN) Description of memory block.
    117  * Returns:
    118  *      Pointer to memory block.
    119  */
    120 STATIC void *
    121 soc_pscan_alloc_clear(unsigned int size, char *description)
    122 {
    123     void *block = NULL;
    124 
    125     if (size) {
    126         block = sal_alloc(size, description);
    127         if (block != NULL) {
    128             sal_memset(block, 0, size);
    129         }
    130     }
    131 
    132     return block;
    133 }
    134 
    135 /*
    136  * Function:
    137  *      soc_pscan_free_resource
    138  * Purpose:
    139  *      Free memory resources allocated for given unit.
    140  * Parameters:
    141  *      unit       - (IN) Unit number.
    142  * Returns:
    143  *      None
    144  */
    145 STATIC void
    146 soc_pscan_free_resource(int unit)
    147 {
    148     pscan_info_t *info;
    149 
    150     if (soc_pscan_info[unit] != NULL) {
    151         info = soc_pscan_info[unit];
    152         if (info->dma_buffer != NULL) {
    153             soc_cm_sfree(unit, info->dma_buffer);
    154         }
    155 
    156         sal_free(soc_pscan_info[unit]);
    157         soc_pscan_info[unit] = NULL;
    158     }
    159 
    160     return;
    161 }
    162 
    163 /*
    164  * Function:
    165  *      soc_pscan_alloc_resource
    166  * Purpose:
    167  *      Allocate memory resources allocated for given unit.
    168  * Parameters:
    169  *      unit       - (IN) Unit number.
    170  * Returns:
    171  *      None
    172  */
    173 STATIC int
    174 soc_pscan_alloc_resource(int unit)
    175 {
    176     pscan_info_t *pscan_info;
    177 
    178     if (soc_pscan_info[unit] != NULL) {
    179         soc_pscan_free_resource(unit);
    180     }
    181 
    182     /* Allocate memory for PSCAN Information Data Structure */
    183     if ((soc_pscan_info[unit] =
    184          soc_pscan_alloc_clear(sizeof(pscan_info_t),
    185                                    "PSCAN info")) == NULL) {
    186         return SOC_E_MEMORY;
    187     }
    188 
    189     pscan_info = PSCAN_INFO(unit);
    190 
    191     /*
    192      * Allocate DMA buffer
    193      *
    194      * DMA buffer will be used to send and receive 'long' messages
    195      * between SDK Host and uController (BTE).
    196      */
    197     pscan_info->dma_buffer_len = PSCAN_DMA_BUFFER_LEN;
    198     pscan_info->dma_buffer = soc_cm_salloc(unit, pscan_info->dma_buffer_len,
    199                                            "PSCAN DMA buffer");
    200     if (!pscan_info->dma_buffer) {
    201         return SOC_E_MEMORY;
    202     }
    203     sal_memset(pscan_info->dma_buffer, 0, pscan_info->dma_buffer_len);
    204 
    205     return SOC_E_NONE;
    206 }
    207 
    208 /*
    209  * Function:
    210  *      soc_pscan_msg_send_receive
    211  * Purpose:
    212  *      Sends given PSCAN control message to the uController.
    213  *      Receives and verifies expected reply.
    214  * Parameters:
    215  *      unit        - (IN) Unit number.
    216  *      s_subclass  - (IN) PSCAN message subclass.
    217  *      s_len       - (IN) Value for 'len' field in message struct.
    218  *                         Length of buffer to flush if DMA send is required.
    219  *      s_data      - (IN) Value for 'data' field in message struct.
    220  *                         Ignored if message requires a DMA send/receive
    221  *                         operation.
    222  *      r_subclass  - (IN) Expected reply message subclass.
    223  *      r_len       - (OUT) Returns value in 'len' reply message field.
    224  *      r_data      - (OUT) Returns value in 'data' reply message field.
    225  * Returns:
    226  *      SOC_E_XXX
    227  * Notes:
    228  *     - The uc_msg 'len' and 'data' fields of mos_msg_data_t
    229  *       can take any arbitrary data.
    230  */
    231 STATIC int
    232 soc_pscan_msg_send_receive(int unit, uint8 s_subclass,
    233                                  uint16 s_len, uint32 s_data,
    234                                  uint8 r_subclass,
    235                                  uint16 *r_len, uint32 *r_data)
    236 {
    237     int rv;
    238     sal_paddr_t paddr;
    239     pscan_info_t *pscan_info = PSCAN_INFO(unit);
    240     mos_msg_data_t send, reply;
    241     uint8 *dma_buffer;
    242     uint32 dma_buffer_len;
    243 
    244     sal_memset(&send, 0, sizeof(send));
    245     sal_memset(&reply, 0, sizeof(reply));
    246     send.s.mclass = MOS_MSG_CLASS_PSCAN;
    247     send.s.subclass = s_subclass;
    248     send.s.len = soc_htons(s_len);
    249 
    250     /*
    251      * Set 'data' to DMA buffer address if a DMA operation is
    252      * required for send or receive.
    253      */
    254     dma_buffer = pscan_info->dma_buffer;
    255     dma_buffer_len = pscan_info->dma_buffer_len;
    256     if (MOS_MSG_DMA_MSG(s_subclass) || MOS_MSG_DMA_MSG(r_subclass)) {
    257         paddr = soc_cm_l2p(unit, dma_buffer);
    258         send.s.data = soc_htonl((uint32)paddr);
    259     } else {
    260         send.s.data = soc_htonl(s_data);
    261     }
    262 
    263     /* Flush DMA memory */
    264     if (MOS_MSG_DMA_MSG(s_subclass)) {
    265         soc_cm_sflush(unit, dma_buffer, s_len);
    266     }
    267 
    268     /* Invalidate DMA memory to read */
    269     if (MOS_MSG_DMA_MSG(r_subclass)) {
    270         soc_cm_sinval(unit, dma_buffer, dma_buffer_len);
    271     }
    272 
    273     rv = soc_cmic_uc_msg_send_receive(unit, pscan_info->uc_num,
    274                                       &send, &reply,
    275                                       pscan_uc_msg_timeout_usecs);
    276 
    277     /* Check reply class, subclass */
    278     if ((rv != SOC_E_NONE) ||
    279         (reply.s.mclass != MOS_MSG_CLASS_PSCAN) ||
    280         (reply.s.subclass != r_subclass)) {
    281         return SOC_E_INTERNAL;
    282     }
    283 
    284     if (r_data != NULL) {
    285         *r_data = soc_ntohl(reply.s.data);
    286     }
    287     if (r_len != NULL) {
    288         *r_len = soc_ntohs(reply.s.len);
    289     }
    290 
    291     return rv;
    292 }
    293 
    294 /*
    295  * Function:
    296  *      soc_pscan_delay
    297  * Purpose:
    298  *      Set the scan delay for the given unit
    299  * Parameters:
    300  *      unit       - (IN) Unit number.
    301  *      delay      - (IN) delay in usec.
    302  * Returns:
    303  *      SOC_E_NONE or error
    304  */
    305 int
    306 soc_pscan_delay(int unit, int delay)
    307 {
    308     int rv = SOC_E_NONE;
    309     uint16 reply_len;
    310     pscan_info_t *pscan_info;
    311 
    312     FEATURE_CHECK(unit);
    313 
    314     /* check if already initialized */
    315     if (!PSCAN_INIT(unit)) {
    316         LOG_WARN(BSL_LS_SOC_COMMON,
    317                  (BSL_META_U(unit,
    318                              "PSCAN not initialized\n")));
    319         return SOC_E_NONE;
    320     }
    321 
    322     pscan_info = PSCAN_INFO(unit);
    323     if (soc_cmic_uc_msg_active_wait(unit, pscan_info->uc_num) != SOC_E_NONE) {
    324         LOG_WARN(BSL_LS_SOC_COMMON,
    325                  (BSL_META_U(unit,
    326                              "uKernel not Ready, PSCAN not started\n")));
    327         return SOC_E_NONE;
    328     }
    329 
    330     /* Send PSCAN delay message to uC */
    331     rv = soc_pscan_msg_send_receive(unit,
    332                                           MOS_MSG_SUBCLASS_PSCAN_SCAN_DELAY,
    333                                           0, delay,
    334                                           MOS_MSG_SUBCLASS_PSCAN_SCAN_DELAY,
    335                                           &reply_len, NULL);
    336 
    337     if (SOC_FAILURE(rv) || (reply_len != 0)) {
    338         if (SOC_SUCCESS(rv)) {
    339             rv = SOC_E_INTERNAL;
    340         }
    341         return rv;
    342     }
    343 
    344     return SOC_E_NONE;
    345 }
    346 
    347 /*
    348  * Function:
    349  *      soc_pscan_port_config
    350  * Purpose:
    351  *      Set the flags for a given <unit, port>
    352  * Parameters:
    353  *      unit       - (IN) Unit number.
    354  *      port       - (IN) Port to configure.
    355  *      flags      - (IN) flag bitmask
    356  * Returns:
    357  *      SOC_E_NONE or error
    358  */
    359 int
    360 soc_pscan_port_config(int unit, uint32 port, uint32 flags)
    361 {
    362     int rv = SOC_E_NONE;
    363     uint16 reply_len;
    364     pscan_info_t *pscan_info;
    365 
    366     FEATURE_CHECK(unit);
    367 
    368     /* check if already initialized */
    369     if (!PSCAN_INIT(unit)) {
    370         LOG_WARN(BSL_LS_SOC_COMMON,
    371                  (BSL_META_U(unit,
    372                              "PSCAN not initialized\n")));
    373         return SOC_E_NONE;
    374     }
    375 
    376     pscan_info = PSCAN_INFO(unit);
    377     if (soc_cmic_uc_msg_active_wait(unit, pscan_info->uc_num) != SOC_E_NONE) {
    378         LOG_WARN(BSL_LS_SOC_COMMON,
    379                  (BSL_META_U(unit,
    380                              "uKernel not Ready, PSCAN not started\n")));
    381         return SOC_E_NONE;
    382     }
    383 
    384     /* Send PSCAN delay message to uC */
    385     rv = soc_pscan_msg_send_receive(unit,
    386                                     MOS_MSG_SUBCLASS_PSCAN_PORT_CONFIG,
    387                                     port, flags,
    388                                     MOS_MSG_SUBCLASS_PSCAN_PORT_CONFIG,
    389                                     &reply_len, NULL);
    390 
    391     if (SOC_FAILURE(rv) || (reply_len != 0)) {
    392         if (SOC_SUCCESS(rv)) {
    393             rv = SOC_E_INTERNAL;
    394         }
    395         return rv;
    396     }
    397 
    398     return SOC_E_NONE;
    399 }
    400 
    401 /*
    402  * Function:
    403  *      soc_pscan_port_enable
    404  * Purpose:
    405  *      Enable/disable scanning on the specified port
    406  * Parameters:
    407  *      unit       - (IN) Unit number.
    408  *      port       - (IN) Port to configure.
    409  *      enable     - (IN) enable flag
    410  * Returns:
    411  *      SOC_E_NONE or error
    412  */
    413 int
    414 soc_pscan_port_enable(int unit, uint32 port, int enable)
    415 {
    416     pscan_info_t *pscan_info;
    417 
    418     FEATURE_CHECK(unit);
    419 
    420     /* check if already initialized */
    421     if (!PSCAN_INIT(unit)) {
    422         LOG_WARN(BSL_LS_SOC_COMMON,
    423                  (BSL_META_U(unit,
    424                              "PSCAN not initialized\n")));
    425         return SOC_E_NONE;
    426     }
    427 
    428     if (port > PSCAN_PORT_BITMAP_BYTE_LEN*8) {
    429         LOG_WARN(BSL_LS_SOC_COMMON,
    430                  (BSL_META_U(unit,
    431                              "PSCAN invalid port %d\n"), port));
    432         return SOC_E_INTERNAL;
    433     }
    434 
    435     pscan_info = PSCAN_INFO(unit);
    436     if (enable) {
    437         pscan_info->bitmap[port >> 3] |= 1 << (port & 0x07);
    438     }
    439     else {
    440         pscan_info->bitmap[port >> 3] &= ~(1 << (port & 0x07));
    441     }
    442     return SOC_E_NONE;
    443 }
    444 
    445 /*
    446  * Function:
    447  *      soc_pscan_update
    448  * Purpose:
    449  *      Push the port scan bitmap to the uKernel
    450  * Parameters:
    451  *      unit       - (IN) Unit number.
    452  * Returns:
    453  *      SOC_E_NONE or error
    454  */
    455 int
    456 soc_pscan_update(int unit)
    457 {
    458     int rv = SOC_E_NONE;
    459     uint16 reply_len;
    460     pscan_info_t *pscan_info = PSCAN_INFO(unit);
    461 
    462     FEATURE_CHECK(unit);
    463 
    464     /* check if already initialized */
    465     if (!PSCAN_INIT(unit)) {
    466         LOG_WARN(BSL_LS_SOC_COMMON,
    467                  (BSL_META_U(unit,
    468                              "PSCAN not initialized\n")));
    469         return SOC_E_NONE;
    470     }
    471     if (soc_cmic_uc_msg_active_wait(unit, pscan_info->uc_num) != SOC_E_NONE) {
    472         LOG_WARN(BSL_LS_SOC_COMMON,
    473                  (BSL_META_U(unit,
    474                              "uKernel not Ready, PSCAN not started\n")));
    475         return SOC_E_NONE;
    476     }
    477 
    478     /* Copy bitmap to dma buffer */
    479     sal_memcpy(pscan_info->dma_buffer, pscan_info->bitmap,
    480                PSCAN_PORT_BITMAP_BYTE_LEN);
    481 
    482     /* Send PSCAN delay message to uC */
    483     rv = soc_pscan_msg_send_receive(unit,
    484                                     MOS_MSG_SUBCLASS_PSCAN_PORT_BITMAP,
    485                                     PSCAN_PORT_BITMAP_BYTE_LEN,
    486                                     0,
    487                                     MOS_MSG_SUBCLASS_PSCAN_PORT_BITMAP_REPLY,
    488                                     &reply_len, NULL);
    489 
    490     if (SOC_FAILURE(rv) || (reply_len != 0)) {
    491         if (SOC_SUCCESS(rv)) {
    492             rv = SOC_E_INTERNAL;
    493         }
    494         return rv;
    495     }
    496 
    497     return SOC_E_NONE;
    498 }
    499 
    500 /*
    501  * Function:
    502  *      soc_pscan_callback_thread
    503  * Purpose:
    504  *      Thread to listen for event messages from uController.
    505  * Parameters:
    506  *      param - Pointer to PSCAN info structure.
    507  * Returns:
    508  *      None
    509  */
    510 STATIC void
    511 soc_pscan_callback_thread(int unit)
    512 {
    513     int rv;
    514     pscan_info_t *pscan_info = PSCAN_INFO(unit);
    515     mos_msg_data_t event_msg;
    516     uint16 port;
    517     uint32 code;
    518 
    519     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    520                 (BSL_META_U(unit,
    521                             "PSCAN callback thread starting\n")));
    522 
    523     pscan_info->event_thread_id = sal_thread_self();
    524     pscan_info->event_thread_kill = 0;
    525 
    526     while (1) {
    527         /* Wait on notifications from uController */
    528         rv = soc_cmic_uc_msg_receive(pscan_info->unit, pscan_info->uc_num,
    529                                      MOS_MSG_CLASS_PSCAN_EVENT, &event_msg,
    530                                      sal_sem_FOREVER);
    531 
    532         if (SOC_FAILURE(rv) || (pscan_info->event_thread_kill)) {
    533             break;   /* Thread exit */
    534         }
    535 
    536         /* Get data from event message */
    537         port = soc_ntohs(event_msg.s.len);
    538         code = soc_ntohl(event_msg.s.data);
    539 
    540         LOG_CLI((BSL_META_U(unit,
    541                             "PSCAN port %d alert 0x%08x\n"), port, code));
    542     }
    543 
    544     pscan_info->event_thread_kill = 0;
    545     pscan_info->event_thread_id = NULL;
    546     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    547                 (BSL_META_U(unit,
    548                             "PSCAN callback thread stopped\n")));
    549     sal_thread_exit(0);
    550 }
    551 
    552 /*
    553  * Function:
    554  *      soc_pscan_init
    555  * Purpose:
    556  *      Initialize the PSCAN subsystem
    557  * Parameters:
    558  *      unit - (IN) Unit number.
    559  * Returns:
    560  *      SOC_E_NONE Operation completed successfully
    561  *      SOC_E_MEMORY Unable to allocate memory for internal control structures
    562  *      SOC_E_INTERNAL Failed to initialize
    563  * Notes:
    564  *      PSCAN initialization will return SOC_E_NONE for the following
    565  *      error conditions (i.e. feature not supported):
    566  *      - uKernel is not loaded
    567  *      - PSCAN application is not found in any of the uC uKernel
    568  */
    569 int
    570 soc_pscan_init(int unit)
    571 {
    572     int uc;
    573     int rv = SOC_E_NONE;
    574     pscan_info_t *pscan_info;
    575     int priority;
    576 
    577     FEATURE_CHECK(unit);
    578 
    579     if (SAL_BOOT_QUICKTURN) {
    580         pscan_uc_msg_timeout_usecs = PSCAN_UC_MSG_TIMEOUT_USECS_QUICKTURN;
    581     } else {
    582         pscan_uc_msg_timeout_usecs = PSCAN_UC_MSG_TIMEOUT_USECS;
    583     }
    584 
    585     /* Check if uKernel is loaded */
    586     for (uc = 0; uc < SOC_INFO(unit).num_ucs; uc++) {
    587         if (soc_cmic_uc_msg_active_wait(unit, uc) == SOC_E_NONE) {
    588             break;
    589         }
    590     }
    591     /* Return silently if there is no active CMICm */
    592     if (uc >= SOC_INFO(unit).num_ucs) {
    593         LOG_WARN(BSL_LS_SOC_COMMON,
    594                  (BSL_META_U(unit,
    595                              "uKernel not Ready, PSCAN not started\n")));
    596         return SOC_E_NONE;
    597     }
    598 
    599     /* Detach if already initialized */
    600     if (PSCAN_INIT(unit)) {
    601         SOC_IF_ERROR_RETURN(soc_pscan_detach(unit));
    602     }
    603 
    604     /*
    605      * Initialize HOST side
    606      */
    607     rv = soc_pscan_alloc_resource(unit);
    608     if (SOC_FAILURE(rv)) {
    609         soc_pscan_free_resource(unit);
    610         return rv;
    611     }
    612 
    613     pscan_info                     = PSCAN_INFO(unit);
    614     pscan_info->unit               = unit;
    615 
    616     /*
    617      * Initialize uController side
    618      */
    619 
    620     /*
    621      * Start PSCAN application in BTE (Broadcom Task Engine) uController.
    622      * Determine which uController is running PSCAN  by choosing the first
    623      * uC that returns successfully.
    624      */
    625     for (uc = 0; uc < SOC_INFO(unit).num_ucs; uc++) {
    626         rv = soc_cmic_uc_appl_init(unit, uc, MOS_MSG_CLASS_PSCAN,
    627                                    pscan_uc_msg_timeout_usecs,
    628                                    PSCAN_SDK_VERSION,
    629                                    PSCAN_UC_MIN_VERSION,
    630                                    NULL,
    631                                    NULL);
    632         if (SOC_E_NONE == rv) {
    633             /* PSCAN started successfully */
    634             pscan_info->uc_num = uc;
    635             break;
    636         }
    637     }
    638 
    639     if (uc >= SOC_INFO(unit).num_ucs) {
    640         /* Could not find or start PSCAN appl */
    641         soc_pscan_free_resource(unit);
    642         LOG_WARN(BSL_LS_SOC_COMMON,
    643                  (BSL_META_U(unit,
    644                              "uKernel PSCAN application not available\n")));
    645         return SOC_E_NONE;
    646     }
    647 
    648     /*
    649      * Initialize Event handler
    650      */
    651     /* Start event thread handler */
    652     priority = soc_property_get(unit, spn_BCM_ESW_PSCAN_THREAD_PRI, BCM_ESW_PSCAN_THREAD_PRI_DFLT);
    653     if (pscan_info->event_thread_id == NULL) {
    654         if (sal_thread_create("bcmPSCAN", SAL_THREAD_STKSZ, 
    655                               priority,
    656                               (void (*)(void*))soc_pscan_callback_thread,
    657                               INT_TO_PTR(unit)) == SAL_THREAD_ERROR) {
    658             if (SAL_BOOT_QUICKTURN) {
    659                 /* If emulation, then wait */
    660                 sal_usleep(1000000);
    661             }
    662 
    663             if (pscan_info->event_thread_id == NULL) {
    664                 SOC_IF_ERROR_RETURN(soc_pscan_detach(unit));
    665                 return SOC_E_MEMORY;
    666             }
    667         }
    668     }
    669     pscan_info->event_thread_kill = 0;
    670 
    671     /* Module has been initialized */
    672     pscan_info->initialized = 1;
    673 
    674     return SOC_E_NONE;
    675 }
    676 
    677 /*
    678  * Function:
    679  *      soc_pscan_detach
    680  * Purpose:
    681  *      Shut down the PSCAN subsystem
    682  * Parameters:
    683  *      unit - (IN) Unit number.
    684  * Returns:
    685  *      SOC_E_NONE Operation completed successfully
    686  * Notes:
    687  *      In progress...
    688  */
    689 int
    690 soc_pscan_detach(int unit)
    691 {
    692     pscan_info_t *pscan_info = PSCAN_INFO(unit);
    693 #if 0
    694     int rv;
    695     uint16 reply_len;
    696 #endif
    697     sal_usecs_t timeout = 0;
    698 
    699     FEATURE_CHECK(unit);
    700 
    701     if (!PSCAN_INIT(unit)) {
    702         return SOC_E_NONE;
    703     }
    704 
    705     /* Event Handler thread exit signal */
    706     if (pscan_info->event_thread_id) {
    707         pscan_info->event_thread_kill = 1;
    708         soc_cmic_uc_msg_receive_cancel(unit, pscan_info->uc_num,
    709                                    MOS_MSG_CLASS_PSCAN_EVENT);
    710 
    711         /*
    712          * Ensure here itself that the callback thread exists as we are going
    713          * to free soc_pscan_info below and we will loose reference
    714          * to the thread
    715          */
    716         timeout = sal_time_usecs() + 1000000;
    717         while (pscan_info->event_thread_id != NULL) {
    718             if (sal_time_usecs() < timeout) {
    719                 /*give some time to already running pscan thread to schedule and exit*/
    720                 sal_usleep(1000);
    721             } else {
    722                 /*timeout*/
    723                 LOG_ERROR(BSL_LS_SOC_COMMON,
    724                           (BSL_META_U(unit,
    725                                       "PSCAN event thread did not exit.\n")));
    726                 return SOC_E_INTERNAL;
    727             }
    728         }
    729     }
    730 
    731 #if 0
    732     /*
    733      * Send PSCAN Uninit message to uC
    734      * Ignore error since that may indicate uKernel was reloaded.
    735      */
    736     rv = soc_pscan_msg_send_receive(unit,
    737                                           MOS_MSG_SUBCLASS_PSCAN_UNINIT,
    738                                           0, 0,
    739                                           MOS_MSG_SUBCLASS_PSCAN_UNINIT_REPLY,
    740                                           &reply_len, NULL);
    741     if (BCM_SUCCESS(rv) && (reply_len != 0)) {
    742         return SOC_E_INTERNAL;
    743     }
    744 #endif
    745 
    746     /* Free resources */
    747     soc_pscan_free_resource(unit);
    748     soc_pscan_info[unit] = NULL;
    749 
    750     return SOC_E_NONE;
    751 }
    752 
    753 #endif /* BCM_CMICM_SUPPORT */