| /****************************************************************************** |
| * |
| * <:copyright-BRCM:2016:DUAL/GPL:standard |
| * |
| * Copyright (c) 2016 Broadcom |
| * All Rights Reserved |
| * |
| * Unless you and Broadcom execute a separate written software license |
| * agreement governing use of this software, this software is licensed |
| * to you under the terms of the GNU General Public License version 2 |
| * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| * with the following added to such license: |
| * |
| * As a special exception, the copyright holders of this software give |
| * you permission to link this software with independent modules, and |
| * to copy and distribute the resulting executable under terms of your |
| * choice, provided that you also meet, for each linked independent |
| * module, the terms and conditions of the license of that module. |
| * An independent module is a module which is not derived from this |
| * software. The special exception does not apply to any modifications |
| * of the software. |
| * |
| * Not withstanding the above, under no circumstances may you combine |
| * this software in any way with any other Broadcom software provided |
| * under a license other than the GPL, without Broadcom's express prior |
| * written consent. |
| * |
| * :> |
| * |
| *****************************************************************************/ |
| |
| /** |
| * @file bal_api.c |
| * @brief The BAL Public API |
| * |
| * @addtogroup api |
| */ |
| |
| /*@{*/ |
| |
| /* Project includes */ |
| #include "bal_api.h" |
| #include "bal_msg.h" |
| #include "bal_api_worker.h" |
| #include "bal_obj_msg_pack_unpack.h" |
| #ifdef BAL_MONOLITHIC |
| #include <bal_worker.h> |
| #endif |
| |
| #ifdef ENABLE_LOG |
| #include <bcm_dev_log.h> |
| |
| /* |
| * @brief The logging device id for the BAL public API |
| */ |
| dev_log_id log_id_public_api; |
| #endif |
| |
| /* |
| * @brief The global mgmt queues |
| * |
| * These are the queues through which the BAL API communicates with |
| * the core, and vice versa. |
| */ |
| static bcmos_msg_queue balapi_rsp_queue; |
| static bcmos_msg_queue balapi_to_core_queue; |
| |
| bcmos_msg_queue *p_balapi_rsp_queue; |
| bcmos_msg_queue *p_balapi_to_core_queue; |
| |
| static bcmos_mutex balapi_lock; |
| static uint32_t balapi_exchange_id; |
| static STAILQ_HEAD(pending_req_list, bcmos_msg) pending_req_list; |
| |
| static bcmos_task api_rsp_rx_thread; |
| static int _bal_ipc_api_rx_handler(long data); |
| |
| /* Rx polling timeout (us) */ |
| #define BAL_API_RX_POLL_TIMEOUT 100000 |
| |
| /***************************************************************************** |
| * Initialize the BAL Public API internal data structures |
| *****************************************************************************/ |
| bcmos_errno bcmbal_api_init(const char *balapi_mgmt_ip_port, |
| const char *core_mgmt_ip_port) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmos_msg_queue_parm msg_q_p = {}; |
| bcmos_task_parm task_p = {}; |
| |
| #ifdef ENABLE_LOG |
| log_id_public_api = bcm_dev_log_id_register("BAL_API", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH); |
| BUG_ON(log_id_public_api == DEV_LOG_INVALID_ID); |
| #endif |
| |
| do |
| { |
| STAILQ_INIT(&pending_req_list); |
| |
| ret = bcmos_mutex_create(&balapi_lock, 0, "bal_api"); |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API protection mutex\n"); |
| break; |
| } |
| |
| /* Create BAL API RX management queue - the BAL Public API |
| * exchanges management messages with the BAL core using this queue. |
| */ |
| msg_q_p.name = "balapi_mgmt_q"; |
| if (NULL != balapi_mgmt_ip_port) |
| { |
| msg_q_p.local_ep_address = balapi_mgmt_ip_port; |
| msg_q_p.remote_ep_address = NULL; |
| msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET; |
| } |
| else |
| { |
| msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_LOCAL; |
| } |
| ret = bcmos_msg_queue_create(&balapi_rsp_queue, &msg_q_p); |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| p_balapi_rsp_queue = &balapi_rsp_queue; |
| #ifdef BAL_MONOLITHIC |
| if (NULL == balapi_mgmt_ip_port) |
| p_bal_core_to_api_queue = p_balapi_rsp_queue; |
| #endif |
| |
| /* Create queue for sending API requests to the core. Only do it if API and core interact via UDP |
| */ |
| if (NULL != core_mgmt_ip_port) |
| { |
| msg_q_p.name = "balapi_to_core_q"; |
| msg_q_p.local_ep_address = NULL; |
| msg_q_p.remote_ep_address = core_mgmt_ip_port; |
| msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET; |
| |
| ret = bcmos_msg_queue_create(&balapi_to_core_queue, &msg_q_p); |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| p_balapi_to_core_queue = &balapi_to_core_queue; |
| } |
| |
| /* Create BAL API RX thread */ |
| task_p.name = "ipc_api_rsp_rx_thread"; |
| task_p.priority = TASK_PRIORITY_IPC_RX; |
| task_p.handler = _bal_ipc_api_rx_handler; |
| task_p.data = (long)p_balapi_rsp_queue; |
| |
| ret = bcmos_task_create(&api_rsp_rx_thread, &task_p); |
| if (ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API response RX thread\n"); |
| break; |
| } |
| |
| /* |
| * Initialize the BAL Public API backend worker and rx threads. These |
| * threads are used to receive asynchronous indications from the core. |
| */ |
| enable_bal_api_indications(balapi_mgmt_ip_port); |
| |
| } |
| while(0); |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * Un-initialize the BAL Public API internal data structures |
| *****************************************************************************/ |
| bcmos_errno bcmbal_api_finish(void) |
| { |
| bcmos_task_destroy(&api_rsp_rx_thread); |
| bcmos_msg_queue_destroy(&balapi_rsp_queue); |
| if (p_balapi_to_core_queue == &balapi_to_core_queue) |
| bcmos_msg_queue_destroy(&balapi_to_core_queue); |
| |
| bal_api_indications_finish(); |
| |
| return BCM_ERR_OK; |
| } |
| |
| /* Find pending request matching response */ |
| static bal_comm_msg_hdr *_bal_api_get_request_by_ex_id(uint32_t ex_id) |
| { |
| bcmos_msg *req_msg, *tmp_msg; |
| bal_comm_msg_hdr *comm_hdr = NULL; |
| |
| STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg) |
| { |
| comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg); |
| if (comm_hdr->ex_id == ex_id) |
| { |
| STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next); |
| break; |
| } |
| } |
| return req_msg ? comm_hdr : NULL; |
| } |
| |
| /* Check if any pending request timed out */ |
| static void _bal_api_check_req_timeout(void) |
| { |
| bcmos_msg *req_msg, *tmp_msg; |
| bal_comm_msg_hdr *comm_hdr; |
| bcmbal_obj *req_obj; |
| uint32_t ts = bcmos_timestamp(); |
| |
| STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg) |
| { |
| comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg); |
| if (ts - comm_hdr->timestamp >= BCMBAL_MSG_TIMEOUT_1_SEC) |
| { |
| STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next); |
| req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(comm_hdr); |
| /* Release pending API call */ |
| req_obj->status = BCM_ERR_TIMEOUT; |
| BCM_LOG(DEBUG, log_id_public_api, "Timing out request %p\n", comm_hdr); |
| bcmos_sem_post(&comm_hdr->sem); |
| } |
| } |
| } |
| |
| /* API response handler */ |
| static int _bal_ipc_api_rx_handler(long data) |
| { |
| static uint32_t last_timeout_check_ts; |
| bcmos_msg_queue *rxq = (bcmos_msg_queue *)data; |
| bcmos_task *my_task = bcmos_task_current(); |
| bcmos_msg *msg; |
| bcmos_errno ret = BCM_ERR_OK; |
| uint32_t ex_id; |
| bal_comm_msg_hdr *req; |
| bcmbal_obj *req_obj; |
| |
| last_timeout_check_ts = bcmos_timestamp(); |
| while (!my_task->destroy_request) |
| { |
| /* Wait for response */ |
| msg = NULL; |
| req = NULL; |
| |
| ret = bcmos_msg_recv(rxq, BAL_API_RX_POLL_TIMEOUT, &msg); |
| if(BCM_ERR_OK != ret && BCM_ERR_TIMEOUT != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, |
| "error during bcmos_msg_recv (error:%s)\n", bcmos_strerror(ret)); |
| } |
| |
| /* Peek exchange id */ |
| if (msg) |
| { |
| ret = bcmbal_bal_msg_peek_ex_id(msg, &ex_id); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, |
| "bad message. Can't find exchange id (error:%s)\n", bcmos_strerror(ret)); |
| bcmos_msg_free(msg); |
| msg = NULL; |
| } |
| else |
| { |
| BCM_LOG(DEBUG, log_id_public_api, "Received message with ex_id=%u\n", ex_id); |
| } |
| } |
| |
| /* Now find pending request and also check if any pending request(s) timed out */ |
| bcmos_mutex_lock(&balapi_lock); |
| if (msg) |
| { |
| req = _bal_api_get_request_by_ex_id(ex_id); |
| if (NULL == req) |
| { |
| BCM_LOG(ERROR, log_id_public_api, |
| "Request with ex_id=%u is not found. Probably expired. Response discarded\n", ex_id); |
| } |
| else |
| { |
| BCM_LOG(DEBUG, log_id_public_api, "Found request %p\n", req); |
| } |
| } |
| if (bcmos_timestamp() - last_timeout_check_ts >= BCMBAL_MSG_TIMEOUT_1_SEC) |
| { |
| _bal_api_check_req_timeout(); |
| last_timeout_check_ts = bcmos_timestamp(); |
| } |
| bcmos_mutex_unlock(&balapi_lock); |
| |
| /* Got a message. Now unpack it */ |
| if (req) |
| { |
| req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(req); |
| ret = bcmbal_obj_msg_unpack(msg, &req); |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Error during message unpack: %s\n", bcmos_strerror(ret)); |
| req_obj->status = ret; |
| } |
| /* Release pending API */ |
| BCM_LOG(DEBUG, log_id_public_api, "Posting request semaphore for %p\n", req); |
| bcmos_sem_post(&req->sem); |
| } |
| |
| if (msg) |
| bcmos_msg_free(msg); /* release packed message. It is no longer needed */ |
| } |
| |
| my_task->destroyed = BCMOS_TRUE; |
| |
| return (BCM_ERR_OK == ret) ? 0 : -EINVAL; |
| } |
| |
| static bcmbal_mgmt_oper_id _bcmbal_obj_to_oper_id(const bcmbal_obj *objinfo) |
| { |
| if (objinfo->group == BCMBAL_MGT_GROUP_STAT) |
| { |
| return BCMBAL_MGMT_OPER_ID_GET_STATS; |
| } |
| else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_GET)) |
| { |
| return BCMBAL_MGMT_OPER_ID_GET; |
| } |
| else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_CLEAR)) |
| { |
| return BCMBAL_MGMT_OPER_ID_CLEAR; |
| } |
| else |
| { |
| return BCMBAL_MGMT_OPER_ID_SET; |
| } |
| } |
| |
| #define BALAPI_OPER_TIMEOUT (30000000) /* 30 seconds */ |
| |
| static bcmos_errno _bcmbal_oper(bcmbal_obj *objinfo) |
| { |
| bal_comm_msg_hdr *comm_hdr = bcmbal_bal_hdr_get(objinfo); |
| bcmos_msg *os_msg; |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| /* |
| * Send the message to the core for processing |
| */ |
| |
| /* Parameter checks */ |
| BUG_ON(NULL == objinfo); |
| |
| /* Check the magic number to be sure that the object has been properly initialized */ |
| if(BCMBAL_OBJ_INIT_VAL != objinfo->obj_init_val) |
| { |
| BCM_LOG(ERROR, log_id_public_api, |
| "Object has not been initialized: must use a BCMBAL INIT macro on the object before calling the BAL API\n"); |
| return BCM_ERR_PARM; |
| } |
| |
| ret = bcmos_sem_create(&comm_hdr->sem, 0, 0, "api_req"); |
| if (ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "Can't create semaphore: %s\n", bcmos_strerror(ret)); |
| /* return here. We don't want to destroy semaphore that wasn't created */ |
| return ret; |
| } |
| |
| do |
| { |
| bcmbal_msg_hdr_set(objinfo, |
| BCMBAL_MGMT_MSG, |
| BAL_MSG_TYPE_REQ, |
| BAL_SUBSYSTEM_PUBLIC_API, |
| objinfo->obj_type, |
| _bcmbal_obj_to_oper_id(objinfo), |
| 0); |
| |
| BCM_LOG(DEBUG, log_id_public_api, "about to send %p\n", objinfo); |
| |
| bcmos_mutex_lock(&balapi_lock); |
| bcmbal_ex_id_set(objinfo, ++balapi_exchange_id); |
| os_msg = bcmbal_bcmos_hdr_get(objinfo); |
| STAILQ_INSERT_TAIL(&pending_req_list, os_msg, next); |
| bcmos_mutex_unlock(&balapi_lock); |
| |
| if (BCM_ERR_OK != (ret = bcmbal_msg_send(p_balapi_to_core_queue, objinfo, BCMOS_MSG_SEND_NO_FREE_ON_ERROR))) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "message send failed with error: %s\n", bcmos_strerror(ret)); |
| break; |
| } |
| BCM_LOG(DEBUG, log_id_public_api, "REQ message sent to core\n"); |
| |
| /* |
| * We've sent the message to the core, now, wait for the response (or timeout) |
| */ |
| ret = bcmos_sem_wait(&comm_hdr->sem, BALAPI_OPER_TIMEOUT); |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "rsp message receive for failed with error: %s\n", |
| bcmos_strerror(ret)); |
| break; |
| } |
| BCM_LOG(DEBUG, log_id_public_api, "RSP message received from core\n"); |
| |
| if (BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "failed to process rsp msg\n"); |
| break; |
| } |
| |
| if(BCM_ERR_OK != objinfo->status) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "remote message command status is: %s\n", |
| bcmos_strerror(objinfo->status)); |
| } |
| |
| /* |
| * Pass the command status received from the core back to the caller |
| */ |
| ret = objinfo->status; |
| } |
| while(0); |
| |
| bcmos_sem_destroy(&comm_hdr->sem); |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * BAL Public API Set (or modify) command. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_cfg_set(bcmbal_cfg *objinfo) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SET\n"); |
| |
| if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| |
| } |
| else |
| { |
| objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_SET; |
| ret = _bcmbal_oper(&objinfo->hdr); |
| } |
| |
| return ret; |
| } |
| |
| #define BCMBAL_MAX_PROXY_PACKET_SIZE (1600) |
| |
| /***************************************************************************** |
| * BAL Public API Packet Send function. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_pkt_send(bcmbal_dest dest, |
| const char *packet_to_send, |
| uint16_t packet_len) |
| { |
| /* Convert the user packet into a BAL object */ |
| bcmbal_packet_cfg *p_packet_obj; |
| bcmbal_packet_key key; |
| bcmbal_u8_list_u32 pkt; |
| bcmos_errno ret; |
| |
| BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SEND to %s\n", |
| (BCMBAL_DEST_TYPE_NNI == dest.type) ? "NNI" : "SUB-TERM"); |
| |
| if(BCMBAL_MAX_PROXY_PACKET_SIZE < packet_len) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "user packet length (%d) cannot be greater than %d\n", |
| packet_len, |
| BCMBAL_MAX_PROXY_PACKET_SIZE); |
| |
| return BCM_ERR_PARM; |
| } |
| |
| BCM_LOG(INFO, log_id_public_api, "user packet first 8 bytes %02X%02X%02X%02X%02X%02X%02X%02X\n", |
| packet_to_send[0], packet_to_send[1], packet_to_send[2], packet_to_send[3], |
| packet_to_send[4], packet_to_send[5], packet_to_send[6], packet_to_send[7]); |
| |
| /* Set up the object key */ |
| key.packet_send_dest = dest; |
| |
| /* Allocate room for the packet object including the user packet */ |
| p_packet_obj = bcmos_calloc(sizeof(bcmbal_packet_cfg) + packet_len); |
| |
| BCMBAL_CFG_INIT(p_packet_obj, packet, key); |
| |
| /* Now fill in user packet data into the object */ |
| pkt.len = packet_len; |
| pkt.val = (uint8_t *)&p_packet_obj[1]; |
| memcpy(pkt.val, packet_to_send, packet_len); |
| |
| BCMBAL_CFG_PROP_SET(p_packet_obj, packet, pkt, pkt); |
| |
| p_packet_obj->hdr.hdr.type = BCMBAL_OBJ_MSG_TYPE_SET; /* internally packet SEND is modeled as a config SET */ |
| ret = _bcmbal_oper(&(p_packet_obj->hdr.hdr)); |
| bcmos_free(p_packet_obj); |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * BAL Public API Get command. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_cfg_get(bcmbal_cfg *objinfo) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| BCM_LOG(DEBUG, log_id_public_api, "BAL PUBLIC API - BCMBAL_GET\n"); |
| |
| if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| |
| } |
| else |
| { |
| objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_GET; |
| ret = _bcmbal_oper(&(objinfo->hdr)); |
| } |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * BAL Public API Clear command. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_cfg_clear(bcmbal_cfg *objinfo) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_CLEAR\n"); |
| |
| if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type) |
| { |
| BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| |
| } |
| else |
| { |
| objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_CLEAR; |
| ret = _bcmbal_oper(&objinfo->hdr); |
| } |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * @brief BAL Public API Get Stats command. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_stat_get(bcmbal_stat *objinfo) |
| { |
| |
| /* Parameter checks */ |
| BUG_ON(NULL == objinfo); |
| |
| /* |
| * @todo Finish the stats function |
| */ |
| |
| BCM_LOG(ERROR, log_id_public_api, "bal get stats API not supported\n"); |
| |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| |
| /***************************************************************************** |
| * BAL Public API indication subscription. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_subscribe_ind(bcmbal_cb_cfg *cb_cfg) |
| { |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| /* |
| * The indication subscription function |
| */ |
| BCM_LOG(DEBUG, log_id_public_api, "BAL indication subscription for type: %s (%d)\n", |
| bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type); |
| |
| ret = _manage_api_ind_listener(IND_CB_SUBSCRIBE, cb_cfg); |
| |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * BAL Public API indication un-subscription. |
| *****************************************************************************/ |
| bcmos_errno bcmbal_unsubscribe_ind(bcmbal_cb_cfg *cb_cfg) |
| { |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| BUG_ON(NULL == cb_cfg); |
| |
| /* |
| * The indication subscription function |
| */ |
| BCM_LOG(DEBUG, log_id_public_api, "BAL indication un-subscription for type: %s (%d)\n", |
| bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type); |
| |
| ret = _manage_api_ind_listener(IND_CB_UNSUBSCRIBE, cb_cfg); |
| |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to get the string representation of the interface type |
| * |
| * @param int_type The interface type to get |
| * |
| * @returns const char * A pointer to a string containing the interface type, |
| * or "INVALID", if not a valid type. |
| * |
| *****************************************************************************/ |
| const char *bcmbal_get_interface_type_str(bcmbal_intf_type int_type) |
| { |
| const char *type_str; |
| |
| switch (int_type) |
| { |
| case(BCMBAL_INTF_TYPE_PON): |
| { |
| type_str = "pon"; |
| } |
| break; |
| |
| case(BCMBAL_INTF_TYPE_NNI): |
| { |
| type_str = "nni"; |
| } |
| break; |
| |
| default: |
| { |
| type_str = "INVALID"; |
| } |
| break; |
| |
| } |
| |
| return type_str; |
| } |
| |
| |
| /*@}*/ |