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 }