blob: 4374fd26f4f9a56c3f2503ef84b3af302f0292b3 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/******************************************************************************
2 *
3 * <:copyright-BRCM:2016:DUAL/GPL:standard
4 *
5 * Copyright (c) 2016 Broadcom
6 * All Rights Reserved
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed
10 * to you under the terms of the GNU General Public License version 2
11 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
12 * with the following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give
15 * you permission to link this software with independent modules, and
16 * to copy and distribute the resulting executable under terms of your
17 * choice, provided that you also meet, for each linked independent
18 * module, the terms and conditions of the license of that module.
19 * An independent module is a module which is not derived from this
20 * software. The special exception does not apply to any modifications
21 * of the software.
22 *
23 * Not withstanding the above, under no circumstances may you combine
24 * this software in any way with any other Broadcom software provided
25 * under a license other than the GPL, without Broadcom's express prior
26 * written consent.
27 *
28 * :>
29 *
30 *****************************************************************************/
31
32/**
33 * @file bal_api.c
34 * @brief The BAL Public API
35 *
36 * @addtogroup api
37 */
38
39/*@{*/
40
41/* Project includes */
42#include "bal_api.h"
43#include "bal_msg.h"
44#include "bal_api_worker.h"
45#include "bal_obj_msg_pack_unpack.h"
46#ifdef BAL_MONOLITHIC
47#include <bal_worker.h>
48#endif
49
50#ifdef ENABLE_LOG
51#include <bcm_dev_log.h>
52
53/*
54 * @brief The logging device id for the BAL public API
55 */
56dev_log_id log_id_public_api;
57#endif
58
59/*
60 * @brief The global mgmt queues
61 *
62 * These are the queues through which the BAL API communicates with
63 * the core, and vice versa.
64 */
65static bcmos_msg_queue balapi_rsp_queue;
66static bcmos_msg_queue balapi_to_core_queue;
67
68bcmos_msg_queue *p_balapi_rsp_queue;
69bcmos_msg_queue *p_balapi_to_core_queue;
70
71static bcmos_mutex balapi_lock;
72static uint32_t balapi_exchange_id;
73static STAILQ_HEAD(pending_req_list, bcmos_msg) pending_req_list;
74
75static bcmos_task api_rsp_rx_thread;
76static int _bal_ipc_api_rx_handler(long data);
77
78/* Rx polling timeout (us) */
79#define BAL_API_RX_POLL_TIMEOUT 100000
80
81/*****************************************************************************
82 * Initialize the BAL Public API internal data structures
83 *****************************************************************************/
84bcmos_errno bcmbal_api_init(const char *balapi_mgmt_ip_port,
85 const char *core_mgmt_ip_port)
86{
87 bcmos_errno ret = BCM_ERR_OK;
88 bcmos_msg_queue_parm msg_q_p = {};
89 bcmos_task_parm task_p = {};
90
91#ifdef ENABLE_LOG
92 log_id_public_api = bcm_dev_log_id_register("BAL_API", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
93 BUG_ON(log_id_public_api == DEV_LOG_INVALID_ID);
94#endif
95
96 do
97 {
98 STAILQ_INIT(&pending_req_list);
99
100 ret = bcmos_mutex_create(&balapi_lock, 0, "bal_api");
101 if (BCM_ERR_OK != ret)
102 {
103 BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API protection mutex\n");
104 break;
105 }
106
107 /* Create BAL API RX management queue - the BAL Public API
108 * exchanges management messages with the BAL core using this queue.
109 */
110 msg_q_p.name = "balapi_mgmt_q";
111 if (NULL != balapi_mgmt_ip_port)
112 {
113 msg_q_p.local_ep_address = balapi_mgmt_ip_port;
114 msg_q_p.remote_ep_address = NULL;
115 msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
116 }
117 else
118 {
119 msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_LOCAL;
120 }
121 ret = bcmos_msg_queue_create(&balapi_rsp_queue, &msg_q_p);
122 if (BCM_ERR_OK != ret)
123 {
124 BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n");
125 ret = BCM_ERR_INTERNAL;
126 break;
127 }
128 p_balapi_rsp_queue = &balapi_rsp_queue;
129#ifdef BAL_MONOLITHIC
130 if (NULL == balapi_mgmt_ip_port)
131 p_bal_core_to_api_queue = p_balapi_rsp_queue;
132#endif
133
134 /* Create queue for sending API requests to the core. Only do it if API and core interact via UDP
135 */
136 if (NULL != core_mgmt_ip_port)
137 {
138 msg_q_p.name = "balapi_to_core_q";
139 msg_q_p.local_ep_address = NULL;
140 msg_q_p.remote_ep_address = core_mgmt_ip_port;
141 msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
142
143 ret = bcmos_msg_queue_create(&balapi_to_core_queue, &msg_q_p);
144 if (BCM_ERR_OK != ret)
145 {
146 BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n");
147 ret = BCM_ERR_INTERNAL;
148 break;
149 }
150 p_balapi_to_core_queue = &balapi_to_core_queue;
151 }
152
153 /* Create BAL API RX thread */
154 task_p.name = "ipc_api_rsp_rx_thread";
155 task_p.priority = TASK_PRIORITY_IPC_RX;
156 task_p.handler = _bal_ipc_api_rx_handler;
157 task_p.data = (long)p_balapi_rsp_queue;
158
159 ret = bcmos_task_create(&api_rsp_rx_thread, &task_p);
160 if (ret)
161 {
162 BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API response RX thread\n");
163 break;
164 }
165
166 /*
167 * Initialize the BAL Public API backend worker and rx threads. These
168 * threads are used to receive asynchronous indications from the core.
169 */
170 enable_bal_api_indications(balapi_mgmt_ip_port);
171
172 }
173 while(0);
174
175 return ret;
176}
177
178/*****************************************************************************
179 * Un-initialize the BAL Public API internal data structures
180 *****************************************************************************/
181bcmos_errno bcmbal_api_finish(void)
182{
183 bcmos_task_destroy(&api_rsp_rx_thread);
184 bcmos_msg_queue_destroy(&balapi_rsp_queue);
185 if (p_balapi_to_core_queue == &balapi_to_core_queue)
186 bcmos_msg_queue_destroy(&balapi_to_core_queue);
187
188 bal_api_indications_finish();
189
190 return BCM_ERR_OK;
191}
192
193/* Find pending request matching response */
194static bal_comm_msg_hdr *_bal_api_get_request_by_ex_id(uint32_t ex_id)
195{
196 bcmos_msg *req_msg, *tmp_msg;
197 bal_comm_msg_hdr *comm_hdr = NULL;
198
199 STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg)
200 {
201 comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg);
202 if (comm_hdr->ex_id == ex_id)
203 {
204 STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next);
205 break;
206 }
207 }
208 return req_msg ? comm_hdr : NULL;
209}
210
211/* Check if any pending request timed out */
212static void _bal_api_check_req_timeout(void)
213{
214 bcmos_msg *req_msg, *tmp_msg;
215 bal_comm_msg_hdr *comm_hdr;
216 bcmbal_obj *req_obj;
217 uint32_t ts = bcmos_timestamp();
218
219 STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg)
220 {
221 comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg);
222 if (ts - comm_hdr->timestamp >= BCMBAL_MSG_TIMEOUT_1_SEC)
223 {
224 STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next);
225 req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(comm_hdr);
226 /* Release pending API call */
227 req_obj->status = BCM_ERR_TIMEOUT;
228 BCM_LOG(DEBUG, log_id_public_api, "Timing out request %p\n", comm_hdr);
229 bcmos_sem_post(&comm_hdr->sem);
230 }
231 }
232}
233
234/* API response handler */
235static int _bal_ipc_api_rx_handler(long data)
236{
237 static uint32_t last_timeout_check_ts;
238 bcmos_msg_queue *rxq = (bcmos_msg_queue *)data;
239 bcmos_task *my_task = bcmos_task_current();
240 bcmos_msg *msg;
241 bcmos_errno ret = BCM_ERR_OK;
242 uint32_t ex_id;
243 bal_comm_msg_hdr *req;
244 bcmbal_obj *req_obj;
245
246 last_timeout_check_ts = bcmos_timestamp();
247 while (!my_task->destroy_request)
248 {
249 /* Wait for response */
250 msg = NULL;
251 req = NULL;
252
253 ret = bcmos_msg_recv(rxq, BAL_API_RX_POLL_TIMEOUT, &msg);
254 if(BCM_ERR_OK != ret && BCM_ERR_TIMEOUT != ret)
255 {
256 BCM_LOG(ERROR, log_id_public_api,
257 "error during bcmos_msg_recv (error:%s)\n", bcmos_strerror(ret));
258 }
259
260 /* Peek exchange id */
261 if (msg)
262 {
263 ret = bcmbal_bal_msg_peek_ex_id(msg, &ex_id);
264 if(BCM_ERR_OK != ret)
265 {
266 BCM_LOG(ERROR, log_id_public_api,
267 "bad message. Can't find exchange id (error:%s)\n", bcmos_strerror(ret));
268 bcmos_msg_free(msg);
269 msg = NULL;
270 }
271 else
272 {
273 BCM_LOG(DEBUG, log_id_public_api, "Received message with ex_id=%u\n", ex_id);
274 }
275 }
276
277 /* Now find pending request and also check if any pending request(s) timed out */
278 bcmos_mutex_lock(&balapi_lock);
279 if (msg)
280 {
281 req = _bal_api_get_request_by_ex_id(ex_id);
282 if (NULL == req)
283 {
284 BCM_LOG(ERROR, log_id_public_api,
285 "Request with ex_id=%u is not found. Probably expired. Response discarded\n", ex_id);
286 }
287 else
288 {
289 BCM_LOG(DEBUG, log_id_public_api, "Found request %p\n", req);
290 }
291 }
292 if (bcmos_timestamp() - last_timeout_check_ts >= BCMBAL_MSG_TIMEOUT_1_SEC)
293 {
294 _bal_api_check_req_timeout();
295 last_timeout_check_ts = bcmos_timestamp();
296 }
297 bcmos_mutex_unlock(&balapi_lock);
298
299 /* Got a message. Now unpack it */
300 if (req)
301 {
302 req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(req);
303 ret = bcmbal_obj_msg_unpack(msg, &req);
304 if (BCM_ERR_OK != ret)
305 {
306 BCM_LOG(ERROR, log_id_public_api, "Error during message unpack: %s\n", bcmos_strerror(ret));
307 req_obj->status = ret;
308 }
309 /* Release pending API */
310 BCM_LOG(DEBUG, log_id_public_api, "Posting request semaphore for %p\n", req);
311 bcmos_sem_post(&req->sem);
312 }
313
314 if (msg)
315 bcmos_msg_free(msg); /* release packed message. It is no longer needed */
316 }
317
318 my_task->destroyed = BCMOS_TRUE;
319
320 return (BCM_ERR_OK == ret) ? 0 : -EINVAL;
321}
322
323static bcmbal_mgmt_oper_id _bcmbal_obj_to_oper_id(const bcmbal_obj *objinfo)
324{
325 if (objinfo->group == BCMBAL_MGT_GROUP_STAT)
326 {
327 return BCMBAL_MGMT_OPER_ID_GET_STATS;
328 }
329 else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_GET))
330 {
331 return BCMBAL_MGMT_OPER_ID_GET;
332 }
333 else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_CLEAR))
334 {
335 return BCMBAL_MGMT_OPER_ID_CLEAR;
336 }
337 else
338 {
339 return BCMBAL_MGMT_OPER_ID_SET;
340 }
341}
342
343#define BALAPI_OPER_TIMEOUT (30000000) /* 30 seconds */
344
345static bcmos_errno _bcmbal_oper(bcmbal_obj *objinfo)
346{
347 bal_comm_msg_hdr *comm_hdr = bcmbal_bal_hdr_get(objinfo);
348 bcmos_msg *os_msg;
349 bcmos_errno ret = BCM_ERR_OK;
350
351 /*
352 * Send the message to the core for processing
353 */
354
355 /* Parameter checks */
356 BUG_ON(NULL == objinfo);
357
358 /* Check the magic number to be sure that the object has been properly initialized */
359 if(BCMBAL_OBJ_INIT_VAL != objinfo->obj_init_val)
360 {
361 BCM_LOG(ERROR, log_id_public_api,
362 "Object has not been initialized: must use a BCMBAL INIT macro on the object before calling the BAL API\n");
363 return BCM_ERR_PARM;
364 }
365
366 ret = bcmos_sem_create(&comm_hdr->sem, 0, 0, "api_req");
367 if (ret)
368 {
369 BCM_LOG(ERROR, log_id_public_api, "Can't create semaphore: %s\n", bcmos_strerror(ret));
370 /* return here. We don't want to destroy semaphore that wasn't created */
371 return ret;
372 }
373
374 do
375 {
376 bcmbal_msg_hdr_set(objinfo,
377 BCMBAL_MGMT_MSG,
378 BAL_MSG_TYPE_REQ,
379 BAL_SUBSYSTEM_PUBLIC_API,
380 objinfo->obj_type,
381 _bcmbal_obj_to_oper_id(objinfo),
382 0);
383
384 BCM_LOG(DEBUG, log_id_public_api, "about to send %p\n", objinfo);
385
386 bcmos_mutex_lock(&balapi_lock);
387 bcmbal_ex_id_set(objinfo, ++balapi_exchange_id);
388 os_msg = bcmbal_bcmos_hdr_get(objinfo);
389 STAILQ_INSERT_TAIL(&pending_req_list, os_msg, next);
390 bcmos_mutex_unlock(&balapi_lock);
391
392 if (BCM_ERR_OK != (ret = bcmbal_msg_send(p_balapi_to_core_queue, objinfo, BCMOS_MSG_SEND_NO_FREE_ON_ERROR)))
393 {
394 BCM_LOG(ERROR, log_id_public_api, "message send failed with error: %s\n", bcmos_strerror(ret));
395 break;
396 }
397 BCM_LOG(DEBUG, log_id_public_api, "REQ message sent to core\n");
398
399 /*
400 * We've sent the message to the core, now, wait for the response (or timeout)
401 */
402 ret = bcmos_sem_wait(&comm_hdr->sem, BALAPI_OPER_TIMEOUT);
403 if (BCM_ERR_OK != ret)
404 {
405 BCM_LOG(ERROR, log_id_public_api, "rsp message receive for failed with error: %s\n",
406 bcmos_strerror(ret));
407 break;
408 }
409 BCM_LOG(DEBUG, log_id_public_api, "RSP message received from core\n");
410
411 if (BCM_ERR_OK != ret)
412 {
413 BCM_LOG(ERROR, log_id_public_api, "failed to process rsp msg\n");
414 break;
415 }
416
417 if(BCM_ERR_OK != objinfo->status)
418 {
419 BCM_LOG(ERROR, log_id_public_api, "remote message command status is: %s\n",
420 bcmos_strerror(objinfo->status));
421 }
422
423 /*
424 * Pass the command status received from the core back to the caller
425 */
426 ret = objinfo->status;
427 }
428 while(0);
429
430 bcmos_sem_destroy(&comm_hdr->sem);
431
432 return ret;
433}
434
435/*****************************************************************************
436 * BAL Public API Set (or modify) command.
437 *****************************************************************************/
438bcmos_errno bcmbal_cfg_set(bcmbal_cfg *objinfo)
439{
440 bcmos_errno ret = BCM_ERR_OK;
441
442 BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SET\n");
443
444 if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
445 {
446 BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
447 ret = BCM_ERR_NOT_SUPPORTED;
448
449 }
450 else
451 {
452 objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_SET;
453 ret = _bcmbal_oper(&objinfo->hdr);
454 }
455
456 return ret;
457}
458
459#define BCMBAL_MAX_PROXY_PACKET_SIZE (1600)
460
461/*****************************************************************************
462 * BAL Public API Packet Send function.
463 *****************************************************************************/
464bcmos_errno bcmbal_pkt_send(bcmbal_dest dest,
465 const char *packet_to_send,
466 uint16_t packet_len)
467{
468 /* Convert the user packet into a BAL object */
469 bcmbal_packet_cfg *p_packet_obj;
470 bcmbal_packet_key key;
471 bcmbal_u8_list_u32 pkt;
472 bcmos_errno ret;
473
474 BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SEND to %s\n",
475 (BCMBAL_DEST_TYPE_NNI == dest.type) ? "NNI" : "SUB-TERM");
476
477 if(BCMBAL_MAX_PROXY_PACKET_SIZE < packet_len)
478 {
479 BCM_LOG(ERROR, log_id_public_api, "user packet length (%d) cannot be greater than %d\n",
480 packet_len,
481 BCMBAL_MAX_PROXY_PACKET_SIZE);
482
483 return BCM_ERR_PARM;
484 }
485
486 BCM_LOG(INFO, log_id_public_api, "user packet first 8 bytes %02X%02X%02X%02X%02X%02X%02X%02X\n",
487 packet_to_send[0], packet_to_send[1], packet_to_send[2], packet_to_send[3],
488 packet_to_send[4], packet_to_send[5], packet_to_send[6], packet_to_send[7]);
489
490 /* Set up the object key */
491 key.packet_send_dest = dest;
492
493 /* Allocate room for the packet object including the user packet */
494 p_packet_obj = bcmos_calloc(sizeof(bcmbal_packet_cfg) + packet_len);
495
496 BCMBAL_CFG_INIT(p_packet_obj, packet, key);
497
498 /* Now fill in user packet data into the object */
499 pkt.len = packet_len;
500 pkt.val = (uint8_t *)&p_packet_obj[1];
501 memcpy(pkt.val, packet_to_send, packet_len);
502
503 BCMBAL_CFG_PROP_SET(p_packet_obj, packet, pkt, pkt);
504
505 p_packet_obj->hdr.hdr.type = BCMBAL_OBJ_MSG_TYPE_SET; /* internally packet SEND is modeled as a config SET */
506 ret = _bcmbal_oper(&(p_packet_obj->hdr.hdr));
507 bcmos_free(p_packet_obj);
508
509 return ret;
510}
511
512/*****************************************************************************
513 * BAL Public API Get command.
514 *****************************************************************************/
515bcmos_errno bcmbal_cfg_get(bcmbal_cfg *objinfo)
516{
517 bcmos_errno ret = BCM_ERR_OK;
518
519 BCM_LOG(DEBUG, log_id_public_api, "BAL PUBLIC API - BCMBAL_GET\n");
520
521 if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
522 {
523 BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
524 ret = BCM_ERR_NOT_SUPPORTED;
525
526 }
527 else
528 {
529 objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_GET;
530 ret = _bcmbal_oper(&(objinfo->hdr));
531 }
532
533 return ret;
534}
535
536/*****************************************************************************
537 * BAL Public API Clear command.
538 *****************************************************************************/
539bcmos_errno bcmbal_cfg_clear(bcmbal_cfg *objinfo)
540{
541 bcmos_errno ret = BCM_ERR_OK;
542
543 BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_CLEAR\n");
544
545 if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
546 {
547 BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
548 ret = BCM_ERR_NOT_SUPPORTED;
549
550 }
551 else
552 {
553 objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_CLEAR;
554 ret = _bcmbal_oper(&objinfo->hdr);
555 }
556
557 return ret;
558}
559
560/*****************************************************************************
561 * @brief BAL Public API Get Stats command.
562 *****************************************************************************/
563bcmos_errno bcmbal_stat_get(bcmbal_stat *objinfo)
564{
565
566 /* Parameter checks */
567 BUG_ON(NULL == objinfo);
568
569 /*
570 * @todo Finish the stats function
571 */
572
573 BCM_LOG(ERROR, log_id_public_api, "bal get stats API not supported\n");
574
575 return BCM_ERR_NOT_SUPPORTED;
576}
577
578/*****************************************************************************
579 * BAL Public API indication subscription.
580 *****************************************************************************/
581bcmos_errno bcmbal_subscribe_ind(bcmbal_cb_cfg *cb_cfg)
582{
583
584 bcmos_errno ret = BCM_ERR_OK;
585
586 /*
587 * The indication subscription function
588 */
589 BCM_LOG(DEBUG, log_id_public_api, "BAL indication subscription for type: %s (%d)\n",
590 bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type);
591
592 ret = _manage_api_ind_listener(IND_CB_SUBSCRIBE, cb_cfg);
593
594 return ret;
595}
596
597/*****************************************************************************
598 * BAL Public API indication un-subscription.
599 *****************************************************************************/
600bcmos_errno bcmbal_unsubscribe_ind(bcmbal_cb_cfg *cb_cfg)
601{
602
603 bcmos_errno ret = BCM_ERR_OK;
604
605 BUG_ON(NULL == cb_cfg);
606
607 /*
608 * The indication subscription function
609 */
610 BCM_LOG(DEBUG, log_id_public_api, "BAL indication un-subscription for type: %s (%d)\n",
611 bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type);
612
613 ret = _manage_api_ind_listener(IND_CB_UNSUBSCRIBE, cb_cfg);
614
615 return ret;
616}
617
618/*****************************************************************************/
619/**
620 * @brief A function to get the string representation of the interface type
621 *
622 * @param int_type The interface type to get
623 *
624 * @returns const char * A pointer to a string containing the interface type,
625 * or "INVALID", if not a valid type.
626 *
627 *****************************************************************************/
628const char *bcmbal_get_interface_type_str(bcmbal_intf_type int_type)
629{
630 const char *type_str;
631
632 switch (int_type)
633 {
634 case(BCMBAL_INTF_TYPE_PON):
635 {
636 type_str = "pon";
637 }
638 break;
639
640 case(BCMBAL_INTF_TYPE_NNI):
641 {
642 type_str = "nni";
643 }
644 break;
645
646 default:
647 {
648 type_str = "INVALID";
649 }
650 break;
651
652 }
653
654 return type_str;
655}
656
657
658/*@}*/