attach.c (11235B)
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 * Attach Application 8 * 9 * A callback suitable for use in the stack task database update 10 * callback is provided. It automatically attaches and detaches 11 * units through the BCM RPC attachments. A callback mechanism 12 * is provided to notify users (BCMX for example) that a unit has 13 * been added or removed. 14 */ 15 16 #include <shared/bsl.h> 17 18 #include <sdk_config.h> 19 #include <assert.h> 20 #include <shared/alloc.h> 21 #include <sal/core/libc.h> 22 #include <sal/core/thread.h> 23 24 #include <bcm/types.h> 25 #include <bcm/error.h> 26 #include <bcm/init.h> 27 28 #include <bcm_int/control.h> 29 #ifdef BCM_RPC_SUPPORT 30 #include <bcm_int/rpc/rpc.h> 31 #endif /* BCM_RPC_SUPPORT */ 32 33 #include <appl/stktask/attach.h> 34 #include <appl/stktask/stktask.h> 35 36 #ifndef ATTACH_THREAD_STACK 37 #define ATTACH_THREAD_STACK SAL_THREAD_STKSZ 38 #endif 39 40 #ifndef ATTACH_THREAD_PRIO 41 #define ATTACH_THREAD_PRIO 50 42 #endif 43 44 45 static volatile int _bcm_stack_attach_thread_active; 46 47 typedef struct _attach_cb_s { 48 struct _attach_cb_s *next; 49 bcm_stack_attach_cb_f callback; 50 } _attach_cb_t; 51 52 static _attach_cb_t *_attach_cb; 53 54 static sal_mutex_t at_lock; 55 #define AT_LOCK sal_mutex_take(at_lock, sal_mutex_FOREVER) 56 #define AT_UNLOCK sal_mutex_give(at_lock) 57 58 /* 59 * Add a function to the callback list 60 */ 61 int 62 bcm_stack_attach_register(bcm_stack_attach_cb_f callback) 63 { 64 _attach_cb_t *acb; 65 66 if (callback == NULL) { 67 return BCM_E_FAIL; 68 } 69 acb = sal_alloc(sizeof(*acb), "attach cb"); 70 if (acb == NULL) { 71 return BCM_E_MEMORY; 72 } 73 acb->callback = callback; 74 acb->next = _attach_cb; 75 _attach_cb = acb; 76 return BCM_E_NONE; 77 } 78 79 /* 80 * Remove a function from the callback list 81 */ 82 int 83 bcm_stack_attach_unregister(bcm_stack_attach_cb_f callback) 84 { 85 _attach_cb_t *acb, *pacb; 86 87 pacb = NULL; 88 for (acb = _attach_cb; acb; pacb = acb, acb = acb->next) { 89 if (acb->callback == callback) { 90 if (pacb == NULL) { 91 _attach_cb = acb->next; 92 } else { 93 pacb->next = acb->next; 94 } 95 sal_free(acb); 96 return BCM_E_NONE; 97 } 98 } 99 return BCM_E_NOT_FOUND; 100 } 101 102 /* 103 * Run the callback list 104 */ 105 STATIC void 106 _bcm_stack_attach_cb_run(int unit, int attached, 107 cpudb_entry_t *cpuent, int cpuunit) 108 { 109 _attach_cb_t *acb; 110 111 for (acb = _attach_cb; acb; acb = acb->next) { 112 (*acb->callback)(unit, attached, cpuent, cpuunit); 113 } 114 #ifdef BCM_RPC_SUPPORT 115 /* notify rpc to fail any queued requests */ 116 if (!attached) { 117 bcm_rpc_detach(unit); 118 } 119 #endif /* BCM_RPC_SUPPORT */ 120 } 121 122 /* 123 * Detach bcm units to match the cpu database. 124 */ 125 int 126 bcm_stack_detach(cpudb_ref_t db_ref) 127 { 128 int ismaster; 129 cpudb_entry_t *nent; 130 cpudb_entry_t oent; 131 int unit, dunit, rv; 132 cpudb_key_t *key; 133 134 AT_LOCK; 135 ismaster = db_ref->local_entry == db_ref->master_entry; 136 137 /* find any dispatch entries that need to be deleted */ 138 sal_memset(&oent, 0, sizeof(oent)); 139 140 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 141 if (BCM_CONTROL(unit) == NULL) { 142 continue; 143 } 144 if (BCM_IS_REMOTE(unit)) { 145 key = (cpudb_key_t *)BCM_CONTROL(unit)->drv_control; 146 CPUDB_KEY_SEARCH(db_ref, *key, nent); 147 if (nent != NULL && ismaster) { 148 continue; 149 } 150 dunit = BCM_CONTROL(unit)->unit; 151 sal_memcpy(&oent.base.key, key, sizeof(cpudb_key_t)); 152 oent.flags = 0; 153 rv = bcm_detach(unit); 154 } else if (BCM_IS_LOCAL(unit)) { 155 if (ismaster) { 156 continue; 157 } 158 if (!(BCM_CAPABILITY(unit) & BCM_CAPA_CALLBACK)) { 159 continue; 160 } 161 dunit = unit; 162 rv = 0; 163 BCM_CAPABILITY(unit) &= ~BCM_CAPA_CALLBACK; 164 sal_memset(&oent.base.key, 0, sizeof(cpudb_key_t)); 165 oent.flags = CPUDB_F_IS_LOCAL; 166 } else { 167 continue; 168 } 169 if (rv >= 0) { 170 _bcm_stack_attach_cb_run(unit, 0, &oent, dunit); 171 } 172 } 173 AT_UNLOCK; 174 175 return BCM_E_NONE; 176 } 177 178 /* 179 * Attach bcm units to match the cpu database. 180 */ 181 int 182 bcm_stack_attach(cpudb_ref_t db_ref) 183 { 184 int ismaster; 185 cpudb_entry_t *nent; 186 int dunit, rv; 187 char keybuf[CPUDB_KEY_STRING_LEN]; 188 char *dtype, *dsubtype; 189 int terminate; 190 191 AT_LOCK; 192 ismaster = db_ref->local_entry == db_ref->master_entry; 193 194 /* add any new cpu units */ 195 if (ismaster) { 196 terminate = 0; 197 198 /* attach local units first */ 199 CPUDB_FOREACH_ENTRY(db_ref, nent) { 200 if (terminate) { 201 break; 202 } 203 if (!(nent->flags & CPUDB_F_IS_LOCAL)) { 204 continue; 205 } 206 dtype = NULL; 207 dsubtype = NULL; 208 rv = 0; 209 for (dunit = 0; dunit < nent->base.num_units; dunit++) { 210 rv = bcm_find(dtype, dsubtype, dunit); 211 if (rv < 0) { 212 rv = bcm_attach(-1, dtype, dsubtype, dunit); 213 } 214 if (rv < 0) { 215 terminate = 1; 216 break; 217 } 218 if (rv >= 0 && !(BCM_CAPABILITY(rv) & BCM_CAPA_CALLBACK)) { 219 _bcm_stack_attach_cb_run(rv, 1, nent, dunit); 220 BCM_CAPABILITY(rv) |= BCM_CAPA_CALLBACK; 221 } 222 } 223 } 224 225 /* attach remote units */ 226 CPUDB_FOREACH_ENTRY(db_ref, nent) { 227 if (terminate) { 228 break; 229 } 230 if (nent->flags & CPUDB_F_IS_LOCAL) { 231 continue; 232 } 233 cpudb_key_format(nent->base.key, keybuf, sizeof(keybuf)); 234 dtype = "client"; 235 dsubtype = keybuf; 236 rv = 0; 237 for (dunit = 0; dunit < nent->base.num_units; dunit++) { 238 rv = bcm_find(dtype, dsubtype, dunit); 239 if (rv < 0) { 240 rv = bcm_attach(-1, dtype, dsubtype, dunit); 241 } 242 if (rv < 0) { 243 terminate = 1; 244 break; 245 } 246 if (rv >= 0 && !(BCM_CAPABILITY(rv) & BCM_CAPA_CALLBACK)) { 247 _bcm_stack_attach_cb_run(rv, 1, nent, dunit); 248 BCM_CAPABILITY(rv) |= BCM_CAPA_CALLBACK; 249 } 250 } 251 } 252 } 253 AT_UNLOCK; 254 255 return BCM_E_NONE; 256 } 257 258 259 /* 260 * Detach and attach bcm units to match the cpu database. 261 */ 262 263 #ifdef BROADCOM_DEBUG 264 265 /* Variables and callback for diagnostics */ 266 static int dt_unit, at_unit, at_cpu; 267 static cpudb_entry_t *at_cpuent; 268 269 static void 270 _bcm_stack_at_dt_update(int unit, 271 int attach, 272 cpudb_entry_t *cpuent, 273 int cpuunit) 274 { 275 COMPILER_REFERENCE(unit); 276 COMPILER_REFERENCE(cpuunit); 277 if (attach) { 278 at_unit++; 279 /* count number of unique CPUs */ 280 if (cpuent != at_cpuent) { 281 at_cpu++; 282 at_cpuent = cpuent; 283 } 284 } else { 285 dt_unit++; 286 } 287 } 288 289 /* Debug version */ 290 291 STATIC void 292 _bcm_stack_detach_attach(cpudb_ref_t db_ref) 293 { 294 int rv; 295 char keybuf[CPUDB_KEY_STRING_LEN]; 296 int dbg_unit; 297 cpudb_entry_t *nent; 298 299 AT_LOCK; 300 301 dbg_unit = 0; 302 CPUDB_FOREACH_ENTRY(db_ref, nent) { 303 dbg_unit += nent->base.num_units; 304 } 305 306 rv = bcm_stack_attach_register(_bcm_stack_at_dt_update); 307 if (BCM_SUCCESS(rv)) { 308 dt_unit = at_unit = at_cpu = 0; 309 at_cpuent = NULL; 310 bcm_stack_detach(db_ref); 311 bcm_stack_attach(db_ref); 312 bcm_stack_attach_unregister(_bcm_stack_at_dt_update); 313 } 314 AT_UNLOCK; 315 316 bcm_st_event_send(BCM_SUCCESS(rv) ? 317 BCM_STE_ATTACH_SUCCESS : BCM_STE_ATTACH_FAILURE); 318 319 cpudb_key_format(db_ref->local_entry->base.key, keybuf, sizeof(keybuf)); 320 if (db_ref->local_entry == db_ref->master_entry) { 321 LOG_INFO(BSL_LS_TKS_COMMON, 322 (BSL_META("STACK: master on %s (%d cpu%s, %d unit%s)\n"), 323 keybuf, 324 db_ref->num_cpus, db_ref->num_cpus == 1 ? "" : "s", 325 dbg_unit, dbg_unit == 1 ? "" : "s")); 326 } else { 327 char keymast[CPUDB_KEY_STRING_LEN]; 328 329 cpudb_key_format(db_ref->master_entry->base.key, 330 keymast, sizeof(keymast)); 331 LOG_INFO(BSL_LS_TKS_COMMON, 332 (BSL_META("STACK: slave on %s (%d cpus, master %s)\n"), 333 keybuf, db_ref->num_cpus, keymast)); 334 } 335 336 if (dt_unit > 0) { 337 LOG_INFO(BSL_LS_TKS_COMMON, 338 (BSL_META("STACK: detach %d unit%s\n"), 339 dt_unit, dt_unit == 1 ? "" : "s")); 340 } 341 342 if (at_cpu > 0) { 343 LOG_INFO(BSL_LS_TKS_COMMON, 344 (BSL_META("STACK: attach %d unit%s on %d cpu%s\n"), 345 at_unit, at_unit == 1 ? "" : "s", 346 at_cpu, at_cpu == 1 ? "" : "s")); 347 } 348 } 349 350 #else 351 352 /* Non-debug version */ 353 354 STATIC void 355 _bcm_stack_detach_attach(cpudb_ref_t db_ref) 356 { 357 AT_LOCK; 358 bcm_stack_detach(db_ref); 359 bcm_stack_attach(db_ref); 360 AT_UNLOCK; 361 362 bcm_st_event_send(BCM_STE_ATTACH_SUCCESS); 363 } 364 365 #endif /* BROADCOM_DEBUG */ 366 367 /* 368 * asynchronous _bcm_stack_attach() 369 */ 370 371 STATIC void 372 _bcm_stack_attach_thread(void *cookie) 373 { 374 cpudb_ref_t db_ref = (cpudb_ref_t)cookie; 375 376 _bcm_stack_attach_thread_active++; 377 378 _bcm_stack_detach_attach(db_ref); 379 380 _bcm_stack_attach_thread_active--; 381 382 sal_thread_exit(0); 383 384 } 385 386 /* 387 * The actual callout routine that the stack task calls. 388 * 389 * The stack attach update call takes place in the ATP RX thread 390 * context. Any attach callback might require the use of packet 391 * services that would need to use the RX thread (BCM RPC calls for 392 * example using ATP), so those callbacks are done in a new thread 393 * context. 394 */ 395 int 396 bcm_stack_attach_update(cpudb_ref_t db_ref) 397 { 398 if (at_lock == NULL) { 399 return BCM_E_INIT; 400 } 401 402 if (_attach_cb != NULL) { 403 404 (void) sal_thread_create("bcmATTACH", 405 ATTACH_THREAD_STACK, 406 ATTACH_THREAD_PRIO, 407 _bcm_stack_attach_thread, 408 (void *)db_ref); 409 } else { 410 _bcm_stack_detach_attach((void *)db_ref); 411 } 412 return BCM_E_NONE; 413 } 414 415 /* 416 * Return TRUE if the attach process is running 417 */ 418 int 419 bcm_stack_attach_running(void) 420 { 421 if ((_bcm_stack_attach_thread_active < 0) || 422 (_bcm_stack_attach_thread_active >= 2)) { 423 assert(0); 424 } 425 return _bcm_stack_attach_thread_active != 0; 426 } 427 428 /* 429 * Initialize resources needed by the attach process. 430 */ 431 int 432 bcm_stack_attach_init(void) 433 { 434 if (at_lock == NULL) { 435 at_lock = sal_mutex_create("bcm_attach"); 436 if (at_lock == NULL) { 437 return BCM_E_MEMORY; 438 } 439 } 440 return BCM_E_NONE; 441 } 442