blob: ca638cea04a11737abba78ae747d48738e5167da [file] [log] [blame]
/******************************************************************************
*
* <: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;
}