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

schan.c (33122B)


      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  * S-Channel (internal command bus) support
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <sal/core/libc.h>
     12 #include <sal/core/boot.h>
     13 #include <sal/core/dpc.h>
     14 
     15 #include <soc/debug.h>
     16 #include <soc/cm.h>
     17 #include <soc/drv.h>
     18 #include <soc/drv.h>
     19 #include <soc/hwstate/hw_log.h>
     20 #include <soc/error.h>
     21 #include <soc/cmic.h>
     22 #ifdef BCM_CMICM_SUPPORT
     23 #include <soc/cmicm.h>
     24 #endif
     25 #include <soc/schanmsg_internal.h>
     26 
     27 #if defined (BCM_DNX_SUPPORT) || defined (BCM_DNXF_SUPPORT)
     28 #include <soc/dnxc/dnxc_ha.h>
     29 #endif
     30 
     31 #ifdef BCM_DNX_SUPPORT
     32 #include <soc/dnx/dnx_err_recovery_manager.h>
     33 #endif
     34 
     35 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN)
     36 /* Back door into the simulation to perform direct SCHANNEL operations */
     37 extern uint32 plibde_schan_op(int unit, schan_msg_t* msg, int, int);
     38 #endif
     39 
     40 #ifdef _SER_TIME_STAMP
     41 sal_usecs_t ser_time_1;
     42 #endif
     43 
     44 #define IS_WRITE_ALLOWED_DURING_WB(unit) \
     45     (SOC_CONTROL(unit)->schan_wb_thread_id == sal_thread_self())
     46 
     47 soc_cmic_schan_control_t  soc_schan_control[SOC_MAX_NUM_DEVICES];
     48 
     49 STATIC soc_cmic_schan_drv_t _soc_schan_drv[SOC_MAX_NUM_DEVICES];
     50 
     51 
     52 /*
     53  * S-Chanel operation names
     54  */
     55 
     56 STATIC char *_soc_schan_op_names[] = {
     57     "UNKNOWN_OPCODE",
     58     "BP_WARN_STATUS",           /* 0x01 */
     59     "BP_DISCARD_STATUS",        /* 0x02 */
     60     "COS_QSTAT_NOTIFY",         /* 0x03 */
     61     "HOL_STAT_NOTIFY",          /* 0x04 */
     62     "",                         /* 0x05 */
     63     "",                         /* 0x06 */
     64     "READ_MEM_CMD",             /* 0x07 */
     65     "READ_MEM_ACK",             /* 0x08 */
     66     "WRITE_MEM_CMD",            /* 0x09 */
     67     "WRITE_MEM_ACK",            /* 0x0a */
     68     "READ_REG_CMD",             /* 0x0b */
     69     "READ_REG_ACK",             /* 0x0c */
     70     "WRITE_REG_CMD",            /* 0x0d */
     71     "WRITE_REG_ACK",            /* 0x0e */
     72     "ARL_INSERT_CMD",           /* 0x0f */
     73     "ARL_INSERT_DONE",          /* 0x10 */
     74     "ARL_DELETE_CMD",           /* 0x11 */
     75     "ARL_DELETE_DONE",          /* 0x12 */
     76     "LINKSTAT_NOTIFY",          /* 0x13 */
     77     "MEM_FAIL_NOTIFY",          /* 0x14 */
     78     "INIT_CFAP",                /* 0x15 */
     79     "",                         /* 0x16 */
     80     "ENTER_DEBUG_MODE",         /* 0x17 */
     81     "EXIT_DEBUG_MODE",          /* 0x18 */
     82     "ARL_LOOKUP_CMD",           /* 0x19 */
     83     "L3_INSERT_CMD",            /* 0x1a */
     84     "L3_INSERT_DONE",           /* 0x1b */
     85     "L3_DELETE_CMD",            /* 0x1c */
     86     "L3_DELETE_DONE",           /* 0x1d */
     87     "L3_LOOKUP_CMD",            /* 0x1e */
     88     "UNKNOWN_OPCODE",           /* 0x1f */
     89     "L2_LOOKUP_CMD_MSG",        /* 0x20 */
     90     "L2_LOOKUP_ACK_MSG",        /* 0x21 */
     91     "L3X2_LOOKUP_CMD_MSG",      /* 0x22 */
     92     "L3X2_LOOKUP_ACK_MSG",      /* 0x23 */
     93     "TABLE_INSERT_CMD_MSG",     /* 0x24 */
     94     "TABLE_INSERT_DONE_MSG",    /* 0x25 */
     95     "TABLE_DELETE_CMD_MSG",     /* 0x26 */
     96     "TABLE_DELETE_DONE_MSG",    /* 0x27 */
     97     "TABLE_LOOKUP_CMD_MSG",     /* 0x28 */
     98     "TABLE_LOOKUP_DONE_MSG",    /* 0x29 */
     99     "FIFO_POP_CMD_MSG",         /* 0x2a */
    100     "FIFO_POP_DONE_MSG",        /* 0x2b */
    101     "FIFO_PUSH_CMD_MSG",        /* 0x2c */
    102     "FIFO_PUSH_DONE_MSG",       /* 0x2d */
    103 };
    104 
    105 char *
    106 soc_schan_op_name(int op)
    107 {
    108     if (op < 0 || op >= COUNTOF(_soc_schan_op_names)) {
    109         op = 0;
    110     }
    111 
    112     return _soc_schan_op_names[op];
    113 }
    114 
    115 #if defined(BCM_TRIUMPH_SUPPORT)
    116 STATIC char *_soc_schan_gen_resp_type_names[] = {
    117     "FOUND",          /*  0 */
    118     "NOT_FOUND",      /*  1 */
    119     "FULL",           /*  2 */
    120     "INSERTED",       /*  3 */
    121     "REPLACED",       /*  4 */
    122     "DELETED",        /*  5 */
    123     "ENTRY_IS_OLD",   /*  6 */
    124     "CLEARED_VALID",  /*  7 */
    125     "L2_FIFO_FULL",   /*  8 */
    126     "MAC_LIMIT_THRE", /*  9 */
    127     "MAC_LIMIT_DEL",  /* 10 */
    128     "L2_STATIC",      /* 11 */
    129     "UNKNOWN",        /* 12 */
    130     "UNKNOWN",        /* 13 */
    131     "UNKNOWN",        /* 14 */
    132     "ERROR"           /* 15 */
    133 };
    134 
    135 STATIC char *
    136 soc_schan_gen_resp_type_name(int type)
    137 {
    138     if (type < 0 || type >= COUNTOF(_soc_schan_gen_resp_type_names)) {
    139         type = 8;
    140     }
    141 
    142     return _soc_schan_gen_resp_type_names[type];
    143 }
    144 
    145 STATIC char *_soc_schan_gen_resp_err_names[] = {
    146     "NONE",            /* 0 */
    147     "SRAM_P_ERR",      /* 1 */
    148     "TCAM_SRCH_ERR",   /* 2 */
    149     "MULTIPLE",        /* 3 */
    150     "TCAM_RD_ERR",     /* 4 */
    151     "MULTIPLE",        /* 5 */
    152     "MULTIPLE",        /* 6 */
    153     "MULTIPLE",        /* 7 */
    154     "TCAM_SEQ_ERR",    /* 8 */
    155     "MULTIPLE",        /* 9 */
    156     "MULTIPLE",        /* 10 */
    157     "MULTIPLE",        /* 11 */
    158     "MULTIPLE",        /* 12 */
    159     "MULTIPLE",        /* 13 */
    160     "MULTIPLE",        /* 14 */
    161     "MULTIPLE",        /* 15 */
    162 };
    163 
    164 
    165 STATIC char *
    166 soc_schan_gen_resp_err_name(int err)
    167 {
    168     if (err < 0 || err >= COUNTOF(_soc_schan_gen_resp_err_names)) {
    169         err = 2;
    170     }
    171 
    172     return _soc_schan_gen_resp_err_names[err];
    173 }
    174 
    175 #endif /* BCM_TRIUMPH_SUPPORT */
    176 
    177 /*******************************************
    178 * @function soc_schan_header_cmd_set
    179 * purpose API to set the command header
    180 *
    181 * @param handle [in] unit
    182 * @param header [out] Populated Command header pointer
    183 * @param opcode [in] Opcode
    184 * @param dst_blk [in] Block ID
    185 * @param acc_type [in] Acc Type
    186 * @param data_byte_len [in] Dlen
    187 * @param dma, bank_ignore_mask [in] Misc Ctrl/ Status
    188 * @returns None
    189 *
    190 * @end
    191  */
    192 void
    193 soc_schan_header_cmd_set(int unit, schan_header_t *header, int opcode,
    194                          int dst_blk, int src_blk, int acc_type,
    195                          int data_byte_len, int dma, uint32 bank_ignore_mask)
    196 {
    197     if (soc_feature(unit, soc_feature_sbus_format_v4)) {
    198         header->v4.opcode = opcode;
    199         header->v4.dst_blk = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk >> 4) : dst_blk;
    200         /* input argument src_blk is ignored */
    201         header->v4.acc_type = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk & 0xf)<<1  : acc_type;
    202         header->v4.data_byte_len = data_byte_len;
    203         header->v4.dma = dma;
    204         header->v4.bank_ignore_mask = bank_ignore_mask;
    205     } else if (soc_feature(unit, soc_feature_new_sbus_format)) {
    206         header->v3.opcode = opcode;
    207         header->v3.dst_blk = dst_blk;
    208         /* input argument src_blk is ignored */
    209         header->v3.acc_type = acc_type;
    210         header->v3.data_byte_len = data_byte_len;
    211         header->v3.dma = dma;
    212         header->v3.bank_ignore_mask = bank_ignore_mask;
    213     } else {
    214         header->v2.opcode = opcode;
    215         header->v2.dst_blk = dst_blk;
    216         header->v2.src_blk = src_blk;
    217         /* input argument acc_type is ignored */
    218         header->v2.data_byte_len = data_byte_len;
    219         /* input argument dma is ignored */
    220         header->v2.bank_ignore_mask = bank_ignore_mask;
    221     }
    222 }
    223 
    224 /*******************************************
    225 * @function soc_schan_header_cmd_get
    226 * purpose API to get the command header
    227 *
    228 * @param handle [in] unit
    229 * @param header [in] Populated Command header pointer
    230 * @param opcode [out] Opcode
    231 * @param dst_blk [out] Block ID
    232 * @param acc_type [out] Acc Type
    233 * @param data_byte_len [out] Dlen
    234 * @param dma, bank_ignore_mask [out] Misc Ctrl/ Status
    235 * @returns None
    236 *
    237 * @end
    238  */
    239 void
    240 soc_schan_header_cmd_get(int unit, schan_header_t *header, int *opcode,
    241                          int *dst_blk, int *src_blk, int *acc_type,
    242                          int *data_byte_len, int *dma,
    243                          uint32 *bank_ignore_mask)
    244 {
    245     if (soc_feature(unit, soc_feature_sbus_format_v4)) {
    246         if (opcode != NULL) {
    247             *opcode = header->v4.opcode;
    248         }
    249         if (dst_blk != NULL) {
    250             *dst_blk = soc_feature(unit, soc_feature_blkid_extended_format) ? (header->v4.dst_blk << 4) |(header->v4.acc_type>>1)  : header->v4.dst_blk;
    251         }
    252         if (src_blk != NULL) {
    253             *src_blk = 0;
    254         }
    255         if (acc_type != NULL) {
    256             *acc_type = (soc_feature(unit, soc_feature_blkid_extended_format)) ? 0  : header->v4.acc_type;
    257         }
    258         if (data_byte_len != NULL) {
    259             *data_byte_len = header->v4.data_byte_len;
    260         }
    261         if (dma != NULL) {
    262             *dma = header->v4.dma;
    263         }
    264         if (bank_ignore_mask != NULL) {
    265             *bank_ignore_mask = header->v4.bank_ignore_mask;
    266         }
    267     } else if (soc_feature(unit, soc_feature_new_sbus_format)) {
    268         if (opcode != NULL) {
    269             *opcode = header->v3.opcode;
    270         }
    271         if (dst_blk != NULL) {
    272             *dst_blk = header->v3.dst_blk;
    273         }
    274         if (src_blk != NULL) {
    275             *src_blk = 0;
    276         }
    277         if (acc_type != NULL) {
    278             *acc_type = header->v3.acc_type;
    279         }
    280         if (data_byte_len != NULL) {
    281             *data_byte_len = header->v3.data_byte_len;
    282         }
    283         if (dma != NULL) {
    284             *dma = header->v3.dma;
    285         }
    286         if (bank_ignore_mask != NULL) {
    287             *bank_ignore_mask = header->v3.bank_ignore_mask;
    288         }
    289     } else {
    290         if (opcode != NULL) {
    291             *opcode = header->v2.opcode;
    292         }
    293         if (dst_blk != NULL) {
    294             *dst_blk = header->v2.dst_blk;
    295         }
    296         if (src_blk != NULL) {
    297             *src_blk = header->v2.src_blk;
    298         }
    299         if (acc_type != NULL) {
    300             *acc_type = 0;
    301         }
    302         if (data_byte_len != NULL) {
    303             *data_byte_len = header->v2.data_byte_len;
    304         }
    305         if (dma != NULL) {
    306             *dma = 0;
    307         }
    308         if (bank_ignore_mask != NULL) {
    309             *bank_ignore_mask = header->v2.bank_ignore_mask;
    310         }
    311     }
    312 }
    313 
    314 /*******************************************
    315 * @function soc_schan_header_status_get
    316 * purpose API to get the header status
    317 *
    318 * @param handle [in] unit
    319 * @param header [in] Populated Command header pointer
    320 * @param opcode [out] Opcode
    321 * @param dst_blk [out] Block ID
    322 * @param acc_type [out] Acc Type
    323 * @param data_byte_len [out] Dlen
    324 * @param err, ecode, nack [out] Misc Ctrl/ Status
    325 * @returns None
    326 *
    327 * @end
    328  */
    329 void
    330 soc_schan_header_status_get(int unit, schan_header_t *header, int *opcode,
    331                             int *src_blk, int *data_byte_len,
    332                             int *err, int *ecode, int *nack)
    333 {
    334     if (soc_feature(unit, soc_feature_sbus_format_v4)) {
    335         *opcode = header->v4.opcode;
    336         if (src_blk != NULL) {
    337             *src_blk = 0;
    338         }
    339         if (data_byte_len != NULL) {
    340             *data_byte_len = header->v4.data_byte_len;
    341         }
    342         if (err != NULL) {
    343             *err = header->v4.err;
    344         }
    345         if (ecode != NULL) {
    346             *ecode = header->v4.ecode;
    347         }
    348         if (nack != NULL) {
    349             *nack = header->v4.nack;
    350         }
    351     } else if (soc_feature(unit, soc_feature_new_sbus_format)) {
    352         *opcode = header->v3.opcode;
    353         if (src_blk != NULL) {
    354             *src_blk = 0;
    355         }
    356         if (data_byte_len != NULL) {
    357             *data_byte_len = header->v3.data_byte_len;
    358         }
    359         if (err != NULL) {
    360             *err = header->v3.err;
    361         }
    362         if (ecode != NULL) {
    363             *ecode = header->v3.ecode;
    364         }
    365         if (nack != NULL) {
    366             *nack = header->v3.nack;
    367         }
    368     } else {
    369         *opcode = header->v2.opcode;
    370         if (src_blk != NULL) {
    371             *src_blk = header->v2.src_blk;
    372         }
    373         if (data_byte_len != NULL) {
    374             *data_byte_len = header->v2.data_byte_len;
    375         }
    376         if (err != NULL) {
    377             *err = header->v2.err;
    378         }
    379         if (ecode != NULL) {
    380             *ecode = header->v2.ecode;
    381         }
    382         if (nack != NULL) {
    383             *nack = header->v2.nack;
    384         }
    385     }
    386 }
    387 
    388 /*******************************************
    389 * @function soc_schan_dump
    390 * @Purpose Dump an S-Channel message for debugging
    391 *
    392 * @param unit [in] unit
    393 *
    394 * @returns SOC_E_NONE
    395 * @returns SOC_E_XXX
    396 *
    397 * @end
    398  */
    399 void
    400 soc_schan_dump(int unit, schan_msg_t *msg, int dwc)
    401 {
    402     char                buf[128];
    403     int                 i, j;
    404 
    405     if (soc_feature(unit, soc_feature_sbus_format_v4)) {
    406         uint32 dst_blk = msg->header.v4.dst_blk;
    407         uint32 acc_type = msg->header.v4.acc_type;
    408         uint32 block_id = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk << 4) | (acc_type >> 1) : dst_blk;
    409         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    410             (BSL_META_U(unit,
    411                             "  HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d "
    412                  "DLEN=%d ACC=%d DPORT=%d BLOCKID=%d OPC=%d=%s]\n"),
    413                  msg->header.v4.nack, msg->header.v4.bank_ignore_mask,
    414                  msg->header.v4.dma, msg->header.v4.ecode,
    415                  msg->header.v4.err, msg->header.v4.data_byte_len,
    416                  msg->header.v4.acc_type, msg->header.v4.dst_blk, block_id,
    417                  msg->header.v4.opcode,
    418                  soc_schan_op_name(msg->header.v4.opcode)));
    419     } else if (soc_feature(unit, soc_feature_new_sbus_format)) {
    420         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    421             (BSL_META_U(unit,
    422                             "  HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d "
    423                  "DLEN=%d ACC=%d DPORT=%d OPC=%d=%s]\n"),
    424                  msg->header.v3.nack, msg->header.v3.bank_ignore_mask,
    425                  msg->header.v3.dma, msg->header.v3.ecode,
    426                  msg->header.v3.err, msg->header.v3.data_byte_len,
    427                  msg->header.v3.acc_type, msg->header.v3.dst_blk,
    428                  msg->header.v3.opcode,
    429                  soc_schan_op_name(msg->header.v3.opcode)));
    430     } else {
    431         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    432             (BSL_META_U(unit,
    433                             "  HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d "
    434                  "DLEN=%d SPORT=%d DPORT=%d OPC=%d=%s]\n"),
    435                  msg->header.v2.nack, msg->header.v2.bank_ignore_mask,
    436                  msg->header.v2.dma, msg->header.v2.ecode,
    437                  msg->header.v2.err, msg->header.v2.data_byte_len,
    438                  msg->header.v2.src_blk, msg->header.v2.dst_blk,
    439                  msg->header.v2.opcode,
    440                  soc_schan_op_name(msg->header.v2.opcode)));
    441     }
    442 
    443 #ifdef BCM_TRIUMPH_SUPPORT
    444     if (soc_feature(unit, soc_feature_generic_table_ops) &&
    445         ((msg->header.v2.opcode == TABLE_INSERT_DONE_MSG) ||
    446          (msg->header.v2.opcode == TABLE_DELETE_DONE_MSG) ||
    447          (msg->header.v2.opcode == TABLE_LOOKUP_DONE_MSG))) {
    448         if (soc_feature(unit, soc_feature_new_sbus_format) &&
    449             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
    450             LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    451                 (BSL_META_U(unit,
    452                                 "  RSP[TYPE=%d=%s ERR_INFO=%d=%s "
    453                      "INDEX=0x%05x]\n"),
    454                      msg->genresp_v2.response.type,
    455                      soc_schan_gen_resp_type_name(msg->genresp_v2.response.type),
    456                      msg->genresp_v2.response.err_info,
    457                      soc_schan_gen_resp_err_name(msg->genresp_v2.response.err_info),
    458                      msg->genresp_v2.response.index));
    459         } else {
    460             LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    461                 (BSL_META_U(unit,
    462                                 "  RSP[SRC=%d TYPE=%d=%s ERR_INFO=%d=%s "
    463                      "INDEX=0x%05x]\n"),
    464                      msg->genresp.response.src,
    465                      msg->genresp.response.type,
    466                      soc_schan_gen_resp_type_name(msg->genresp.response.type),
    467                      msg->genresp.response.err_info,
    468                      soc_schan_gen_resp_err_name(msg->genresp.response.err_info),
    469                      msg->genresp.response.index));
    470         }
    471     }
    472 #endif /* BCM_TRIUMPH_SUPPORT */
    473 
    474     assert(dwc <= CMIC_SCHAN_WORDS(unit));
    475 
    476     for (i = 0; i < dwc; i += 4) {
    477         buf[0] = 0;
    478 
    479         for (j = i; j < i + 4 && j < dwc; j++) {
    480             sal_sprintf(buf + sal_strlen(buf),
    481                         " DW[%2d]=0x%08x", j, msg->dwords[j]);
    482         }
    483 
    484         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    485             (BSL_META_U(unit, " %s\n"), buf));
    486     }
    487 }
    488 /*******************************************
    489 * @function soc_schan_override_enable
    490 * @Purpose Enable schan override
    491 *
    492 * @param unit [in] unit
    493 *
    494 * @returns SOC_E_NONE
    495 * @returns SOC_E_XXX
    496 *
    497 * @end
    498  */
    499 
    500 #define SOC_SCHAN_WB_TIME_OUT            (5000000) /*5 sec*/
    501 int
    502 soc_schan_override_enable(int unit)
    503 {
    504     if (unit < 0 || unit >= SOC_MAX_NUM_DEVICES) {
    505         return SOC_E_UNIT;
    506     }
    507     if (!SOC_HW_ACCESS_DISABLE(unit)) {
    508         return SOC_E_NONE;
    509     }
    510     if (SOC_WARM_BOOT(unit)) {
    511         if (sal_mutex_take(SOC_CONTROL(unit)->schan_wb_mutex,
    512                            SOC_SCHAN_WB_TIME_OUT)) {
    513             LOG_ERROR(BSL_LS_SOC_SCHAN,
    514                       (BSL_META_U(unit,
    515                                   "Failed to take schan_wb_mutex.\n")));
    516             return SOC_E_INTERNAL;
    517         }
    518         SOC_CONTROL(unit)->schan_wb_thread_id = sal_thread_self();
    519     }
    520 
    521     return SOC_E_NONE;
    522 }
    523 
    524 /*******************************************
    525 * @function soc_schan_override_disable
    526 * @Purpose Disable schan override
    527 *
    528 * @param unit [in] unit
    529 *
    530 * @returns SOC_E_NONE
    531 * @returns SOC_E_XXX
    532 *
    533 * @end
    534  */
    535 int
    536 soc_schan_override_disable(int unit)
    537 {
    538     if (unit < 0 || unit >= SOC_MAX_NUM_DEVICES) {
    539         return SOC_E_UNIT;
    540     }
    541     if (SOC_CONTROL(unit)->schan_wb_thread_id == sal_thread_self()) {
    542         SOC_CONTROL(unit)->schan_wb_thread_id = SAL_THREAD_ERROR;
    543         if (sal_mutex_give(SOC_CONTROL(unit)->schan_wb_mutex)) {
    544             LOG_ERROR(BSL_LS_SOC_SCHAN,
    545                       (BSL_META_U(unit,
    546                                   "Failed to release schan_wb_mutex.\n")));
    547             return SOC_E_INTERNAL;
    548         }
    549     }
    550 
    551     return SOC_E_NONE;
    552 }
    553 
    554 /*******************************************
    555 * @function soc_schan_op
    556 * purpose cmic SCHAN operation
    557 *
    558 * @param unit [in] unit
    559 * @param msg [in] schan_msg_t
    560 * @param dwc_write [in] Write messages
    561 * @param dwc_write [in] read messages
    562 * @param intr [in] use interrupt
    563 *
    564 * @returns SOC_E_NONE
    565 * @returns SOC_E_XXX
    566 *
    567 * @comments  This calls appropriate function based on CMIC type
    568 * Writes a message of dwc_write DWORDs from msg to the S-Channel, waits
    569 * for the operation to complete, then reads dwc_read DWORDs from the
    570 * channel into msg.  If there is no return data, use dwc_read = 0.
    571 *
    572 * On platforms where it is appropriate, the S-Channel is locked during
    573 * the operation to prevent multiple tasks trying to use the S-Channel
    574 * simultaneously.
    575 *
    576 * Return value is negative on error, 0 on success.
    577 *
    578 * If intr is true, this routine goes to sleep until an S-Channel
    579 * completion interrupt wakes it up.  Otherwise, it polls for the done
    580 * bit.  NOTE: if schanIntrEnb is false, intr is always overridden to 0.
    581 *
    582 * Polling is more CPU efficient for most operations since they complete
    583 * much faster than the interrupt processing time would take.  However,
    584 * due to the chip design, some operations such as ARL insert and delete
    585 * may have unbounded response time.  In this case, the interrupt should
    586 * be used.  The worst case we have seen is 1 millisec when the switch
    587 * is passing max traffic with random addresses at min packet size.
    588 *
    589 * @end
    590  */
    591 int
    592 soc_schan_op(int unit,
    593              schan_msg_t *msg,
    594              int dwc_write, int dwc_read,
    595              int intr)
    596 {
    597     int rv;
    598 
    599     if (_soc_schan_drv[unit].soc_schan_op == NULL) {
    600         LOG_FATAL(BSL_LS_SOC_SCHAN, (BSL_META_U(unit,
    601                   "SOC_SCHAN_OP() function is undefined\n")));
    602         rv = SOC_E_FAIL;
    603     } else {
    604         rv =  _soc_schan_drv[unit].soc_schan_op(unit, msg, dwc_write, dwc_read, intr);
    605     }
    606 
    607     return rv;
    608 }
    609 
    610 /*******************************************
    611 * @function _soc_schan_check_hw_access_disabled
    612 * @Purpose return TRUE if hardware access is disabled
    613 *
    614 * @param unit [in] unit
    615 * @param msg [in] pointer to Type <schan_msg_t>
    616 * @param dwc_read [out] pointer to status
    617 *
    618 * @returns TRUE or FALSE
    619 *
    620 * @comments If hardware access is disabled, this
    621 * should return TRUE and set *rv to an error code that
    622 * will be passed up to the caller.  Otherwise, return FALSE
    623 * and do not alter *rv.
    624 
    625 * @end
    626  */
    627 STATIC int
    628 _soc_schan_check_hw_access_disabled(int unit, schan_msg_t *msg, int *rv)
    629 {
    630     if (SOC_HW_ACCESS_DISABLE(unit)) {
    631         switch (msg->header.v2.opcode) {
    632         case WRITE_MEMORY_CMD_MSG:
    633             *rv = SOC_E_NONE;
    634             return TRUE;
    635         case WRITE_REGISTER_CMD_MSG:
    636             msg->header.v2.opcode = WRITE_REGISTER_ACK_MSG;
    637             *rv = SOC_E_NONE;
    638             return TRUE;
    639         case ARL_INSERT_CMD_MSG:
    640             msg->header.v2.opcode = ARL_INSERT_DONE_MSG;
    641             *rv = SOC_E_NONE;
    642             return TRUE;
    643         case ARL_DELETE_CMD_MSG:
    644             msg->header.v2.opcode = ARL_DELETE_DONE_MSG;
    645             *rv = SOC_E_NONE;
    646             return TRUE;
    647         case L3_INSERT_CMD_MSG:
    648             msg->header.v2.opcode = L3_INSERT_DONE_MSG;
    649             *rv = SOC_E_NONE;
    650             return TRUE;
    651         case L3_DELETE_CMD_MSG:
    652             msg->header.v2.opcode = L3_DELETE_DONE_MSG;
    653             *rv = SOC_E_NONE;
    654             return TRUE;
    655         case INIT_CFAP_MSG:
    656             *rv = SOC_E_NONE;
    657             return TRUE;
    658         case READ_REGISTER_CMD_MSG:
    659             if (SOC_IS_DETACHING(unit)) {
    660                 sal_memset(msg->bytes, 0,
    661                            sizeof(uint32) * CMIC_SCHAN_WORDS_ALLOC);
    662                 msg->header.v2.opcode = READ_REGISTER_ACK_MSG;
    663                 *rv = SOC_E_NONE;
    664                 return TRUE;
    665             }
    666             break;
    667         case READ_MEMORY_CMD_MSG:
    668             if (SOC_IS_DETACHING(unit)) {
    669                 sal_memset(msg->bytes, 0,
    670                            sizeof(uint32) * CMIC_SCHAN_WORDS_ALLOC);
    671                 msg->header.v2.opcode = READ_MEMORY_ACK_MSG;
    672                 *rv = SOC_E_NONE;
    673                 return TRUE;
    674             }
    675             break;
    676         case L2_LOOKUP_CMD_MSG:
    677             if (SOC_IS_DETACHING(unit)) {
    678                 msg->header.v2.opcode = L2_LOOKUP_ACK_MSG;
    679                 *rv = SOC_E_NOT_FOUND;
    680                 return TRUE;
    681             }
    682             break;
    683         case L3X2_LOOKUP_CMD_MSG:
    684             if (SOC_IS_DETACHING(unit)) {
    685                 msg->header.v2.opcode = L3X2_LOOKUP_ACK_MSG;
    686                 *rv = SOC_E_NOT_FOUND;
    687                 return TRUE;
    688             }
    689             break;
    690         case ARL_LOOKUP_CMD_MSG:
    691         case L3_LOOKUP_CMD_MSG:
    692             if (SOC_IS_DETACHING(unit)) {
    693                 *rv = SOC_E_NOT_FOUND;
    694                 return TRUE;
    695             }
    696             break;
    697         case TABLE_INSERT_CMD_MSG:
    698             msg->header.v2.opcode = TABLE_INSERT_DONE_MSG;
    699             *rv = SOC_E_NONE;
    700             return TRUE;
    701         case TABLE_DELETE_CMD_MSG:
    702             msg->header.v2.opcode = TABLE_DELETE_DONE_MSG;
    703             *rv = SOC_E_NONE;
    704             return TRUE;
    705         case FIFO_POP_CMD_MSG:
    706             msg->header.v2.opcode = FIFO_POP_DONE_MSG;
    707             *rv = SOC_E_NONE;
    708             return TRUE;
    709         case FIFO_PUSH_CMD_MSG:
    710             msg->header.v2.opcode = FIFO_PUSH_DONE_MSG;
    711             *rv = SOC_E_NONE;
    712             return TRUE;
    713         default:
    714             break;
    715         }
    716     }
    717 
    718     return FALSE;
    719 }
    720 
    721 /*******************************************
    722 * @function _soc_schan_op_arad_sanity_check
    723 * purpose API to perform sanity check for ARAD
    724 *
    725 * @param unit [in] unit
    726 * @param msg [in] pointer to Type <schan_msg_t>
    727 * @param dwc_write [in] write
    728 * @param dwc_read [in] read
    729 *
    730 * @returns SOC_E_NONE
    731 * @returns SOC_E_XXX
    732 * @end
    733  */
    734 
    735 /*******************************************
    736 * @function soc_schan_op_sanity_check
    737 * purpose API to perform sanity checks
    738 *
    739 * @param unit [in] unit
    740 * @param msg [in] pointer to Type <schan_msg_t>
    741 * @param dwc_write [in] write
    742 * @param dwc_read [in] read
    743 * @param dwc_read [out] pointer to status
    744 *
    745 * @returns TRUE if the caller should abort the call and return *rv up the stack.
    746 * @returns FALSE if the caller should continue as normal.
    747 *
    748 * @comments First, check that writing is allowed:
    749 *    If (device is ARAD) and (opcode is not a READ command) and (override flag is off)
    750 *    Then: writing is not allowed.
    751 *
    752 * Then, assert sanity checks.
    753 * Finally, log the message that schan access is beginning
    754 *
    755 * @end
    756  */
    757 int
    758 soc_schan_op_sanity_check(int unit, schan_msg_t *msg, int dwc_write,
    759                            int dwc_read, int *rv)
    760 {
    761     *rv = SOC_E_NONE;
    762 
    763     assert(! sal_int_context());
    764     assert(dwc_write <= CMIC_SCHAN_WORDS(unit));
    765     assert(dwc_read <= CMIC_SCHAN_WORDS(unit));
    766 
    767     /* don't perform check for DNX devices as they undergo different check */
    768     if (!SOC_IS_DNX(unit) && !SOC_IS_DNXF(unit)) {
    769         if (_soc_schan_check_hw_access_disabled(unit, msg, rv) == TRUE) {
    770             return TRUE;
    771         }
    772     }
    773 
    774     if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) {
    775         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    776             (BSL_META_U(unit,
    777                             "S-CHANNEL %s: (unit %d)\n"),
    778                  soc_schan_op_name(msg->header.v2.opcode), unit));
    779         soc_schan_dump(unit, msg, dwc_write);
    780     }
    781 
    782     return FALSE;
    783 }
    784 
    785 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN)
    786 
    787 /*******************************************
    788 * @function _soc_schan_op_wrapper_plibde
    789 * purpose  this is called with plisim enabled
    790 *
    791 * @param unit [in] unit
    792 * @param msg [in] schan_msg_t
    793 * @param dwc_write [in] Write messages
    794 * @param dwc_write [in] read messages
    795 * @param intr [in] use interrupt
    796 *
    797 * @returns SOC_E_NONE
    798 * @returns SOC_E_XXX
    799 *
    800 * @end
    801  */
    802 STATIC int
    803 _soc_schan_op_wrapper_plibde(int unit, schan_msg_t *msg, int dwc_write,
    804                             int dwc_read, int intr)
    805 {
    806     int rv;
    807 
    808     if (soc_schan_op_sanity_check(unit, msg, dwc_write, dwc_read, &rv) == TRUE) {
    809         return rv;
    810     }
    811     /* Back door into the simulation to perform direct SCHANNEL operations */
    812     if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) {
    813         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    814             (BSL_META_U(unit,
    815                             "S-CHANNEL %s: (unit %d)\n"),
    816                  soc_schan_op_name(msg->header.v2.opcode), unit));
    817         soc_schan_dump(unit, msg, dwc_write);
    818     }
    819 
    820     rv = plibde_schan_op(unit, msg, dwc_write, dwc_read);
    821 
    822     if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) {
    823         soc_schan_dump(unit, msg, dwc_read);
    824     }
    825 
    826     return rv;
    827 }
    828 #endif
    829 
    830 #ifdef INCLUDE_RCPU
    831 
    832 /*******************************************
    833 * @function _soc_schan_op_wrapper_rcpu
    834 * purpose  Called if rcpu schan callback is registered
    835 *
    836 * @param unit [in] unit
    837 * @param msg [in] schan_msg_t
    838 * @param dwc_write [in] Write messages
    839 * @param dwc_write [in] read messages
    840 * @param intr [in] use interrupt
    841 *
    842 * @returns SOC_E_NONE
    843 * @returns SOC_E_XXX
    844 *
    845 * @end
    846  */
    847 STATIC int
    848 _soc_schan_op_wrapper_rcpu(int unit, schan_msg_t *msg, int dwc_write,
    849                           int dwc_read, int intr)
    850 {
    851     if (SOC_CONTROL(unit)->soc_rcpu_schan_op == NULL) {
    852         LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit,
    853                   "No soc_rcpu_schan_op callback defined\n")));
    854         return SOC_E_FAIL;
    855     }
    856 
    857     return SOC_CONTROL(unit)->soc_rcpu_schan_op(unit, msg, dwc_write, dwc_read);
    858 }
    859 #endif /* INCLUDE_RCPU */
    860 
    861 
    862 /*******************************************
    863 * @function soc_schan_timeout_check
    864 * @Purpose enable special processing for timeout
    865 *
    866 * @param unit [in] unit
    867 * @param msg [in] pointer to Type <schan_msg_t>
    868 * @param dwc_read [out] pointer to status
    869 *
    870 * @returns TRUE or FALSE
    871 *
    872 * @end
    873  */
    874 int
    875 soc_schan_timeout_check(int unit, int *rv, schan_msg_t *msg, int cmc, int ch)
    876 {
    877     if (*rv != SOC_E_TIMEOUT) {
    878         SOC_CONTROL(unit)->stat.schan_op++;
    879         return FALSE;
    880     }
    881 
    882     if (SOC_IS_TRIUMPH3(unit) && msg->header.v3.opcode == WRITE_REGISTER_CMD_MSG) {
    883         if ((msg->writecmd.address == 0x02029700) &&
    884             (msg->writecmd.header.v3.dst_blk >= 0x8  && msg->writecmd.header.v3.dst_blk <= 0xf)) {
    885             *rv = SOC_E_NONE;
    886              SOC_CONTROL(unit)->stat.schan_op++;
    887         }
    888     } else {
    889         LOG_WARN(BSL_LS_SOC_SCHAN,
    890             (BSL_META_U(unit,
    891                 "soc_schan_op: operation attempt timed out\n")));
    892         SOC_CONTROL(unit)->stat.err_sc_tmo++;
    893         if (_soc_schan_drv[unit].soc_schan_reset != NULL) {
    894             _soc_schan_drv[unit].soc_schan_reset(unit, cmc, ch);
    895         }
    896         return TRUE;
    897     }
    898 
    899     return FALSE;
    900 }
    901 
    902 /*******************************************
    903 * @function _soc_schan_control_init
    904 * purpose API to Initialize and SCHAN control
    905 *
    906 * @param unit [in] unit
    907 *
    908 * @returns SOC_E_NONE
    909 * @returns SOC_E_XXX
    910 *
    911 * @end
    912  */
    913 STATIC int _soc_schan_control_init(int unit)
    914 {
    915     int rv = SOC_E_NONE;
    916     int cmc;
    917 
    918     SOC_SCHAN_CONTROL(unit).schanTimeout = &SOC_CONTROL(unit)->schanTimeout;
    919     SOC_SCHAN_CONTROL(unit).schanIntrEnb = &SOC_CONTROL(unit)->schanIntrEnb;
    920     for (cmc = 0; cmc <= SOC_CMCS_NUM_MAX; cmc++) {
    921         SOC_SCHAN_CONTROL(unit).schanIntr[cmc] = &SOC_CONTROL(unit)->schanIntr[cmc];
    922         SOC_SCHAN_CONTROL(unit).schan_result[cmc] = &SOC_CONTROL(unit)->schan_result[cmc];
    923     }
    924 
    925     return rv;
    926 }
    927 /*******************************************
    928 * @function soc_schan_init
    929 * purpose API to Initialize and config SCHAN
    930 *
    931 * @param unit [in] unit
    932 *
    933 * @returns SOC_E_NONE
    934 * @returns SOC_E_XXX
    935 *
    936 * @end
    937  */
    938 int soc_schan_init(int unit)
    939 {
    940     int rv = SOC_E_NONE;
    941 
    942     SOC_IF_ERROR_RETURN(_soc_schan_control_init(unit));
    943 
    944 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN)
    945     if ((SAL_BOOT_PLISIM || SAL_BOOT_BCMSIM)) {
    946         _soc_schan_drv[unit].soc_schan_op = _soc_schan_op_wrapper_plibde;
    947         return rv;
    948     }
    949 #endif
    950 
    951 #ifdef INCLUDE_RCPU
    952     if (SOC_IS_RCPU_ONLY(unit) || SOC_IS_RCPU_UNIT(unit)) {
    953        _soc_schan_drv[unit].soc_schan_op = _soc_schan_op_wrapper_rcpu;
    954        return rv;
    955     }
    956 #endif
    957 
    958 #ifdef BCM_CMICX_SUPPORT
    959    if (soc_feature(unit, soc_feature_cmicx)) {
    960        rv = soc_cmicx_schan_init(unit, &_soc_schan_drv[unit]);
    961        return rv;
    962    }
    963 #endif
    964 
    965 #if defined(BCM_CMICM_SUPPORT)
    966     if (soc_feature(unit, soc_feature_cmicm)) {
    967         rv = soc_cmicm_schan_init(unit, &_soc_schan_drv[unit]);
    968         return rv;
    969     }
    970 #endif
    971 
    972 
    973    rv = soc_cmice_schan_init(unit, &_soc_schan_drv[unit]);
    974 
    975 
    976     return rv;
    977 }
    978 
    979 /*******************************************
    980 * @function soc_schan_deinit
    981 * purpose SDK-7 API to de-Initialize SCHAN
    982 *
    983 * @param unit [in] unit
    984 *
    985 * @returns SOC_E_NONE
    986 * @returns SOC_E_XXX
    987 *
    988 * @end
    989  */
    990 int soc_schan_deinit(int unit)
    991 {
    992     int rv = SOC_E_NONE;
    993 
    994     if (_soc_schan_drv[unit].soc_schan_deinit) {
    995         rv = _soc_schan_drv[unit].soc_schan_deinit(unit);
    996     }
    997 
    998     _soc_schan_drv[unit].soc_schan_deinit = NULL;
    999     _soc_schan_drv[unit].soc_schan_op = NULL;
   1000     _soc_schan_drv[unit].soc_schan_reset = NULL;
   1001 
   1002     return rv;
   1003 }
   1004 /*
   1005  * Procedures related to PEM block access.
   1006  * {
   1007  */
   1008 /*
   1009  * phy_mem_read
   1010  * phy_mem_write
   1011  *
   1012  * Send/ (rcv) msg to/(from) the S-Channel to carry out PEM operation
   1013  * as per '*mem' and '*entry_data'.
   1014  * Wait for interrupt to indicate operation to complete. For 'read',
   1015  * response data is on '*entry_data'.
   1016  *
   1017  * Access memory or register depending on the LS 16 bis of mem->mem_address
   1018  * (non-zero for 'memory').
   1019  *
   1020  * S-Channel is locked during the operation to prevent multiple tasks
   1021  * trying to use the S-Channel simultaneously.
   1022  *
   1023  * Return value is negative on error, 0 (SOC_E_NONE) on success.
   1024  *
   1025  * NOTE: If SOC_CONTROL(unit)->schanIntrEnb is false, interrupt operation
   1026  * is overridden in favour of polling.
   1027  *
   1028  * NOTE: Within 'header', this procedure uses header.v4
   1029  *
   1030  * Ensure that a SOC_CONTROL(unit)->schan_op function pointer is defined for this
   1031  * unit. If not, an error is flagged.
   1032  *
   1033  * See also:
   1034  *   soc_schan_op(), _soc_schan_op_cmicm(), soc_direct_memreg_get(),
   1035  *   soc_direct_memreg_set(), schan_header_t
   1036  */
   1037 int phy_mem_read(int unit, phy_mem_t *mem, void *entry_data)
   1038 {
   1039   int ret ;
   1040   int is_mem ;
   1041   uint32 addr, data_longs_to_read ;
   1042   uint32 mask = 0xFFFF0000 ;
   1043   /*
   1044    * Access memory or register depending on the LS 16 bis.
   1045    */
   1046   is_mem = ( (mem->mem_address & mask) != 0 ) ? 1 : 0;
   1047   /*
   1048    * Always request an integer number of longs (expressed in bytes).
   1049    */
   1050   data_longs_to_read = BITS2WORDS(mem->mem_width_in_bits) ;
   1051   /*
   1052     * row_index was removed from phy_mem_t (see SDK-111156).
   1053     * Need updated ucode.
   1054     */
   1055   addr = mem->mem_address;
   1056 
   1057   ret = soc_direct_memreg_get(unit, mem->block_identifier, addr, data_longs_to_read,is_mem, (uint32 *)entry_data) ;
   1058   return (ret) ;
   1059 }
   1060 int phy_mem_write(int unit, phy_mem_t *mem, void *entry_data)
   1061 {
   1062   int ret ;
   1063   int is_mem ;
   1064   uint32 addr, data_longs_to_write ;
   1065   uint32 mask = 0xFFFF0000 ;
   1066   /*
   1067    * Access memory or register depending on the LS 16 bis.
   1068    */
   1069   is_mem = ( (mem->mem_address & mask) != 0 ) ? 1 : 0;
   1070   /*
   1071    * Always request an integer number of longs (expressed in bytes).
   1072    */
   1073   data_longs_to_write = BITS2WORDS(mem->mem_width_in_bits) ;
   1074   /*
   1075     * row_index was removed from phy_mem_t (see SDK-111156).
   1076     * Need updated ucode.
   1077     */
   1078   addr = mem->mem_address;
   1079   ret = soc_direct_memreg_set(unit, mem->block_identifier, addr, data_longs_to_write, is_mem, (uint32 *)entry_data) ;
   1080   return (ret) ;
   1081 }
   1082 
   1083 /*
   1084  * }
   1085  */