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

cmice_schan.c (10845B)


      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  *  CMICE 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 #include <soc/drv.h>
     15 #include <soc/debug.h>
     16 #include <soc/cm.h>
     17 #include <soc/error.h>
     18 #include <soc/cmic.h>
     19 #include <soc/schanmsg_internal.h>
     20 
     21 
     22 #ifdef BCM_TRIUMPH2_SUPPORT
     23 #include <soc/triumph2.h>
     24 #endif
     25 #ifdef BCM_TRIDENT_SUPPORT
     26 #include <soc/trident.h>
     27 #endif
     28 
     29 #include <soc/cmicm.h>
     30 
     31 /*******************************************
     32 * @function _soc_cmice_schan_reset
     33 * @Purpose Resets the CMICE S-Channel interface.
     34 *
     35 * @param unit [in] unit
     36 *
     37 * @returns None
     38 * @comments This is required when we sent
     39 * a message and did not receive a response after the poll count was
     40 * exceeded.
     41 * @end
     42  */
     43 STATIC void
     44 _soc_cmice_schan_reset(int unit, int cmc, int ch)
     45 {
     46     uint32 val;
     47 
     48     val = soc_pci_read(unit, CMIC_CONFIG);
     49 
     50     /* Toggle S-Channel abort bit in CMIC_CONFIG register */
     51     soc_pci_write(unit, CMIC_CONFIG, val | CC_SCHAN_ABORT);
     52 
     53     SDK_CONFIG_MEMORY_BARRIER;
     54 
     55     soc_pci_write(unit, CMIC_CONFIG, val);
     56 
     57     SDK_CONFIG_MEMORY_BARRIER;
     58 
     59     if (SAL_BOOT_QUICKTURN) {
     60         /* Give Quickturn at least 2 cycles */
     61         sal_usleep(10 * MILLISECOND_USEC);
     62     }
     63 }
     64 
     65 /*******************************************
     66 * @function _soc_cmice_schan_dpp_err_check
     67 * purpose dpp error check
     68 *
     69 * @param unit [in] unit
     70 *
     71 * @returns SOC_E_NONE
     72 * @returns SOC_E_XXX
     73 *
     74 * @comments   On DPP and DFE devices (without CMIC-M)
     75 * but with the schan_err_check feature,
     76 * exercise the feature and check for schan errors.
     77 
     78 * @end
     79  */
     80 STATIC int
     81 _soc_cmice_schan_dpp_err_check(int unit)
     82 {
     83     int rv = SOC_E_NONE;
     84 
     85 #if defined(BCM_SAND_SUPPORT)
     86     if(soc_feature(unit, soc_feature_schan_err_check)) {
     87         uint32 schan_err, err_bit = 0;
     88 
     89         schan_err = soc_pci_read(unit, CMIC_SCHAN_ERR);
     90         err_bit = soc_reg_field_get(unit, CMIC_SCHAN_ERRr, schan_err, ERRBITf);
     91 
     92         if (err_bit) {
     93             soc_pci_write(unit, CMIC_SCHAN_ERR, 0);
     94             rv = SOC_E_FAIL;
     95             LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit,
     96                       "  ERRBIT received in CMIC_SCHAN_ERR.\n")));
     97         }
     98     }
     99 #endif /* BCM_SAND_SUPPORT */
    100 
    101     return rv;
    102 }
    103 
    104 /*******************************************
    105 * @function _soc_cmice_schan_intr_wait
    106 * purpose interrupt wait to complete SCHAN operation
    107 *
    108 * @param unit [in] unit
    109 *
    110 * @returns SOC_E_NONE
    111 * @returns SOC_E_XXX
    112 *
    113 * @comments  Called by schan_op_* functions.
    114 * wait on a schan interrupt.  When schan interrupts are disabled,
    115 * _soc_cmice_schan_poll_wait is called instead.
    116 
    117 * @end
    118  */
    119 STATIC int
    120 _soc_cmice_schan_intr_wait(int unit)
    121 {
    122     int rv = SOC_E_NONE;
    123 
    124     soc_intr_enable(unit, IRQ_SCH_MSG_DONE);
    125 
    126     if (sal_sem_take(SOC_CONTROL(unit)->schanIntr[SOC_PCI_CMC(unit)],
    127                       SOC_CONTROL(unit)->schanTimeout) != 0) {
    128         rv = SOC_E_TIMEOUT;
    129     } else {
    130         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    131                  (BSL_META_U(unit,
    132                              "  Interrupt received\n")));
    133 
    134         if (SOC_CONTROL(unit)->schan_result[SOC_PCI_CMC(unit)] & SC_MSG_NAK_TST) {
    135             rv = SOC_E_FAIL;
    136         }
    137         if (soc_feature(unit, soc_feature_schan_hw_timeout)) {
    138             if (SOC_CONTROL(unit)->schan_result[SOC_PCI_CMC(unit)] & SC_MSG_TIMEOUT_TST) {
    139                 rv = SOC_E_TIMEOUT;
    140             }
    141         }
    142 
    143         SOC_IF_ERROR_RETURN(_soc_cmice_schan_dpp_err_check(unit));
    144     }
    145 
    146     soc_intr_disable(unit, IRQ_SCH_MSG_DONE);
    147 
    148     return rv;
    149 }
    150 
    151 /*******************************************
    152 * @function _soc_cmice_schan_tr2_check_ser_nack
    153 * purpose check for a ser and nack.
    154 *
    155 * @param unit [in] unit
    156 * @param msg [in] schan_msg_t
    157 *
    158 * @returns SOC_E_NONE
    159 * @returns SOC_E_XXX
    160 *
    161 * @comments  On Triumph2 devices, enable special processing in
    162 * response to schan NACK responses.  For table insert/lookup/delete,
    163 * if a parity error appears, send a NACK.  For memory/register reads,
    164 * send a NACK regardless.
    165 
    166 * @end
    167  */
    168 
    169 STATIC int
    170 _soc_cmice_schan_tr2_check_ser_nack(int unit, schan_msg_t *msg)
    171 {
    172 #ifdef BCM_TRIUMPH2_SUPPORT
    173     schan_msg_t resp_msg;
    174 
    175     /* This is still the input opcode */
    176     resp_msg.dwords[1] =
    177         soc_pci_read(unit, CMIC_SCHAN_MESSAGE(unit, 1));
    178 
    179     switch (msg->header.v2.opcode) {
    180         case TABLE_INSERT_CMD_MSG:
    181         case TABLE_DELETE_CMD_MSG:
    182         case TABLE_LOOKUP_CMD_MSG:
    183             if (SCHAN_GEN_RESP_TYPE_ERROR !=
    184                 resp_msg.genresp.response.type) {
    185                 /* Not a parity error */
    186                 break;
    187             }
    188             /* Else fallthru */
    189         case READ_MEMORY_CMD_MSG:
    190         case READ_REGISTER_CMD_MSG:
    191             {
    192                 int dst_blk, opcode;
    193                 soc_schan_header_cmd_get(unit, &msg->header, &opcode, &dst_blk,
    194                     NULL, NULL, NULL, NULL, NULL);
    195 
    196                 (void)soc_ser_mem_nack(INT_TO_PTR(unit),
    197                     INT_TO_PTR(msg->gencmd.address),
    198                     INT_TO_PTR(dst_blk),
    199                     opcode == READ_REGISTER_CMD_MSG ? INT_TO_PTR(1) : 0, 0);
    200             }
    201             break;
    202         default:
    203             break;
    204     }
    205 #endif /* BCM_TRIUMPH2_SUPPORT */
    206 
    207     return SOC_E_NONE;
    208 }
    209 
    210 /*******************************************
    211 * @function _soc_cmice_schan_check_ser_parity
    212 * purpose check for a ser parity error.
    213 *
    214 * @param unit [in] unit
    215 * @param schanCtrl [in] schan control
    216 * @param msg [in] schan_msg_t
    217 *
    218 * @returns SOC_E_NONE
    219 * @returns SOC_E_XXX
    220 *
    221 * @end
    222  */
    223 STATIC int
    224 _soc_cmice_schan_check_ser_parity(int unit, uint32 *schanCtrl, schan_msg_t *msg)
    225 {
    226     int rv = SOC_E_NONE;
    227 
    228 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIDENT_SUPPORT)
    229     if ((*schanCtrl & SC_MSG_SER_CHECK_FAIL_TST) &&
    230         soc_feature(unit, soc_feature_ser_parity)) {
    231             rv = SOC_E_FAIL;
    232             LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit,
    233                       "  SER Parity Check Error.\n")));
    234             sal_dpc(soc_ser_fail, INT_TO_PTR(unit),
    235                     INT_TO_PTR(msg->gencmd.address), 0, 0, 0);
    236     }
    237 #endif /* BCM_TRIUMPH2_SUPPORT, BCM_TRIDENT_SUPPORT */
    238 
    239     return rv;
    240 }
    241 
    242 
    243 /*******************************************
    244 * @function _soc_cmice_schan_poll_wait
    245 * purpose POLL wait to complete cmice SCHAN operation
    246 *
    247 * @param unit [in] unit
    248 * @param msg [in] schan_msg_t
    249 *
    250 * @returns SOC_E_NONE
    251 * @returns SOC_E_XXX
    252 *
    253 * @end
    254 * @comments  Called by schan_cmice_schan_op function.
    255 * In case interrupts are disabled, wait on a schan response via polling.
    256  */
    257 STATIC int
    258 _soc_cmice_schan_poll_wait(int unit, schan_msg_t *msg)
    259 {
    260     int rv = SOC_E_NONE;
    261     soc_timeout_t to;
    262     uint32 schanCtrl;
    263 
    264     soc_timeout_init(&to,  SOC_CONTROL(unit)->schanTimeout, 100);
    265 
    266     while (((schanCtrl = soc_pci_read(unit, CMIC_SCHAN_CTRL)) &
    267             SC_MSG_DONE_TST) == 0) {
    268         if (soc_timeout_check(&to)) {
    269             rv = SOC_E_TIMEOUT;
    270             break;
    271         }
    272     }
    273 
    274     if (rv == SOC_E_NONE) {
    275         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    276                  (BSL_META_U(unit,
    277                              "  Done in %d polls\n"), to.polls));
    278     }
    279 
    280     if (schanCtrl & SC_MSG_NAK_TST) {
    281         rv = SOC_E_FAIL;
    282 #ifdef _SER_TIME_STAMP
    283         ser_time_1 = sal_time_usecs();
    284 #endif
    285         LOG_VERBOSE(BSL_LS_SOC_SCHAN,
    286                  (BSL_META_U(unit,
    287                              "  NAK received from SCHAN.\n")));
    288 
    289         SOC_IF_ERROR_RETURN(_soc_cmice_schan_tr2_check_ser_nack(unit, msg));
    290     }
    291 
    292     SOC_IF_ERROR_RETURN(_soc_cmice_schan_check_ser_parity(unit, &schanCtrl, msg));
    293 
    294     if (soc_feature(unit, soc_feature_schan_hw_timeout)) {
    295         if (schanCtrl & SC_MSG_TIMEOUT_TST) {
    296             rv = SOC_E_TIMEOUT;
    297         }
    298     }
    299 
    300     SOC_IF_ERROR_RETURN(_soc_cmice_schan_dpp_err_check(unit));
    301     soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MSG_DONE_CLR);
    302 
    303     return rv;
    304 }
    305 
    306 /*******************************************
    307 * @function _soc_cmice_schan_op
    308 * purpose cmice SCHAN operation
    309 *
    310 * @param unit [in] unit
    311 * @param msg [in] schan_msg_t
    312 * @param dwc_write [in] Write messages
    313 * @param dwc_write [in] read messages
    314 * @param intr [in] use interrupt
    315 *
    316 * @returns SOC_E_NONE
    317 * @returns SOC_E_XXX
    318 *
    319 * @end
    320 * @comments  this is the basic logic for schan
    321  */
    322 STATIC int
    323 _soc_cmice_schan_op(int unit, schan_msg_t *msg, int dwc_write,
    324                       int dwc_read, int intr)
    325 {
    326     int i, rv;
    327 
    328     if (soc_schan_op_sanity_check(unit, msg, dwc_write, dwc_read, &rv) == TRUE) {
    329         return rv;
    330     }
    331 
    332     SCHAN_LOCK(unit);
    333 
    334     do {
    335         rv = SOC_E_NONE;
    336 
    337         /* Write raw S-Channel Data: dwc_write words */
    338         for (i = 0; i < dwc_write; i++) {
    339             soc_pci_write(unit, CMIC_SCHAN_MESSAGE(unit, i), msg->dwords[i]);
    340         }
    341 
    342         soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MSG_START_SET);
    343 
    344         /* Wait for completion using either the interrupt or polling method */
    345         if (intr &&  SOC_CONTROL(unit)->schanIntrEnb) {
    346             rv = _soc_cmice_schan_intr_wait(unit);
    347         } else {
    348             rv = _soc_cmice_schan_poll_wait(unit, msg);
    349         }
    350 
    351         if (soc_schan_timeout_check(unit, &rv, msg, 0, 0) == TRUE) {
    352             break;
    353         }
    354 
    355         /* Read in data from S-Channel buffer space, if any */
    356         for (i = 0; i < dwc_read; i++) {
    357             msg->dwords[i] = soc_pci_read(unit, CMIC_SCHAN_MESSAGE(unit, i));
    358         }
    359 
    360         if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) {
    361             soc_schan_dump(unit, msg, dwc_read);
    362         }
    363 
    364     } while (0);
    365 
    366     SCHAN_UNLOCK(unit);
    367 
    368     if (rv == SOC_E_TIMEOUT) {
    369         if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_ERROR)) {
    370             LOG_ERROR(BSL_LS_SOC_SCHAN,
    371                       (BSL_META_U(unit,
    372                                   "SchanTimeOut:soc_schan_op operation timed out\n")));
    373             soc_schan_dump(unit, msg, dwc_write);
    374         }
    375     }
    376 
    377     return rv;
    378 }
    379 
    380 /*******************************************
    381 * @function _soc_cmice_schan_deinit
    382 * purpose API to de-nitialize cmice SCHAN
    383 *
    384 * @param unit [in] unit
    385 *
    386 * @returns SOC_E_NONE
    387 * @returns SOC_E_XXX
    388 *
    389 * @end
    390  */
    391 STATIC int
    392 _soc_cmice_schan_deinit(int unit)
    393 {
    394     _soc_cmice_schan_reset(unit, 0, 0);
    395     return SOC_E_NONE;
    396 }
    397 
    398 /*******************************************
    399 * @function soc_schan_cmice_init
    400 * purpose API to Initialize cmice SCHAN
    401 *
    402 * @param unit [in] unit
    403 * @param drv [out] soc_cmic_schan_drv_t
    404 *
    405 * @returns SOC_E_NONE
    406 * @returns SOC_E_XXX
    407 *
    408 * @end
    409 * @comments used for cmice
    410  */
    411 int soc_cmice_schan_init(int unit, soc_cmic_schan_drv_t *drv)
    412 {
    413     drv->soc_schan_deinit = _soc_cmice_schan_deinit;
    414     drv->soc_schan_op = _soc_cmice_schan_op;
    415     drv->soc_schan_reset = _soc_cmice_schan_reset;
    416 
    417     return SOC_E_NONE;
    418 
    419 }