soc_async_sbusdma.c (13702B)
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: soc_async_sbusdma.c 8 * Purpose: SOC SBUS-DMA driver, supports both sync and async modes. 9 */ 10 11 #include <shared/bsl.h> 12 #include <shared/alloc.h> 13 #include <soc/drv.h> 14 #include <soc/debug.h> 15 #include <soc/cm.h> 16 #include <soc/sbusdma_internal.h> 17 #include <soc/soc_async_sbusdma.h> 18 19 #if defined(BCM_SBUSDMA_SUPPORT) && defined(BCM_SOC_ASYNC_SUPPORT) 20 21 #if (!defined(_LIMITS_H)) && !defined(_LIBC_LIMITS_H_) 22 23 #if (!defined(INT_MIN)) && !defined(INT_MAX) 24 #define INT_MIN (((int)1)<<(sizeof(int)*8-1)) 25 #define INT_MAX (~INT_MIN) 26 #endif 27 28 #ifndef UINT_MAX 29 #define UINT_MAX ((unsigned)-1) 30 #endif 31 32 #endif 33 34 typedef struct soc_async_sbusdma_reg_s { 35 soc_sbusdma_reg_drv_t drv; 36 soc_sbusdma_cmic_ch_t ch; 37 soc_async_handle_t handle; 38 } soc_async_sbusdma_reg_t; 39 40 STATIC soc_async_sbusdma_reg_t _async_sbusdma_reg[SOC_MAX_NUM_DEVICES]; 41 42 /******************************************* 43 * @function _soc_async_sbusdma_cb_f 44 * purpose this function calls used defined callback 45 * 46 * @param unit [in] unit # 47 * @param data [in] User parameter 48 * @param cookie [in] user/driver data 49 * @param cookie [in] status 50 * 51 * @end 52 */ 53 STATIC void 54 _soc_async_sbusdma_cb_f(int unit, 55 void *data, void *cookie, int status) 56 { 57 cmic_sbusdma_wparam_t *wparam; 58 59 wparam = (cmic_sbusdma_wparam_t *)cookie; 60 if (wparam) { 61 wparam->cb_f(unit, data, wparam->cookie, status); 62 sal_free(wparam); 63 } 64 } 65 66 /******************************************* 67 * @function _soc_async_sbusdma_msg_alloc 68 * purpose this function to initialize sbus message 69 * 70 * @param unit [in] unit # 71 * @param msg [in, out] pointer to pointer soc_async_msg_t 72 * @param param [in] user data pointer 73 * @param cbf [in] user call back function 74 * 75 * @returns SOC_E_BUSY 76 * @returns SOC_E_MEMORY 77 * @end 78 */ 79 STATIC int 80 _soc_async_sbusdma_msg_alloc(int unit, 81 soc_async_msg_t **msg, 82 soc_sbusdma_reg_param_t *param, 83 soc_async_cb_f cbf) 84 { 85 cmic_sbusdma_wparam_t *wparam; 86 87 wparam = sal_alloc(sizeof(cmic_sbusdma_wparam_t), "cmicx_sbusdma_wparam"); 88 89 if(!wparam) { 90 return SOC_E_MEMORY; 91 } 92 93 if (SOC_FAILURE(soc_async_msg_alloc(_async_sbusdma_reg[unit].handle, msg))) { 94 sal_free(wparam); 95 return SOC_E_MEMORY; 96 } 97 (*msg)->unit = unit; 98 (*msg)->type = p_sbus_dma; 99 (*msg)->data = param; 100 (*msg)->cookie = wparam; 101 (*msg)->wait_f = _async_sbusdma_reg[unit].drv.soc_sbusdma_reg_complete; 102 (*msg)->cb_f = _soc_async_sbusdma_cb_f; 103 wparam->cb_f = cbf; 104 wparam->cookie = NULL; 105 106 return SOC_E_NONE; 107 } 108 109 /******************************************* 110 * @function _soc_async_sbusdma_msg_free 111 * purpose this function to initialize sbus message 112 * 113 * @param unit [in] unit # 114 * @param msg [in] pointer to soc_async_msg_t 115 * 116 * @returns SOC_E_BUSY 117 * @returns SOC_E_MEMORY 118 * @end 119 */ 120 STATIC int 121 _soc_async_sbusdma_msg_free(int unit, 122 soc_async_msg_t *msg) 123 { 124 cmic_sbusdma_wparam_t *wparam = NULL; 125 126 if (msg == NULL) 127 return SOC_E_PARAM; 128 129 wparam = (cmic_sbusdma_wparam_t *)msg->cookie; 130 131 if (wparam) { 132 sal_free(wparam); 133 } 134 135 soc_async_msg_free(_async_sbusdma_reg[unit].handle, msg); 136 137 return SOC_E_NONE; 138 } 139 140 /******************************************* 141 * @function soc_async_mem_array_sbusdma_write 142 * purpose DMA acceleration for soc_mem_write_range() 143 * If callback function is NULL then the call 144 * will behave as synchronous/Blocked. 145 * 146 * @param unit [in] unit # 147 * @param param [in] soc_sbusdma_reg_param_t pointer 148 * @param cbf [out] soc_async_cb_f, call back function pointer 149 * 150 * @returns SOC_E_BUSY 151 * @returns SOC_E_NONE 152 * 153 * @end 154 */ 155 int 156 soc_async_mem_array_sbusdma_write(int unit, 157 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 158 { 159 soc_control_t *soc = SOC_CONTROL(unit); 160 int rv = SOC_E_NONE; 161 soc_async_msg_t *msg; 162 soc_timeout_t to; 163 cmic_sbusdma_wait_t *wait; 164 165 /* If callback is defined it is async call */ 166 if (cbf != NULL) { 167 rv = _soc_async_sbusdma_msg_alloc(unit, &msg, param, cbf); 168 if (rv == SOC_E_NONE) { 169 wait = &((cmic_sbusdma_wparam_t *)(msg->cookie))->wait; 170 wait->intr_enb = soc->tslamDmaIntrEnb; 171 wait->timeout = soc->tslamDmaTimeout; 172 msg->proc_f = _async_sbusdma_reg[unit].drv.soc_sbusdma_write_prog; 173 soc_timeout_init(&to, wait->timeout, 100); 174 do { 175 rv = soc_async_msg_queue(_async_sbusdma_reg[unit].handle, msg); 176 if (rv == SOC_E_NONE) { 177 break; 178 } 179 } while(!soc_timeout_check(&to)); 180 181 if (SOC_FAILURE(rv)) { 182 (void)_soc_async_sbusdma_msg_free(unit, msg); 183 } 184 } 185 186 } else { 187 if (_async_sbusdma_reg[unit].drv.soc_mem_sbusdma_write != NULL) { 188 rv = _async_sbusdma_reg[unit].drv.soc_mem_sbusdma_write(unit, 189 param); 190 } else { 191 rv = SOC_E_INIT; 192 } 193 } 194 195 return rv; 196 } 197 198 /******************************************* 199 * @function soc_async_mem_sbusdma_write 200 * purpose DMA acceleration for soc_mem_write_range() 201 * This calls 'soc_mem_array_sbusdma_async_write' 202 * 203 * @param unit [in] unit # 204 * @param param [in] soc_sbusdma_reg_param_t pointer 205 * @param cbf [out] soc_async_cb_f, call back function pointer 206 * 207 * @returns SOC_E_BUSY 208 * @returns SOC_E_NONE 209 * 210 * @end 211 */ 212 int 213 soc_async_mem_sbusdma_write(int unit, 214 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 215 { 216 param->array_id_start = 0; 217 param->array_id_end = 0; 218 param->flags= 0; 219 220 return soc_async_mem_array_sbusdma_write(unit, param, cbf); 221 } 222 223 /******************************************* 224 * @function soc_async_mem_array_sbusdma_read 225 * purpose DMA acceleration for soc_mem_read_range() 226 * If callback function is NULL then the call 227 * will behave as synchronous/Blocked. 228 * 229 * @param unit [in] unit # 230 * @param param [in] soc_sbusdma_reg_param_t pointer 231 * @param cbf [out] soc_async_cb_f, call back function pointer 232 * 233 * @returns SOC_E_BUSY 234 * @returns SOC_E_NONE 235 * 236 * @end 237 */ 238 int 239 soc_async_mem_array_sbusdma_read(int unit, 240 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 241 { 242 soc_control_t *soc = SOC_CONTROL(unit); 243 int rv = SOC_E_NONE; 244 soc_async_msg_t *msg; 245 soc_timeout_t to; 246 cmic_sbusdma_wait_t *wait; 247 248 /* If callback is defined it is async call */ 249 if (cbf != NULL) { 250 rv = _soc_async_sbusdma_msg_alloc(unit, &msg, param, cbf); 251 if (rv == SOC_E_NONE) { 252 wait = &((cmic_sbusdma_wparam_t *)(msg->cookie))->wait; 253 wait->intr_enb = soc->tableDmaIntrEnb; 254 wait->timeout = soc->tableDmaTimeout; 255 msg->proc_f = _async_sbusdma_reg[unit].drv.soc_sbusdma_read_prog; 256 soc_timeout_init(&to, wait->timeout, 100); 257 258 do { 259 rv = soc_async_msg_queue(_async_sbusdma_reg[unit].handle, msg); 260 if (rv == SOC_E_NONE) { 261 break; 262 } 263 } while(!soc_timeout_check(&to)); 264 265 if (SOC_FAILURE(rv)) { 266 (void)_soc_async_sbusdma_msg_free(unit, msg); 267 } 268 } 269 270 } else { 271 if (_async_sbusdma_reg[unit].drv.soc_mem_sbusdma_read != NULL) { 272 rv = _async_sbusdma_reg[unit].drv.soc_mem_sbusdma_read(unit, 273 param); 274 } else { 275 rv = SOC_E_INIT; 276 } 277 } 278 return rv; 279 } 280 281 /******************************************* 282 * @function soc_async_mem_sbusdma_read 283 * purpose DMA acceleration for soc_mem_read_range() 284 * This calls 'soc_mem_array_sbusdma_async_read' 285 * 286 * @param unit [in] unit # 287 * @param param [in] soc_sbusdma_reg_param_t pointer 288 * @param cbf [out] soc_async_cb_f, call back function pointer 289 * 290 * @returns SOC_E_BUSY 291 * @returns SOC_E_NONE 292 * 293 * @end 294 */ 295 int 296 soc_async_mem_sbusdma_read(int unit, 297 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 298 { 299 param->array_id_start = 0; 300 301 return soc_async_mem_array_sbusdma_read(unit, param, cbf); 302 } 303 304 /******************************************* 305 * @function soc_async_mem_sbusdma_clear_specific 306 * purpose Clear a specific memory/table region using 307 * DMA write (slam) acceleration. 308 * If callback function is NULL then the call 309 * will behave as synchronous/Blocked. 310 * 311 * @param unit [in] unit # 312 * @param param [in] soc_sbusdma_reg_param_t pointer 313 * @param cbf [out] soc_async_cb_f, call back function pointer 314 * 315 * @returns SOC_E_BUSY 316 * @returns SOC_E_NONE 317 * 318 * @end 319 */ 320 int 321 soc_async_mem_sbusdma_clear_specific(int unit, 322 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 323 { 324 soc_control_t *soc = SOC_CONTROL(unit); 325 int rv = SOC_E_NONE; 326 soc_async_msg_t *msg; 327 soc_timeout_t to; 328 329 /* If callback is defined it is async call */ 330 if (cbf != NULL) { 331 rv = _soc_async_sbusdma_msg_alloc(unit, &msg, param, cbf); 332 if (rv == SOC_E_NONE) { 333 msg->proc_f = _async_sbusdma_reg[unit].drv.soc_sbusdma_clear_prog; 334 msg->wait_f = NULL; 335 soc_timeout_init(&to, soc->tslamDmaTimeout, 100); 336 do { 337 rv = soc_async_msg_queue(_async_sbusdma_reg[unit].handle, msg); 338 if (rv == SOC_E_NONE) { 339 break; 340 } 341 } while(!soc_timeout_check(&to)); 342 343 if (SOC_FAILURE(rv)) { 344 (void)_soc_async_sbusdma_msg_free(unit, msg); 345 } 346 } 347 348 } else { 349 if (_async_sbusdma_reg[unit].drv.soc_mem_sbusdma_clear != NULL) { 350 rv = _async_sbusdma_reg[unit].drv.soc_mem_sbusdma_clear(unit, 351 param); 352 } else { 353 rv = SOC_E_INIT; 354 } 355 } 356 357 return rv; 358 } 359 360 /******************************************* 361 * @function soc_async_mem_sbusdma_clear 362 * This function calls 'soc_mem_sbusdma_async_clear_specific' 363 * This calls 'soc_async_mem_sbusdma_clear_specific' 364 * 365 * @param unit [in] unit # 366 * @param param [in] soc_sbusdma_reg_param_t pointer 367 * @param cbf [out] soc_async_cb_f, call back function pointer 368 * 369 * @returns SOC_E_BUSY 370 * @returns SOC_E_NONE 371 * 372 * @end 373 */ 374 int 375 soc_async_mem_sbusdma_clear(int unit, 376 soc_sbusdma_reg_param_t *param, soc_async_cb_f cbf) 377 { 378 379 param->array_id_start = 0; 380 param->array_id_end = UINT_MAX; 381 param->index_begin = INT_MIN; 382 param->index_end = INT_MAX; 383 384 return soc_async_mem_sbusdma_clear_specific(unit, param, cbf); 385 } 386 387 /******************************************* 388 * @function soc_async_sbusdma_ch_try_get 389 * purpose get idle channel on cmc 390 * 391 * @param unit [in] unit # 392 * @param cmc [out] cmc number 0-1 393 * @param ch [out] channel number 0-2 394 * 395 * @returns SOC_E_BUSY 396 * @returns SOC_E_NONE 397 * 398 * @end 399 */ 400 int soc_async_sbusdma_ch_try_get(int unit, int cmc, int ch) 401 { 402 int rv = SOC_E_NONE; 403 404 if (_async_sbusdma_reg[unit].ch.soc_sbusdma_ch_try_get != NULL) { 405 rv = 406 _async_sbusdma_reg[unit].ch.soc_sbusdma_ch_try_get(unit, cmc, ch); 407 } else { 408 rv = SOC_E_INIT; 409 } 410 411 return rv; 412 } 413 414 /******************************************* 415 * @function soc_async_sbusdma_ch_put 416 * purpose put back the freed channel on cmc 417 * 418 * @param cmc [in] cmc number 419 * @param ch [in] channel number 420 * 421 * @returns SOC_E_PARAM 422 * @returns SOC_E_NONE 423 * 424 * @end 425 */ 426 int soc_async_sbusdma_ch_put(int unit, int cmc, int ch) 427 { 428 int rv; 429 430 if (_async_sbusdma_reg[unit].ch.soc_sbusdma_ch_put != NULL) { 431 rv = 432 _async_sbusdma_reg[unit].ch.soc_sbusdma_ch_put(unit, cmc, ch); 433 } else { 434 rv = SOC_E_INIT; 435 } 436 437 return rv; 438 } 439 /******************************************* 440 * @function soc_async_sbusdma_deinit 441 * purpose API to DeInitialize ASYNC SBUS DMA 442 * 443 * @param unit [in] unit 444 * 445 * @returns SOC_E_NONE 446 * @returns SOC_E_XXX 447 * 448 * @end 449 */ 450 int 451 soc_async_sbusdma_deinit(int unit) 452 { 453 #ifdef BCM_CMICX_SUPPORT 454 if (soc_feature(unit, soc_feature_cmicx)) { 455 (void)cmicx_sbusdma_ch_deinit(unit); 456 457 if (_async_sbusdma_reg[unit].handle) { 458 (void)soc_async_proc_deinit(_async_sbusdma_reg[unit].handle); 459 _async_sbusdma_reg[unit].handle = NULL; 460 } 461 462 } 463 #endif 464 return SOC_E_NONE; 465 } 466 467 /******************************************* 468 * @function soc_async_sbusdma_init 469 * purpose API to Initialize ASYNC SBUS DMA 470 * 471 * @param unit [in] unit 472 * @param prop [in] soc_async_prop_t pointer 473 * 474 * @returns SOC_E_NONE 475 * @returns SOC_E_XXX 476 * 477 * @end 478 */ 479 int 480 soc_async_sbusdma_init(int unit, soc_async_prop_t *prop) 481 { 482 int rv = SOC_E_NONE; 483 484 #ifdef BCM_CMICX_SUPPORT 485 if (soc_feature(unit, soc_feature_cmicx)) { 486 SOC_IF_ERROR_RETURN(cmicx_sbusdma_reg_init(unit, 487 &_async_sbusdma_reg[unit].drv)); 488 489 SOC_IF_ERROR_RETURN(cmicx_sbusdma_ch_init(unit, 490 CMIC_CMCx_SBUSDMA_CHSELECT_TIMEOUT, 491 &_async_sbusdma_reg[unit].ch)); 492 493 SOC_IF_ERROR_RETURN(cmicx_sbusdma_intr_init(unit)); 494 } 495 496 rv = soc_async_proc_init( 497 unit, 498 prop, 499 &_async_sbusdma_reg[unit].handle); 500 501 if (rv != SOC_E_NONE) { 502 LOG_ERROR(BSL_LS_SOC_DMA, 503 (BSL_META_U(unit, 504 "Failed to initialize Async Proc =%d\n"), rv)); 505 (void)soc_async_sbusdma_deinit(unit); 506 return rv; 507 } 508 LOG_VERBOSE(BSL_LS_SOC_DMA, 509 (BSL_META_U(unit,":SUCCESS\n"))); 510 #endif 511 return rv; 512 } 513 514 #endif /* defined(BCM_SBUSDMA_SUPPORT) && defined(BCM_SOC_ASYNC_SUPPORT) */ 515