blob: 8cbeddf072656b5802b22306a3da06fd5ce4ef30 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(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.
:>
*/
#include <bcmos_system.h>
#include <bcm_dev_log.h>
#include <bcmolt_api.h>
#include <bcmolt_model_types.h>
#include "bcmolt_user_appl_remote_logger.h"
static struct
{
FILE *file_handle;
uint64_t file_size;
bcmolt_remote_logger_cfg cfg;
bcmos_task task;
bcmos_timer timer;
dev_log_id log_id;
} remote_logger[BCMTR_MAX_OLTS] = {};
static bcmos_timer_rc remote_logger_timer_handler(bcmos_timer *timer, long data)
{
bcmolt_devid device = (bcmolt_devid)data;
int written;
bcmos_errno err;
bcmolt_logger_cfg cfg;
bcmolt_logger_key key = { .file_id = BCMOLT_LOG_FILE_ID_DDR };
BCMOLT_CFG_INIT(&cfg, logger, key);
BCMOLT_CFG_PROP_GET(&cfg, logger, buffer);
err = bcmolt_cfg_get(device, &cfg.hdr);
if (err != BCM_ERR_OK)
{
BCM_LOG(ERROR, remote_logger[device].log_id, "Logger get API returned '%s' (%d)\n", bcmos_strerror(err), err);
bcmolt_remote_logger_appl_stop(device);
return BCMOS_TIMER_OK;
}
written = fprintf(
remote_logger[device].file_handle,
"%.*s",
(int)sizeof(cfg.data.buffer.buff),
cfg.data.buffer.buff);
if (written < 0)
{
BCM_LOG(ERROR, remote_logger[device].log_id, "File write returned %d\n", written);
bcmolt_remote_logger_appl_stop(device);
return BCMOS_TIMER_OK;
}
fflush(remote_logger[device].file_handle);
/* Check to see if we will exceed the max file size next time we write a chunk. */
remote_logger[device].file_size += written;
if (remote_logger[device].file_size + sizeof(cfg.data.buffer.buff) > remote_logger[device].cfg.max_file_size)
{
switch (remote_logger[device].cfg.max_file_size_reached_behavior)
{
case BCMOLT_REMOTE_LOGGER_FILE_SIZE_REACHED_BEHAVIOR_STOP:
BCM_LOG(INFO, remote_logger[device].log_id, "Max file size reached - remote logger stopped\n");
bcmolt_remote_logger_appl_stop(device);
return BCMOS_TIMER_OK;
case BCMOLT_REMOTE_LOGGER_FILE_SIZE_REACHED_BEHAVIOR_CLEAR:
BCM_LOG(INFO, remote_logger[device].log_id, "Max file size reached - log file cleared\n");
/* the easiest way to clear the file is to close/re-open it */
fclose(remote_logger[device].file_handle);
remote_logger[device].file_handle = fopen(remote_logger[device].cfg.filename, "w");
BUG_ON(remote_logger[device].file_handle == NULL);
break;
default:
break;
}
}
if (cfg.data.buffer.msg_to_read == 0)
{
/* There are no more messages to read right now, wait for the entire polling interval. */
bcmos_timer_start(
&remote_logger[device].timer,
remote_logger[device].cfg.polling_period_ms * 1000); /* ms to us */
}
else
{
/* There are more messages to read - wait for only the 'subsequent delay' time. */
bcmos_timer_start(
&remote_logger[device].timer,
remote_logger[device].cfg.subsequent_delay_ms * 1000); /* ms to us */
}
return BCMOS_TIMER_OK;
}
void bcmolt_remote_logger_appl_init()
{
static bcmos_task_parm task_params =
{
.priority = TASK_PRIORITY_USER_APPL_REMOTE_LOGGER,
.core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */
.init_handler = NULL
};
static bcmos_module_parm module_params =
{
.qparm = { .size = 1 } /* just the timer message */
};
static bcmos_timer_parm timer_params =
{
.periodic = BCMOS_FALSE, /* we will re-enable the timer after each tick */
.handler = remote_logger_timer_handler
};
bcmos_errno err;
bcmolt_devid device;
for (device = 0; device < BCMTR_MAX_OLTS; device++)
{
bcmos_module_id module_id = BCMOS_MODULE_ID_USER_APPL_REMOTE_LOGGER_DEV0 + device;
snprintf(
remote_logger[device].task.name,
sizeof(remote_logger[device].task.name),
"user_appl_remote_logger%u",
device);
task_params.name = remote_logger[device].task.name;
module_params.qparm.name = remote_logger[device].task.name;
timer_params.owner = module_id;
timer_params.name = remote_logger[device].task.name;
timer_params.data = (long)device;
err = bcmos_task_create(&remote_logger[device].task, &task_params);
BUG_ON(err != BCM_ERR_OK);
err = bcmos_module_create(module_id, &remote_logger[device].task, &module_params);
BUG_ON(err != BCM_ERR_OK);
err = bcmos_timer_create(&remote_logger[device].timer, &timer_params);
BUG_ON(err != BCM_ERR_OK);
remote_logger[device].log_id =
bcm_dev_log_id_register(remote_logger[device].task.name, DEV_LOG_LEVEL_WARNING, DEV_LOG_ID_TYPE_BOTH);
}
}
bcmos_errno bcmolt_remote_logger_appl_start(bcmolt_devid device)
{
bcmos_errno err;
bcmolt_logger_cfg cfg;
bcmolt_logger_key key = { .file_id = BCMOLT_LOG_FILE_ID_DDR };
if (bcmolt_remote_logger_appl_is_running(device))
{
BCM_LOG(ERROR, remote_logger[device].log_id, "Remote logger application is already running.\n");
return BCM_ERR_ALREADY;
}
/* configure DDR log file to clear on read so we can always stay up-to-date */
BCMOLT_CFG_INIT(&cfg, logger, key);
BCMOLT_CFG_PROP_SET(&cfg, logger, enable_log, BCMOS_TRUE);
BCMOLT_CFG_PROP_SET(&cfg, logger, clear_after_read, BCMOS_TRUE);
err = bcmolt_cfg_set(0, &cfg.hdr);
if (err != BCM_ERR_OK)
{
BCM_LOG(ERROR, remote_logger[device].log_id, "Logger set API returned '%s' (%d)\n", bcmos_strerror(err), err);
return err;
}
remote_logger[device].file_handle = fopen(remote_logger[device].cfg.filename, "w");
if (remote_logger[device].file_handle == NULL)
{
BCM_LOG(ERROR, remote_logger[device].log_id, "Could not open file '%s'\n", remote_logger[device].cfg.filename);
return BCM_ERR_IO;
}
remote_logger[device].file_size = 0;
bcmos_timer_start(&remote_logger[device].timer, remote_logger[device].cfg.polling_period_ms * 1000); /* ms to us */
return BCM_ERR_OK;
}
bcmos_errno bcmolt_remote_logger_appl_stop(bcmolt_devid device)
{
if (!bcmolt_remote_logger_appl_is_running(device))
{
BCM_LOG(ERROR, remote_logger[device].log_id, "Remote logger application is not running.\n");
return BCM_ERR_ALREADY;
}
bcmos_timer_stop(&remote_logger[device].timer);
fclose(remote_logger[device].file_handle);
remote_logger[device].file_handle = NULL;
return BCM_ERR_OK;
}
bcmos_bool bcmolt_remote_logger_appl_is_running(bcmolt_devid device)
{
return bcmos_timer_is_running(&remote_logger[device].timer);
}
bcmos_errno bcmolt_remote_logger_appl_cfg_get(bcmolt_devid device, bcmolt_remote_logger_cfg *cfg)
{
*cfg = remote_logger[device].cfg;
return BCM_ERR_OK;
}
bcmos_errno bcmolt_remote_logger_appl_cfg_update(bcmolt_devid device, const bcmolt_remote_logger_cfg *cfg)
{
remote_logger[device].cfg = *cfg;
return BCM_ERR_OK;
}