| /****************************************************************************** |
| * |
| * <: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. |
| * |
| * :> |
| * |
| *****************************************************************************/ |
| |
| /* |
| * unitest.c |
| * |
| * Created on: 2013-12-10 |
| * Author: swallace |
| */ |
| |
| #include "bcmos_system.h" |
| #include "bcm_db_engine.h" |
| |
| /* EPON LLID data structure subset */ |
| typedef enum |
| { |
| /* Free entry in the LLID management table, available for assignment on an |
| MPCP register request. */ |
| unassigned_llid, |
| /* Locked out waiting on a timer to release the LLID */ |
| not_registered_llid, |
| /* Waiting for permission to register from host */ |
| ignored_llid, |
| /* LLID has been assigned to an ONU MAC but not registered. Intermediate |
| state before the ONU returns a registration ack. */ |
| wait_reg_ack_llid, |
| /* OLT link is in-service; user traffic is allowed */ |
| inservice_llid, |
| wait_no_reports_llid, |
| /* The following state only applies to multicast/flood links */ |
| in_service_mcast_llid, |
| /* We want a "Reserved" state for things like Optical monitoring */ |
| reserved_llid, |
| /* We have detected a rogue ONU on this LLID - don't use it! */ |
| quarantined_llid, |
| llid_state_count, |
| } epon_olt_llid_state; |
| |
| static char *get_llid_state_string(epon_olt_llid_state llid_state) |
| { |
| static char *llid_state_strings[]= { |
| "unassigned", |
| "not_registered", |
| "ignored", |
| "wait_reg_ack", |
| "inservice", |
| "wait_no_reports", |
| "in_service_mcast", |
| "reserved", |
| "quarantined" |
| }; |
| |
| return llid_state_strings[(uint16_t)(llid_state)]; |
| } |
| |
| #define MAX_LINKS_PER_PORT 512 |
| #define MAX_PORTS_PER_HALF_CHIP 8 |
| #define MAX_LINKS_PER_HALF_CHIP ((MAX_LINKS_PER_PORT)*(MAX_PORTS_PER_HALF_CHIP)) |
| |
| typedef uint8_t core_epon; |
| typedef uint16_t hw_link_index; |
| |
| typedef struct epon_db_olt_llid_rec |
| { |
| epon_olt_llid_state state; |
| core_epon epon; |
| hw_link_index index; |
| } epon_db_olt_llid_rec; |
| |
| |
| typedef struct epon_msg_olt_llid_rec |
| { |
| uint16_t index; |
| epon_db_olt_llid_rec llid_rec; |
| } epon_msg_olt_llid_rec; |
| |
| typedef enum |
| { |
| enabled, |
| disabled, |
| } epon_olt_port_state; |
| |
| static char *get_port_state_string(epon_olt_port_state port_state) |
| { |
| static char *port_state_strings[]= { |
| "enabled", |
| "disabled", |
| }; |
| |
| return port_state_strings[(uint16_t)(port_state)]; |
| } |
| |
| |
| typedef struct epon_db_olt_port_rec |
| { |
| epon_olt_port_state state; |
| } epon_db_olt_port_rec; |
| |
| typedef struct epon_msg_olt_port_rec |
| { |
| uint16_t index; |
| epon_db_olt_port_rec port_rec; |
| } epon_msg_olt_port_rec; |
| |
| typedef enum |
| { |
| epon_olt_link_record, |
| epon_olt_port_record, |
| num_db_tables, |
| } db_tables; |
| |
| |
| /* Master database handle */ |
| static bcmdb_set *db_sos_set; |
| |
| static bcmdb_set* epon_get_db_handle(void) |
| { |
| return db_sos_set; |
| } |
| |
| #define LINK_REC_DB() bcmdb_set *db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_link_record) |
| |
| #define PORT_REC_DB bcmdb_set *db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_port_record) |
| |
| /* Database test messages - */ |
| typedef enum |
| { |
| update_link_db = 20, |
| update_port_db = 21, |
| dump_db = 30, |
| } dbtest_msgid; |
| |
| static inline const epon_db_olt_llid_rec *epon_olt_get_llid_rec_read(uint16_t index) |
| { |
| LINK_REC_DB(); |
| return bcmdb_record_get_read(db_set, index, epon_db_olt_llid_rec); |
| }; |
| |
| static inline void epon_db_olt_unlock_llid_rec(uint16_t index) |
| { |
| LINK_REC_DB(); |
| bcmdb_record_unlock_read(db_set, index); |
| } |
| |
| |
| #define OltGetLlidRecWrite(index) \ |
| ({ \ |
| LINK_REC_DB(); \ |
| bcmdb_record_get_write(db_set, index, epon_db_olt_llid_rec);\ |
| }) |
| |
| #define OltCommitLlidRec(index) \ |
| ({ \ |
| LINK_REC_DB(); \ |
| bcmdb_record_unlock_write(db_set, BCMOS_FALSE);\ |
| }) |
| |
| |
| static void ut_dump_db(void) |
| { |
| uint16_t index; |
| bcmdb_set *db_set; |
| |
| db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_port_record); |
| for (index = 0; index < MAX_PORTS_PER_HALF_CHIP; index++) |
| { |
| const epon_db_olt_port_rec *port_rec; |
| port_rec = bcmdb_record_get_read(db_set, index, epon_db_olt_port_rec); |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, |
| "Record %d, state %s\n", index, |
| get_port_state_string(port_rec->state)); |
| bcmdb_record_unlock_read(db_set, index); |
| } |
| |
| for (index = 0; index < MAX_LINKS_PER_HALF_CHIP; index++) |
| { |
| const epon_db_olt_llid_rec *llid_rec; |
| llid_rec = epon_olt_get_llid_rec_read(index); |
| if (llid_rec->state != unassigned_llid) |
| { |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, |
| "Record %d, port %d, state %s\n", llid_rec->index, |
| llid_rec->epon, get_llid_state_string(llid_rec->state)); |
| } |
| epon_db_olt_unlock_llid_rec(index); |
| } |
| |
| |
| } |
| |
| static void ut_update_link_db(epon_msg_olt_llid_rec *rec) |
| { |
| epon_db_olt_llid_rec *llid_rec; |
| llid_rec=OltGetLlidRecWrite(rec->index); |
| llid_rec->state=rec->llid_rec.state; |
| |
| OltCommitLlidRec(index); |
| } |
| |
| static void ut_update_port_db(epon_msg_olt_port_rec *rec) |
| { |
| bcmdb_set *db_set; |
| epon_db_olt_port_rec *port_rec; |
| |
| db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_port_record); |
| port_rec = bcmdb_record_get_write(db_set, rec->index, epon_db_olt_port_rec); |
| |
| port_rec->state=rec->port_rec.state; |
| |
| bcmdb_record_unlock_write(db_set, BCMOS_FALSE); |
| } |
| |
| |
| static void ut_msg_handler(dbtest_msgid id, void *data) |
| { |
| switch (id) |
| { |
| case update_link_db: |
| ut_update_link_db((epon_msg_olt_llid_rec*)data); |
| break; |
| |
| case update_port_db: |
| ut_update_port_db((epon_msg_olt_port_rec*)data); |
| break; |
| |
| case dump_db: |
| ut_dump_db(); |
| break; |
| |
| default: |
| break; |
| } |
| |
| } |
| |
| /* Database engine unit test functions */ |
| static uint16_t epon_db_data_init(void) |
| { |
| uint16_t index; |
| bcmdb_set *db_set; |
| int rc = 0; |
| |
| db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_link_record); |
| for ( index = 0; |
| (index < MAX_LINKS_PER_HALF_CHIP) && (rc >= 0) && (db_set != NULL) ; |
| index++) |
| { |
| epon_db_olt_llid_rec llid_rec; |
| |
| llid_rec.state = unassigned_llid; |
| llid_rec.epon = index/MAX_LINKS_PER_PORT; |
| llid_rec.index = index; |
| rc = bcmdb_record_add(db_set, index, (void *)&llid_rec); |
| } |
| |
| db_set = bcmdb_set_handle(epon_get_db_handle(), epon_olt_port_record); |
| for ( index = 0; |
| (index < MAX_PORTS_PER_HALF_CHIP) && (rc >= 0) && (db_set != NULL) ; |
| index++) |
| { |
| epon_db_olt_port_rec port_rec; |
| port_rec.state = disabled; |
| rc = bcmdb_record_add(db_set, index, (void *)&port_rec); |
| } |
| return rc; |
| } |
| |
| static int epon_db_instance_init(void) |
| { |
| bcmdb_sos_init db_sos_inst; |
| bcmdb_sor_init db_sor_inst; |
| const char* db_name = "EPON STACK"; |
| const char* db_llid_name = "EPON LINK REC"; |
| const char* db_eport_name = "EPON PORT REC"; |
| bcmdb_set *db_sor_set; |
| int rc; |
| |
| db_sos_inst.name = db_name; |
| db_sos_inst.backend_type = BCMDB_BACKEND_ARRAY; |
| db_sos_inst.max_entries = num_db_tables; |
| rc = bcmdb_make_set_of_sets(&db_sos_inst, &db_sos_set); |
| |
| if (rc >= 0) |
| { |
| db_sor_inst.name = db_llid_name; |
| db_sor_inst.backend_type = BCMDB_BACKEND_ARRAY; |
| db_sor_inst.lock_policy = BCMDB_LOCK_NB_READ_SHADOW_WRITE; |
| db_sor_inst.max_entries = MAX_LINKS_PER_HALF_CHIP; |
| db_sor_inst.record_size = sizeof(epon_db_olt_llid_rec); |
| db_sor_inst.format = NULL; |
| bcmdb_make_set_of_records(&db_sor_inst, BCMOS_TRUE, &db_sor_set); |
| |
| rc = bcmdb_set_add(epon_get_db_handle(), |
| epon_olt_link_record, db_sor_set); |
| } |
| if (rc >= 0) |
| { |
| db_sor_inst.name = db_eport_name; |
| db_sor_inst.backend_type = BCMDB_BACKEND_ARRAY; |
| db_sor_inst.lock_policy = BCMDB_LOCK_NB_READ_SHADOW_WRITE; |
| db_sor_inst.max_entries = MAX_PORTS_PER_HALF_CHIP; |
| db_sor_inst.record_size = sizeof(epon_db_olt_port_rec); |
| db_sor_inst.format = NULL; |
| rc = bcmdb_make_set_of_records(&db_sor_inst, BCMOS_TRUE, &db_sor_set); |
| } |
| |
| rc = bcmdb_set_add(epon_get_db_handle(), epon_olt_port_record, db_sor_set); |
| |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "database creation returnd %d\n", rc); |
| |
| if (rc >= 0) |
| { |
| rc = epon_db_data_init(); |
| } |
| return rc; |
| } |
| |
| /* Thread handlers - so that the DB accesses can be tested across multiple |
| threads. */ |
| static int task1_handler(long data) |
| { |
| bcmos_msg_queue *q = (bcmos_msg_queue *)data; |
| bcmos_msg *msg; |
| |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "traditional task handler\n"); |
| |
| while (1) |
| { |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "Waiting for message\n"); |
| |
| bcmos_msg_recv(q, BCMOS_WAIT_FOREVER, &msg); |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, |
| "Received message ID %d, data %p\n", |
| msg->type, msg->data); |
| |
| ut_msg_handler(msg->type, msg->data); |
| bcmos_usleep(100000); |
| } |
| |
| return 0; |
| } |
| |
| |
| static bcmos_errno mod1_init(long data) |
| { |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "%ld\n", data); |
| return BCM_ERR_OK; |
| } |
| |
| static void mod_msg_handler(bcmos_module_id module_id, bcmos_msg *msg) |
| { |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "module %d msg %d data %p\n", |
| module_id, msg->type, msg->data); |
| |
| ut_msg_handler(msg->type, msg->data); |
| } |
| |
| |
| |
| /* Unit test function - */ |
| int main(int argc, char *argv[]) |
| { |
| bcmos_task_parm tp = {}; |
| bcmos_msg_queue_parm qp = {}; |
| bcmos_module_parm mp = {}; |
| bcmos_msg msg1 = {}; |
| bcmos_msg msg2 = {}; |
| |
| bcmos_task t1; |
| bcmos_task t2; |
| bcmos_msg_queue q1; |
| bcmos_errno rc; |
| epon_msg_olt_llid_rec link_rec1, link_rec2; |
| epon_msg_olt_port_rec port_msg1, port_msg2; |
| |
| bcmos_init(); |
| bcmos_trace_level_set(BCMOS_TRACE_LEVEL_DEBUG); |
| |
| if (epon_db_instance_init() < 0) |
| { |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_ERROR, |
| "Could not instantiate a Database\n"); |
| return BCM_ERR_NOMEM; |
| } |
| |
| BCMOS_TRACE(BCMOS_TRACE_LEVEL_INFO, "Database set %p\n", |
| bcmdb_set_handle(db_sos_set, epon_olt_link_record)); |
| |
| /* Create message queue */ |
| qp.name = "msg queue1"; |
| qp.size = 16; |
| qp.high_wm = 14; |
| qp.low_wm = 12; |
| rc = bcmos_msg_queue_create(&q1, &qp); |
| |
| /* Create a couple of threads */ |
| tp.name = "task1"; |
| tp.handler = task1_handler; |
| tp.data = (long)&q1; |
| rc = bcmos_task_create(&t1, &tp); |
| |
| tp.name = "task2"; |
| tp.handler = NULL; |
| tp.data = 0; |
| rc = bcmos_task_create(&t2, &tp); |
| |
| /* Register a module */ |
| mp.qparm.name = "module1"; |
| mp.qparm.size = 16; |
| mp.init = mod1_init; |
| bcmos_module_create(BCMOS_MODULE_ID_TEST1, &t2, &mp); |
| |
| /* Wait some */ |
| bcmos_usleep(2000000); |
| |
| /* Send a message to update the DB - enable a port*/ |
| port_msg1.index=5; |
| port_msg1.port_rec.state=enabled; |
| msg1.type = update_port_db; |
| msg1.data = &port_msg1; |
| bcmos_msg_send(&q1, &msg1, BCMOS_MSG_SEND_NO_FREE_ON_ERROR); |
| |
| /* Send a message to update the DB - enable a port*/ |
| port_msg2.index=3; |
| port_msg2.port_rec.state=enabled; |
| msg2.type = update_port_db; |
| msg2.data = &port_msg2; |
| bcmos_msg_send(&q1, &msg2, BCMOS_MSG_SEND_NO_FREE_ON_ERROR); |
| |
| /* Wait some */ |
| bcmos_usleep(2000000); |
| |
| /* Send a message to update the DB - put a link In Service*/ |
| link_rec1.index=14; |
| link_rec1.llid_rec.state=inservice_llid; |
| msg1.type = update_link_db; |
| msg1.data = &link_rec1; |
| bcmos_msg_send(&q1, &msg1, BCMOS_MSG_SEND_NO_FREE_ON_ERROR); |
| |
| /* Send a message to update the DB - quarantine a link */ |
| link_rec2.index=22; |
| link_rec2.llid_rec.state=quarantined_llid; |
| msg2.type = update_link_db; |
| msg2.data = &link_rec2; |
| msg2.handler = mod_msg_handler; |
| bcmos_msg_send_to_module(BCMOS_MODULE_ID_TEST1, &msg2, BCMOS_MSG_SEND_NO_FREE_ON_ERROR); |
| |
| /* Wait some */ |
| bcmos_usleep(2000000); |
| |
| /* Send a message to dump the DB */ |
| msg1.type = dump_db; |
| msg1.handler = mod_msg_handler; |
| msg1.data = NULL; |
| bcmos_msg_send_to_module(BCMOS_MODULE_ID_TEST1, &msg1, BCMOS_MSG_SEND_NO_FREE_ON_ERROR); |
| |
| |
| /* Wait some */ |
| bcmos_usleep(2000000); |
| |
| return rc; |
| } |