blob: 244b2e242abc477d38def5f69ca62b9d66eb29f1 [file] [log] [blame]
/*
* wl msch command module
*
* Broadcom Proprietary and Confidential. Copyright (C) 2017,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
* written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id: wlu_msch.c 502986 2014-09-16 23:06:58Z $
*/
#ifdef WIN32
#include <windows.h>
#endif
#include <wlioctl.h>
#if defined(DONGLEBUILD)
#include <typedefs.h>
#include <osl.h>
#endif
/* Because IL_BIGENDIAN was removed there are few warnings that need
* to be fixed. Windows was not compiled earlier with IL_BIGENDIAN.
* Hence these warnings were not seen earlier.
* For now ignore the following warnings
*/
#ifdef WIN32
#pragma warning(push)
#pragma warning(disable : 4244)
#pragma warning(disable : 4761)
#endif
#include <bcmutils.h>
#include <bcmendian.h>
#include "wlu_common.h"
#include "wlu.h"
#ifdef WIN32
#define bzero(b, len) memset((b), 0, (len))
#endif
#ifdef LINUX
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/if_packet.h>
#endif /* LINUX */
#include <miniopt.h>
#include <sys/stat.h>
#include <trxhdr.h>
#include <stdio.h>
#include <errno.h>
#ifndef WIN32
#include <fcntl.h>
#endif /* WIN32 */
#include <event_log.h>
#if defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000)
extern int wlu_efi_stat(char *filename, struct stat *filest);
extern long wlu_efi_ftell(void *fp);
extern int wlu_efi_fseek(void *fp, long offset, int whence);
extern size_t wlu_efi_fwrite(void *buf, size_t size, size_t nmemb, void *fp);
extern size_t wlu_efi_fread(void *buf, size_t size, size_t nmemb, void *fp);
extern void wlu_efi_fclose(void *fp);
extern void * wlu_efi_fopen(char *filename, char *mode);
#define fopen(filename, mode) (FILE *)wlu_efi_fopen(filename, mode)
#define fread(buf, size, nmemb, fp) wlu_efi_fread(buf, size, nmemb, fp)
#define fwrite(buf, size, nmemb, fp) wlu_efi_fwrite(buf, size, nmemb, fp)
#define fseek(fp, offset, origin) wlu_efi_fseek(fp, offset, origin)
#define ftell(fp) wlu_efi_ftell(fp)
#define stat(fname, filest) wlu_efi_stat(fname, (struct stat *)(filest))
#define fclose(fp) wlu_efi_fclose(fp)
#ifdef stderr
#undef stderr
#define stderr stdout
#endif
#endif /* defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION >= 0x00020000) */
#if defined(linux)
static cmd_func_t wl_msch_event_check;
#endif /* linux */
static cmd_func_t wl_msch_request;
static cmd_func_t wl_msch_collect;
static cmd_func_t wl_msch_dump;
static cmd_func_t wl_msch_profiler;
static char *mschbufp = NULL, *mschdata = NULL;
static FILE *mschfp = NULL;
#define MSCH_COLLECT_USAGE \
"{enable|disable} [+/-register] [+/-callback] [+/-profiler] " \
"[+/-error] [+/-debug] [+/-info] [+/-trace]\n" \
"\tenable: alloc memory to save profiler data\n" \
"\tdisable: stop monitor, and free memory\n" \
"\t+/-register: save or skip register data\n" \
"\t+/-callback: save or skip register data\n" \
"\t+/-profiler: save or skip profiler data\n" \
"\t+/-error: save or skip error messages\n" \
"\t+/-debug: save or skip debug messages\n" \
"\t+/-info: save or skip infomation messages\n" \
"\t+/-trace: save or skip trace messages\n"
#define MSCH_FMTFILE_USAGE \
"-D copydir -F \"logstrs_path=xxxx st_str_file_path=xxxx " \
"map_file_path=xxxx rom_st_str_file_path=xxxx rom_map_file_path=xxxx\"\n"
static cmd_t wl_msch_cmds[] = {
{ "msch_req", wl_msch_request, WLC_GET_VAR, WLC_SET_VAR,
"register multiple channel scheduler \n"
"\tUsage: msch_req <id> -w wlc_index -c \"channel_list\" -f flags -t type [params] "
"-p priority -s start_time -d duration -i interval"
"\t-w W, --wlc_index=W\tset wlc index\n"
"\t-c L, --channels=L\tcomma or space separated list of channels to scheduler\n"
"\t-f F, --flags=F\tset flags, 1 for contiguous cahhhel scheduler\n"
"\t-t T, --type=T\tset scheduler type: fix, sf, df dur-flex, bf params\n\n"
"\t-p P, --priority=P\tpriority for the scheduler\n"
"\t-s S, --start-time=S\tstart time(ms) for the scheduler\n"
"\t-d D, --duration=D\tduration(ms) for the scheduler\n"
"\t-i I, --interval=I\tinterval(ms) for the scheduler\n"},
{ "msch_collect", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
"control multiple channel scheduler profiler saving data\n"
"\tUsage: msch_collect " MSCH_COLLECT_USAGE},
{ "msch_dump", wl_msch_dump, WLC_GET_VAR, WLC_SET_VAR,
"dump multiple channel scheduler profiler data\n"
"\tUsage: msch_dump [filename] " MSCH_FMTFILE_USAGE},
{ "msch_profiler", wl_msch_profiler, WLC_GET_VAR, WLC_SET_VAR,
"dump multiple channel scheduler profiler data\n"
"\tUsage: msch_profiler [uploadfilename] [filename] " MSCH_FMTFILE_USAGE},
{ "msch_event", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
"control multiple channel scheduler profiler event data\n"
"\tUsage: msch_event " MSCH_COLLECT_USAGE},
{ "msch_event_log", wl_msch_collect, WLC_GET_VAR, WLC_SET_VAR,
"control multiple channel scheduler profiler event Log data\n"
"\tUsage: msch_event_log " MSCH_COLLECT_USAGE},
#if defined(linux)
{ "msch_event_check", wl_msch_event_check, -1, -1,
"Listen and print Multiple channel scheduler events\n"
"\tmsch_event_check syntax is: msch_event_check ifname [filename]"
"[+/-register] [+/-callback] [+/-profiler] "
"[+/-error] [+/-debug] [+/-info] [+/-trace] " MSCH_FMTFILE_USAGE},
#endif /* linux */
{ NULL, NULL, 0, 0, NULL }
};
/* module initialization */
void
wluc_msch_module_init(void)
{
/* get the global buf */
if (WLC_IOCTL_MAXLEN >= 2 * WL_MSCH_PROFILER_BUFFER_SIZE) {
mschdata = wl_get_buf();
} else {
mschdata = (char *)malloc(2 * WL_MSCH_PROFILER_BUFFER_SIZE);
if (!mschdata)
return;
}
mschbufp = (char *)&mschdata[WL_MSCH_PROFILER_BUFFER_SIZE];
/* register proxd commands */
wl_module_cmds_register(wl_msch_cmds);
}
static int
wl_parse_msch_chanspec_list(char *list_str, chanspec_t *chanspec_list, int chanspec_num)
{
int num = 0;
chanspec_t chanspec;
char *next, str[8];
size_t len;
if ((next = list_str) == NULL)
return BCME_ERROR;
while ((len = strcspn(next, " ,")) > 0) {
if (len >= sizeof(str)) {
fprintf(stderr, "string \"%s\" before ',' or ' ' is too long\n", next);
return BCME_ERROR;
}
strncpy(str, next, len);
str[len] = 0;
chanspec = wf_chspec_aton(str);
if (chanspec == 0) {
fprintf(stderr, "could not parse chanspec starting at "
"\"%s\" in list:\n%s\n", str, list_str);
return BCME_ERROR;
}
if (num == chanspec_num) {
fprintf(stderr, "too many chanspecs (more than %d) in chanspec list:\n%s\n",
chanspec_num, list_str);
return BCME_ERROR;
}
chanspec_list[num++] = htodchanspec(chanspec);
next += len;
next += strspn(next, " ,");
}
return num;
}
static int
wl_parse_msch_bf_param(char *param_str, uint32 *param)
{
int num;
uint32 val;
char* str;
char* endptr = NULL;
if (param_str == NULL)
return BCME_ERROR;
str = param_str;
num = 0;
while (*str != '\0') {
val = (uint32)strtol(str, &endptr, 0);
if (endptr == str) {
fprintf(stderr,
"could not parse bf param starting at"
" substring \"%s\" in list:\n%s\n",
str, param_str);
return -1;
}
str = endptr + strspn(endptr, " ,");
if (num >= 4) {
fprintf(stderr, "too many bf param (more than 6) in param str:\n%s\n",
param_str);
return BCME_ERROR;
}
param[num++] = htod32(val);
}
return num;
}
static int
wl_msch_request(void *wl, cmd_t *cmd, char **argv)
{
int params_size = sizeof(msch_register_params_t);
msch_register_params_t *params;
uint32 val = 0;
uint16 val16;
char key[64];
int keylen;
char *p, *eq, *valstr, *endptr = NULL;
char opt;
bool good_int;
int err = BCME_OK;
int i;
UNUSED_PARAMETER(wl);
UNUSED_PARAMETER(cmd);
params = (msch_register_params_t*)malloc(params_size);
if (params == NULL) {
fprintf(stderr, "Error allocating %d bytes for msch register params\n",
params_size);
return BCME_NOMEM;
}
memset(params, 0, params_size);
/* skip the command name */
argv++;
params->id = 0;
while ((p = *argv) != NULL) {
argv++;
memset(key, 0, sizeof(key));
opt = '\0';
valstr = NULL;
good_int = FALSE;
if (!strncmp(p, "--", 2)) {
eq = strchr(p, '=');
if (eq == NULL) {
fprintf(stderr,
"wl_msch_request: missing \" = \" in long param \"%s\"\n", p);
err = BCME_USAGE_ERROR;
goto exit;
}
keylen = eq - (p + 2);
if (keylen > 63)
keylen = 63;
memcpy(key, p + 2, keylen);
valstr = eq + 1;
if (*valstr == '\0') {
fprintf(stderr, "wl_msch_request: missing value after "
"\" = \" in long param \"%s\"\n", p);
err = BCME_USAGE_ERROR;
goto exit;
}
}
else if (!strncmp(p, "-", 1)) {
opt = p[1];
if (strlen(p) > 2) {
fprintf(stderr, "wl_msch_request: only single char options, "
"error on param \"%s\"\n", p);
err = BCME_BADARG;
goto exit;
}
if (*argv == NULL) {
fprintf(stderr,
"wl_msch_request: missing value parameter after \"%s\"\n", p);
err = BCME_USAGE_ERROR;
goto exit;
}
valstr = *argv;
argv++;
} else {
val = (uint32)strtol(p, &endptr, 0);
if (*endptr == '\0') {
/* not all the value string was parsed by strtol */
good_int = TRUE;
}
if (!good_int) {
fprintf(stderr,
"wl_msch_request: parameter error \"%s\"\n", p);
err = BCME_BADARG;
goto exit;
}
val16 = (uint16)val;
params->id = htod16(val16);
continue;
}
/* parse valstr as int just in case */
val = (uint32)strtol(valstr, &endptr, 0);
if (*endptr == '\0') {
/* not all the value string was parsed by strtol */
good_int = TRUE;
}
if (opt == 'h' || !strcmp(key, "help")) {
printf("%s", cmd->help);
goto exit;
} else if (opt == 'w' || !strcmp(key, "wlc_index")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as an wlc_index\n",
valstr);
err = BCME_BADARG;
goto exit;
}
val16 = (uint16)val;
params->wlc_index = htod16(val16);
} else if (opt == 'c' || !strcmp(key, "channels")) {
i = wl_parse_msch_chanspec_list(valstr,
(chanspec_t *)params->chanspec_list, WL_MSCH_NUMCHANNELS);
if (i == BCME_ERROR) {
fprintf(stderr, "error parsing channel list arg\n");
err = BCME_BADARG;
goto exit;
}
val = (uint32)i;
params->chanspec_cnt = htod32(val);
} else if (opt == 'n' || !strcmp(key, "id")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as an register id\n",
valstr);
err = BCME_BADARG;
goto exit;
}
val16 = (uint16)val;
params->id = htod16(val16);
} else if (opt == 'f' || !strcmp(key, "flags")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as an flages\n",
valstr);
err = BCME_BADARG;
goto exit;
}
val16 = (uint16)val;
params->flags = htod16(val16);
} else if (opt == 't' || !strcmp(key, "type")) {
if (!strcmp(valstr, "f") || !strncmp(valstr, "fix", 3)) {
params->req_type = (uint32)WL_MSCH_RT_BOTH_FIXED;
} else if (!strcmp(valstr, "sf") || !strcmp(valstr, "start-flex")) {
params->req_type = (uint32)WL_MSCH_RT_START_FLEX;
} else if (!strcmp(valstr, "df") || !strcmp(valstr, "dur-flex")) {
if (*argv == NULL) {
fprintf(stderr,
"wl_msch_request: missing param of dur-flex\n");
err = BCME_USAGE_ERROR;
goto exit;
}
valstr = *argv;
argv++;
val = (uint32)strtol(valstr, &endptr, 0);
if (*endptr != '\0') {
fprintf(stderr,
"could not parse \"%s\" as dur-flex value\n", valstr);
err = BCME_USAGE_ERROR;
goto exit;
}
params->req_type = (uint32)WL_MSCH_RT_DUR_FLEX;
params->dur_flex = htod32(val);
} else if (!strcmp(valstr, "bf") || !strcmp(valstr, "both-flex")) {
if (*argv == NULL) {
fprintf(stderr,
"wl_msch_request: missing param of both-flex\n");
err = BCME_USAGE_ERROR;
goto exit;
}
valstr = *argv;
argv++;
if (wl_parse_msch_bf_param(valstr, &params->min_dur) != 4) {
fprintf(stderr, "error parsing both flex params\n");
err = BCME_BADARG;
goto exit;
}
params->req_type = (uint32)WL_MSCH_RT_BOTH_FLEX;
} else {
fprintf(stderr,
"error type param \"%s\"\n",
valstr);
err = BCME_BADARG;
goto exit;
}
params->req_type = htod32(params->req_type);
} else if (opt == 'p' || !strcmp(key, "priority")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as priority\n",
valstr);
err = BCME_BADARG;
goto exit;
}
val16 = (uint16)val;
params->priority = htod16(val16);
} else if (opt == 's' || !strcmp(key, "start-time")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as start time\n",
valstr);
err = BCME_BADARG;
goto exit;
}
params->start_time = htod32(val);
} else if (opt == 'd' || !strcmp(key, "duration")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as duration\n",
valstr);
err = BCME_BADARG;
goto exit;
}
params->duration = htod32(val);
} else if (opt == 'i' || !strcmp(key, "interval")) {
if (!good_int) {
fprintf(stderr,
"could not parse \"%s\" as interval\n",
valstr);
err = BCME_BADARG;
goto exit;
}
params->interval = htod32(val);
} else {
fprintf(stderr,
"wl_msch_request: error option param \"%s\"\n", p);
err = BCME_BADARG;
goto exit;
}
}
err = wlu_var_setbuf(wl, cmd->name, params, params_size);
exit:
free(params);
return err;
}
static int
wl_msch_collect(void *wl, cmd_t *cmd, char **argv)
{
bool eventcmd = (!strcmp(cmd->name, "msch_event"));
bool eventlogcmd = (!strcmp(cmd->name, "msch_event_log"));
bool collectcmd = (!strcmp(cmd->name, "msch_collect"));
char *p, *endptr;
int opt, v, val, err = BCME_OK;
UNUSED_PARAMETER(wl);
if ((err = wlu_iovar_getint(wl, cmd->name, &val)) < 0)
return err;
err = BCME_OK;
if (!*++argv) {
printf("MSCH %s: %sable {", (eventcmd? "Event" : (eventlogcmd? "EventLog" :
"Profile")), ((val & WL_MSCH_CMD_ENABLE_BIT)? "En" : "Dis"));
if (val & WL_MSCH_CMD_REGISTER_BIT)
printf("registe ");
if (val & WL_MSCH_CMD_CALLBACK_BIT)
printf("callbac ");
if (val & WL_MSCH_CMD_PROFILE_BIT)
printf("profiler ");
if (val & WL_MSCH_CMD_ERROR_BIT)
printf("error ");
if (val & WL_MSCH_CMD_DEBUG_BIT)
printf("debug ");
if (val & WL_MSCH_CMD_INFOM_BIT)
printf("info ");
if (val & WL_MSCH_CMD_TRACE_BIT)
printf("trace ");
printf("\x08}\n");
return err;
}
while ((p = *argv) != NULL) {
opt = 0;
if (p[0] == '+') {
opt = 1;
p++;
}
else if (p[0] == '-') {
opt = 2;
p++;
}
if (opt == 0) {
v = (uint32)strtol(p, &endptr, 0);
if (*endptr == '\0') {
if (v == 1)
val |= WL_MSCH_CMD_ENABLE_BIT;
else if (v == 0)
val &= ~WL_MSCH_CMD_ENABLE_BIT;
else {
err = BCME_EPERM;
break;
}
}
else if (!strcmp(p, "enable") || !strcmp(p, "start")) {
val |= WL_MSCH_CMD_ENABLE_BIT;
}
else if (!strcmp(p, "disable") || !strcmp(p, "stop"))
val &= ~WL_MSCH_CMD_ENABLE_BIT;
else if (collectcmd && !strcmp(p, "dump"))
return wl_msch_dump(wl, cmd, argv);
else {
err = BCME_EPERM;
break;
}
} else {
if (opt == 2 && (!strcmp(p, "-help") || !strcmp(p, "h"))) {
printf("%s", cmd->help);
return BCME_OK;
} else if (opt == 2 && (!strcmp(p, "all") || !strcmp(p, "a"))) {
val &= ~WL_MSCH_CMD_ALL_BITS;
} else if (!strcmp(p, "profiler") || !strcmp(p, "p")) {
if (opt == 1)
val |= WL_MSCH_CMD_PROFILE_BIT;
else
val &= ~WL_MSCH_CMD_PROFILE_BIT;
}
else if (!strcmp(p, "callback") || !strcmp(p, "c")) {
if (opt == 1)
val |= WL_MSCH_CMD_CALLBACK_BIT;
else
val &= ~WL_MSCH_CMD_CALLBACK_BIT;
}
else if (!strcmp(p, "register") || !strcmp(p, "r")) {
if (opt == 1)
val |= WL_MSCH_CMD_REGISTER_BIT;
else
val &= ~WL_MSCH_CMD_REGISTER_BIT;
}
else if (!strcmp(p, "error") || !strcmp(p, "e")) {
if (opt == 1)
val |= WL_MSCH_CMD_ERROR_BIT;
else
val &= ~WL_MSCH_CMD_ERROR_BIT;
}
else if (!strcmp(p, "debug") || !strcmp(p, "d")) {
if (opt == 1)
val |= WL_MSCH_CMD_DEBUG_BIT;
else
val &= ~WL_MSCH_CMD_DEBUG_BIT;
}
else if (!strcmp(p, "info") || !strcmp(p, "i")) {
if (opt == 1)
val |= WL_MSCH_CMD_INFOM_BIT;
else
val &= ~WL_MSCH_CMD_INFOM_BIT;
}
else if (!strcmp(p, "trace") || !strcmp(p, "t")) {
if (opt == 1)
val |= WL_MSCH_CMD_TRACE_BIT;
else
val &= ~WL_MSCH_CMD_TRACE_BIT;
}
else if (collectcmd && opt == 2 && !strcmp(p, "s") && *++argv) {
p = *argv;
v = (uint32)strtol(p, &endptr, 0);
if (*endptr == '\0') {
val &= ~WL_MSCH_CMD_SIZE_MASK;
val |= (v << WL_MSCH_CMD_SIZE_SHIFT);
} else {
err = BCME_EPERM;
break;
}
}
else {
err = BCME_EPERM;
break;
}
}
argv++;
}
if (eventcmd && (val & WL_MSCH_CMD_ENABLE_BIT)) {
uint8 event_inds_mask[WL_EVENTING_MASK_LEN];
/* read current mask state */
if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask,
WL_EVENTING_MASK_LEN))) {
fprintf(stderr, "couldn't read event_msgs\n");
goto exit;
}
event_inds_mask[WLC_E_MSCH / 8] |= (1 << (WLC_E_MSCH % 8));
if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask,
WL_EVENTING_MASK_LEN))) {
fprintf(stderr, "couldn't write event_msgs\n");
goto exit;
}
}
val &= ~WL_MSCH_CMD_VER_MASK;
val |= (WL_MSCH_PROFILER_VER << WL_MSCH_CMD_VER_SHIFT);
if (err == BCME_OK)
err = wlu_iovar_setint(wl, cmd->name, val);
exit:
return err;
}
typedef struct {
int num_fmts;
char **fmts;
char *raw_fmts;
char *raw_sstr;
uint32 fmts_size;
uint32 raw_fmts_size;
uint32 raw_sstr_size;
uint32 ramstart;
uint32 rodata_start;
uint32 rodata_end;
char *rom_raw_sstr;
uint32 rom_raw_sstr_size;
uint32 rom_ramstart;
uint32 rom_rodata_start;
uint32 rom_rodata_end;
} wl_event_log_t;
wl_event_log_t raw_event;
#define BYTES_AHEAD_NUM 11 /* address in map file is before these many bytes */
#define READ_NUM_BYTES 1000 /* read map file each time this No. of bytes */
#define GO_BACK_FILE_POS_NUM_BYTES 100 /* set file pos back to cur pos */
static char *ramstart_str = "text_start"; /* string in mapfile has addr ramstart */
static char *rodata_start_str = "rodata_start"; /* string in mapfile has addr rodata start */
static char *rodata_end_str = "rodata_end"; /* string in mapfile has addr rodata end */
#define RAMSTART_BIT 0x01
#define RDSTART_BIT 0x02
#define RDEND_BIT 0x04
#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
static char *logstrs_path = "/root/logstrs.bin";
static char *st_str_file_path = "/root/rtecdc.bin";
static char *map_file_path = "/root/rtecdc.map";
static char *rom_st_str_file_path = "/root/roml.bin";
static char *rom_map_file_path = "/root/roml.map";
static char *ram_file_str = "rtecdc";
static char *rom_file_str = "roml";
static int
wl_read_map(char *fname, uint32 *ramstart, uint32 *rodata_start, uint32 *rodata_end)
{
FILE *filep = NULL;
char *raw_fmts = NULL;
int read_size = READ_NUM_BYTES;
int keep_size = GO_BACK_FILE_POS_NUM_BYTES;
int error = 0;
char * cptr = NULL;
char c;
uint8 count = 0;
if (fname == NULL) {
fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
return BCME_ERROR;
}
filep = fopen(fname, "rb");
if (!filep) {
perror(fname);
fprintf(stderr, "Cannot open file %s\n", fname);
return BCME_ERROR;
}
*ramstart = 0;
*rodata_start = 0;
*rodata_end = 0;
/* Allocate 1 byte more than read_size to terminate it with NULL */
raw_fmts = (char *)malloc(read_size + keep_size + 1);
if (raw_fmts == NULL) {
fprintf(stderr, "%s: Failed to allocate raw_fmts memory \n", __FUNCTION__);
goto fail;
}
memset(raw_fmts, ' ', GO_BACK_FILE_POS_NUM_BYTES);
/* read ram start, rodata_start and rodata_end values from map file */
while (count != ALL_MAP_VAL)
{
error = fread(&raw_fmts[keep_size], 1, read_size, filep);
if (error < 0) {
fprintf(stderr, "%s: map file read failed err:%d \n", __FUNCTION__,
error);
goto fail;
}
/* End raw_fmts with NULL as strstr expects NULL terminated strings */
raw_fmts[read_size + keep_size] = '\0';
/* Get ramstart address */
if ((cptr = strstr(raw_fmts, ramstart_str))) {
cptr = cptr - BYTES_AHEAD_NUM;
sscanf(cptr, "%x %c text_start", ramstart, &c);
count |= RAMSTART_BIT;
}
/* Get ram rodata start address */
if ((cptr = strstr(raw_fmts, rodata_start_str))) {
cptr = cptr - BYTES_AHEAD_NUM;
sscanf(cptr, "%x %c rodata_start", rodata_start, &c);
count |= RDSTART_BIT;
}
/* Get ram rodata end address */
if ((cptr = strstr(raw_fmts, rodata_end_str))) {
cptr = cptr - BYTES_AHEAD_NUM;
sscanf(cptr, "%x %c rodata_end", rodata_end, &c);
count |= RDEND_BIT;
}
if (error < read_size) {
/*
* since we reset file pos back to earlier pos by
* GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
* The reason for this is if string is spreaded across
* bytes, the read function should not miss it.
* So if ret value is less than read_size, reached EOF don't read further
*/
break;
}
/*
* go back to predefined NUM of bytes so that we won't miss
* the string and addr even if it comes as splited in next read.
*/
memcpy(raw_fmts, &raw_fmts[read_size], keep_size);
}
fail:
if (filep) {
fclose(filep);
}
if (raw_fmts) {
free(raw_fmts);
}
if (count != ALL_MAP_VAL) {
fprintf(stderr, "%s: readmap error 0X%x \n", __FUNCTION__, count);
return BCME_ERROR;
}
return BCME_OK;
}
static void
wl_init_static_strs_array(char *str_file, char *map_file)
{
FILE *filep = NULL;
char *raw_fmts = NULL;
uint32 logstrs_size = 0;
int error = 0;
uint32 ramstart = 0;
uint32 rodata_start = 0;
uint32 rodata_end = 0;
uint32 logfilebase = 0;
error = wl_read_map(map_file, &ramstart, &rodata_start, &rodata_end);
if (error != BCME_OK) {
fprintf(stderr, "readmap Error!! \n");
/* don't do event log parsing in actual case */
if (strstr(str_file, ram_file_str) != NULL) {
raw_event.raw_sstr = NULL;
} else if (strstr(str_file, rom_file_str) != NULL) {
raw_event.rom_raw_sstr = NULL;
}
return;
}
if (str_file == NULL) {
fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
return;
}
filep = fopen(str_file, "rb");
if (!filep) {
perror(str_file);
fprintf(stderr, "Cannot open file %s\n", str_file);
return;
}
/* Full file size is huge. Just read required part */
logstrs_size = rodata_end - rodata_start;
raw_fmts = (char *)malloc(logstrs_size);
if (raw_fmts == NULL) {
fprintf(stderr, "%s: Failed to allocate raw_fmts memory \n", __FUNCTION__);
goto fail;
}
logfilebase = rodata_start - ramstart;
error = fseek(filep, logfilebase, SEEK_SET);
if (error < 0) {
fprintf(stderr, "%s: %s llseek failed %d \n", __FUNCTION__, str_file, error);
goto fail;
}
error = fread(raw_fmts, 1, logstrs_size, filep);
if (error != (int)logstrs_size) {
fprintf(stderr, "%s: %s read failed %d \n", __FUNCTION__, str_file, error);
goto fail;
}
if (strstr(str_file, ram_file_str) != NULL) {
raw_event.raw_sstr = raw_fmts;
raw_event.raw_sstr_size = logstrs_size;
raw_event.ramstart = ramstart;
raw_event.rodata_start = rodata_start;
raw_event.rodata_end = rodata_end;
} else if (strstr(str_file, rom_file_str) != NULL) {
raw_event.rom_raw_sstr = raw_fmts;
raw_event.rom_raw_sstr_size = logstrs_size;
raw_event.rom_ramstart = ramstart;
raw_event.rom_rodata_start = rodata_start;
raw_event.rom_rodata_end = rodata_end;
}
fclose(filep);
free(raw_fmts);
return;
fail:
if (raw_fmts) {
free(raw_fmts);
}
if (filep) {
fclose(filep);
}
if (strstr(str_file, ram_file_str) != NULL) {
raw_event.raw_sstr = NULL;
} else if (strstr(str_file, rom_file_str) != NULL) {
raw_event.rom_raw_sstr = NULL;
}
return;
}
static void
wl_init_logstrs_array(char *logstrs_path)
{
FILE *filep = NULL;
char *raw_fmts = NULL;
int logstrs_size = 0;
int error = 0;
logstr_header_t *hdr = NULL;
uint32 *lognums = NULL;
char *logstrs = NULL;
int ram_index = 0;
char **fmts = NULL;
int num_fmts = 0;
int i = 0;
if (logstrs_path == NULL) {
fprintf(stderr, "%s: ERROR fname is NULL \n", __FUNCTION__);
return;
}
filep = fopen(logstrs_path, "rb");
if (!filep) {
perror(logstrs_path);
fprintf(stderr, "Cannot open file %s\n", logstrs_path);
return;
}
if (fseek(filep, 0, SEEK_END) < 0 ||
(logstrs_size = ftell(filep)) < 0) {
fprintf(stderr, "%s: Could not determine size of %s \n", __FUNCTION__,
logstrs_path);
goto fail;
}
raw_fmts = (char *)malloc(logstrs_size);
if (raw_fmts == NULL) {
fprintf(stderr, "%s: Failed to allocate memory \n", __FUNCTION__);
goto fail;
}
fseek(filep, 0, SEEK_SET);
error = fread(raw_fmts, 1, logstrs_size, filep);
if (error != logstrs_size) {
fprintf(stderr, "%s: Failed to read file %s", __FUNCTION__, logstrs_path);
goto fail;
}
/* Remember header from the logstrs.bin file */
hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
sizeof(logstr_header_t));
if (hdr->log_magic == LOGSTRS_MAGIC) {
/*
* logstrs.bin start with header.
*/
num_fmts = hdr->rom_logstrs_offset / sizeof(uint32);
ram_index = (hdr->ram_lognums_offset -
hdr->rom_lognums_offset) / sizeof(uint32);
lognums = (uint32 *)&raw_fmts[hdr->rom_lognums_offset];
logstrs = (char *)&raw_fmts[hdr->rom_logstrs_offset];
} else {
/*
* Legacy logstrs.bin format without header.
*/
num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
if (num_fmts == 0) {
/* Legacy ROM/RAM logstrs.bin format:
* - ROM 'lognums' section
* - RAM 'lognums' section
* - ROM 'logstrs' section.
* - RAM 'logstrs' section.
*
* 'lognums' is an array of indexes for the strings in the
* 'logstrs' section. The first uint32 is 0 (index of first
* string in ROM 'logstrs' section).
*
* The 4324b5 is the only ROM that uses this legacy format. Use the
* fixed number of ROM fmtnums to find the start of the RAM
* 'lognums' section. Use the fixed first ROM string ("Con\n") to
* find the ROM 'logstrs' section.
*/
#define NUM_4324B5_ROM_FMTS 186
#define FIRST_4324B5_ROM_LOGSTR "Con\n"
ram_index = NUM_4324B5_ROM_FMTS;
lognums = (uint32 *) raw_fmts;
num_fmts = ram_index;
logstrs = (char *) &raw_fmts[num_fmts << 2];
while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
num_fmts++;
logstrs = (char *) &raw_fmts[num_fmts << 2];
}
} else {
/* Legacy RAM-only logstrs.bin format:
* - RAM 'lognums' section
* - RAM 'logstrs' section.
*
* 'lognums' is an array of indexes for the strings in the
* 'logstrs' section. The first uint32 is an index to the
* start of 'logstrs'. Therefore, if this index is divided
* by 'sizeof(uint32)' it provides the number of logstr
* entries.
*/
ram_index = 0;
lognums = (uint32 *)raw_fmts;
logstrs = (char *)&raw_fmts[num_fmts << 2];
}
}
if (num_fmts)
fmts = (char **)malloc(num_fmts * sizeof(char *));
if (fmts == NULL) {
fprintf(stderr, "%s: Failed to allocate fmts memory\n", __FUNCTION__);
goto fail;
}
raw_event.fmts_size = num_fmts * sizeof(char *);
for (i = 0; i < num_fmts; i++) {
/* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
* (they are 0-indexed relative to 'rom_logstrs_offset').
*
* RAM lognums are already indexed to point to the correct RAM logstrs (they
* are 0-indexed relative to the start of the logstrs.bin file).
*/
if (i == ram_index) {
logstrs = raw_fmts;
}
fmts[i] = &logstrs[lognums[i]];
}
raw_event.fmts = fmts;
raw_event.raw_fmts_size = logstrs_size;
raw_event.raw_fmts = raw_fmts;
raw_event.num_fmts = num_fmts;
fclose(filep);
return;
fail:
if (raw_fmts) {
free(raw_fmts);
}
if (filep) {
fclose(filep);
}
}
static int wl_init_frm_array(char *dir, char *files)
{
char *logstrs = NULL, *logstrs_d = NULL;
char *st_str_file = NULL, *st_str_file_d = NULL;
char *map_file = NULL, *map_file_d = NULL;
char *rom_st_str_file = NULL, *rom_st_str_file_d = NULL;
char *rom_map_file = NULL, *rom_map_file_d = NULL;
char *next, *str, *eq, *valstr;
size_t len;
if ((next = files)) {
while ((len = strcspn(next, " ,")) > 0) {
str = next;
next += len;
next += strspn(next, " ,");
str[len] = '\0';
eq = strchr(str, '=');
if (eq == NULL) {
fprintf(stderr, "wl_init_frm_array: missing \" = \" in file "
"param \"%s\"\n", str);
return BCME_USAGE_ERROR;
}
valstr = eq + 1;
if (*valstr == '\0') {
fprintf(stderr, "wl_init_frm_array: missing value after "
"\" = \" in file param \"%s\"\n", str);
return BCME_USAGE_ERROR;
}
*eq = '\0';
if (!strcmp(str, "logstrs_path"))
logstrs = valstr;
else if (!strcmp(str, "st_str_file_path"))
st_str_file = valstr;
else if (!strcmp(str, "map_file_path"))
map_file = valstr;
else if (!strcmp(str, "rom_st_str_file_path"))
rom_st_str_file = valstr;
else if (!strcmp(str, "rom_map_file_path"))
rom_map_file = valstr;
else {
fprintf(stderr, "wl_init_frm_array: error file %s\n", str);
return BCME_USAGE_ERROR;
}
}
}
if (dir) {
len = strlen(dir);
if (!logstrs) {
logstrs_d = (char *)malloc(len + 32);
logstrs = logstrs_d;
if (logstrs) {
strcpy(logstrs, dir);
strcat(logstrs, "/logstrs.bin");
}
}
if (!st_str_file) {
st_str_file_d = (char *)malloc(len + 32);
st_str_file = st_str_file_d;
if (st_str_file) {
strcpy(st_str_file, dir);
strcat(st_str_file, "/rtecdc.bin");
}
}
if (!map_file) {
map_file_d = (char *)malloc(len + 32);
map_file = map_file_d;
if (map_file) {
strcpy(map_file, dir);
strcat(map_file, "/rtecdc.map");
}
}
if (!rom_st_str_file) {
rom_st_str_file_d = (char *)malloc(len + 32);
rom_st_str_file = rom_st_str_file_d;
if (rom_st_str_file) {
strcpy(rom_st_str_file, dir);
strcat(rom_st_str_file, "/roml.bin");
}
}
if (!rom_map_file) {
rom_map_file_d = (char *)malloc(len + 32);
rom_map_file = rom_map_file_d;
if (rom_map_file) {
strcpy(rom_map_file, dir);
strcat(rom_map_file, "/roml.map");
}
}
}
if (!logstrs)
logstrs = logstrs_path;
if (!st_str_file)
st_str_file = st_str_file_path;
if (!map_file)
map_file = map_file_path;
if (!rom_st_str_file)
rom_st_str_file = rom_st_str_file_path;
if (!rom_map_file)
rom_map_file = rom_map_file_path;
wl_init_logstrs_array(logstrs);
wl_init_static_strs_array(st_str_file, map_file);
wl_init_static_strs_array(rom_st_str_file, rom_map_file);
if (dir) {
if (logstrs_d) {
free(logstrs_d);
}
if (st_str_file_d) {
free(st_str_file_d);
}
if (map_file_d) {
free(map_file_d);
}
if (rom_st_str_file_d) {
free(rom_st_str_file_d);
}
if (rom_map_file_d) {
free(rom_map_file_d);
}
}
return BCME_OK;
}
#define MSCH_EVENTS_PRINT(nbytes) \
do { \
printf("%s", mschbufp); \
if (mschfp) \
fwrite(mschbufp, 1, nbytes, mschfp); \
} while (0)
#define MSCH_EVENTS_SPPRINT(space) \
do { \
if (space > 0) { \
int ii; \
for (ii = 0; ii < space; ii++) mschbufp[ii] = ' '; \
mschbufp[space] = '\0'; \
MSCH_EVENTS_PRINT(space); \
} \
} while (0)
#define MSCH_EVENTS_PRINTF(fmt) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_PRINTF1(fmt, a) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
(a)); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_PRINTF2(fmt, a, b) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
(a), (b)); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_PRINTF3(fmt, a, b, c) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
(a), (b), (c)); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_PRINTF4(fmt, a, b, c, d) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
(a), (b), (c), (d)); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_PRINTF5(fmt, a, b, c, d, e) \
do { \
int nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmt, \
(a), (b), (c), (d), (e)); \
MSCH_EVENTS_PRINT(nbytes); \
} while (0)
#define MSCH_EVENTS_SPPRINTF(space, fmt) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF(fmt); \
} while (0)
#define MSCH_EVENTS_SPPRINTF1(space, fmt, a) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF1(fmt, (a)); \
} while (0)
#define MSCH_EVENTS_SPPRINTF2(space, fmt, a, b) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF2(fmt, (a), (b)); \
} while (0)
#define MSCH_EVENTS_SPPRINTF3(space, fmt, a, b, c) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF3(fmt, (a), (b), (c)); \
} while (0)
#define MSCH_EVENTS_SPPRINTF4(space, fmt, a, b, c, d) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF4(fmt, (a), (b), (c), (d)); \
} while (0)
#define MSCH_EVENTS_SPPRINTF5(space, fmt, a, b, c, d, e) \
do { \
MSCH_EVENTS_SPPRINT(space); \
MSCH_EVENTS_PRINTF5(fmt, (a), (b), (c), (d), (e)); \
} while (0)
static char *wl_msch_display_time(uint32 time_h, uint32 time_l)
{
static char display_time[32];
uint64 t;
uint32 s, ss;
if (time_h == 0xffffffff && time_l == 0xffffffff) {
snprintf(display_time, 31, "-1");
} else {
t = ((uint64)(ntoh32(time_h)) << 32) | ntoh32(time_l);
s = (uint32)(t / 1000000);
ss = (uint32)(t % 1000000);
snprintf(display_time, 31, "%d.%06d", s, ss);
}
return display_time;
}
static void
wl_msch_chanspec_list(int sp, char *data, uint16 ptr, uint16 chanspec_cnt)
{
int i, cnt = (int)ntoh16(chanspec_cnt);
uint16 *chanspec_list = (uint16 *)(data + ntoh16(ptr));
char buf[CHANSPEC_STR_LEN];
chanspec_t c;
MSCH_EVENTS_SPPRINTF(sp, "<chanspec_list>:");
for (i = 0; i < cnt; i++) {
c = (chanspec_t)ntoh16(chanspec_list[i]);
MSCH_EVENTS_PRINTF1(" %s", wf_chspec_ntoa(c, buf));
}
MSCH_EVENTS_PRINTF("\n");
}
static void
wl_msch_elem_list(int sp, char *title, char *data, uint16 ptr, uint16 list_cnt)
{
int i, cnt = (int)ntoh16(list_cnt);
uint32 *list = (uint32 *)(data + ntoh16(ptr));
MSCH_EVENTS_SPPRINTF1(sp, "%s_list: ", title);
for (i = 0; i < cnt; i++) {
MSCH_EVENTS_PRINTF1("0x%08x->", ntoh32(list[i]));
}
MSCH_EVENTS_PRINTF("null\n");
}
static void
wl_msch_req_param_profiler_data(int sp, int ver, char *data, uint16 ptr)
{
int sn = sp + 4;
msch_req_param_profiler_event_data_t *p =
(msch_req_param_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 type, flags;
UNUSED_PARAMETER(ver);
MSCH_EVENTS_SPPRINTF(sp, "<request parameters>\n");
MSCH_EVENTS_SPPRINTF(sn, "req_type: ");
type = p->req_type;
if (type < 4) {
char *req_type[] = {"fixed", "start-flexible", "duration-flexible",
"both-flexible"};
MSCH_EVENTS_PRINTF1("%s", req_type[type]);
}
else
MSCH_EVENTS_PRINTF1("unknown(%d)", type);
flags = ntoh16(p->flags);
if (flags & WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS)
MSCH_EVENTS_PRINTF(", CHAN_CONTIGUOUS");
if (flags & WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS)
MSCH_EVENTS_PRINTF(", MERGE_CONT_SLOTS");
if (flags & WL_MSCH_REQ_FLAGS_PREMTABLE)
MSCH_EVENTS_PRINTF(", PREMTABLE");
if (flags & WL_MSCH_REQ_FLAGS_PREMT_CURTS)
MSCH_EVENTS_PRINTF(", PREMT_CURTS");
if (flags & WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE)
MSCH_EVENTS_PRINTF(", PREMT_IMMEDIATE");
MSCH_EVENTS_PRINTF1(", priority: %d\n", p->priority);
MSCH_EVENTS_SPPRINTF3(sn, "start-time: %s, duration: %d(us), interval: %d(us)\n",
wl_msch_display_time(p->start_time_h, p->start_time_l),
ntoh32(p->duration), ntoh32(p->interval));
if (type == WL_MSCH_RT_DUR_FLEX)
MSCH_EVENTS_SPPRINTF1(sn, "dur_flex: %d(us)\n", ntoh32(p->flex.dur_flex));
else if (type == WL_MSCH_RT_BOTH_FLEX) {
MSCH_EVENTS_SPPRINTF2(sn, "min_dur: %d(us), max_away_dur: %d(us)\n",
ntoh32(p->flex.bf.min_dur), ntoh32(p->flex.bf.max_away_dur));
MSCH_EVENTS_SPPRINTF2(sn, "hi_prio_time: %s, hi_prio_interval: %d(us)\n",
wl_msch_display_time(p->flex.bf.hi_prio_time_h,
p->flex.bf.hi_prio_time_l),
ntoh32(p->flex.bf.hi_prio_interval));
}
}
static void
wl_msch_timeslot_profiler_data(int sp, int ver, char *title, char *data, uint16 ptr, bool empty)
{
int s, sn = sp + 4;
msch_timeslot_profiler_event_data_t *p =
(msch_timeslot_profiler_event_data_t *)(data + ntoh16(ptr));
char *state[] = {"NONE", "CHN_SW", "ONCHAN_FIRE", "OFF_CHN_PREP",
"OFF_CHN_DONE", "TS_COMPLETE"};
UNUSED_PARAMETER(ver);
MSCH_EVENTS_SPPRINTF1(sp, "<%s timeslot>: ", title);
if (empty) {
MSCH_EVENTS_PRINTF(" null\n");
return;
}
else
MSCH_EVENTS_PRINTF1("0x%08x\n", ntoh32(p->p_timeslot));
s = (int)(ntoh32(p->state));
if (s > 5) s = 0;
MSCH_EVENTS_SPPRINTF4(sn, "id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n",
ntoh32(p->timeslot_id), ntoh32(p->state), state[s], ntoh32(p->p_chan_ctxt));
MSCH_EVENTS_SPPRINTF1(sn, "fire_time: %s",
wl_msch_display_time(p->fire_time_h, p->fire_time_l));
MSCH_EVENTS_PRINTF1(", pre_start_time: %s",
wl_msch_display_time(p->pre_start_time_h, p->pre_start_time_l));
MSCH_EVENTS_PRINTF1(", end_time: %s",
wl_msch_display_time(p->end_time_h, p->end_time_l));
MSCH_EVENTS_PRINTF1(", sch_dur: %s\n",
wl_msch_display_time(p->sch_dur_h, p->sch_dur_l));
}
static void
wl_msch_req_timing_profiler_data(int sp, int ver, char *title, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_timing_profiler_event_data_t *p =
(msch_req_timing_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 type;
UNUSED_PARAMETER(ver);
MSCH_EVENTS_SPPRINTF1(sp, "<%s req_timing>: ", title);
if (empty) {
MSCH_EVENTS_PRINTF(" null\n");
return;
}
else
MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_timing), ntoh32(p->p_prev), ntoh32(p->p_next));
MSCH_EVENTS_SPPRINTF(sn, "flags:");
type = ntoh16(p->flags);
if ((type & 0x7f) == 0)
MSCH_EVENTS_PRINTF(" NONE");
else {
if (type & WL_MSCH_RC_FLAGS_ONCHAN_FIRE)
MSCH_EVENTS_PRINTF(" ONCHAN_FIRE");
if (type & WL_MSCH_RC_FLAGS_START_FIRE_DONE)
MSCH_EVENTS_PRINTF(" START_FIRE");
if (type & WL_MSCH_RC_FLAGS_END_FIRE_DONE)
MSCH_EVENTS_PRINTF(" END_FIRE");
if (type & WL_MSCH_RC_FLAGS_ONFIRE_DONE)
MSCH_EVENTS_PRINTF(" ONFIRE_DONE");
if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_START)
MSCH_EVENTS_PRINTF(" SPLIT_SLOT_START");
if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_END)
MSCH_EVENTS_PRINTF(" SPLIT_SLOT_END");
if (type & WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE)
MSCH_EVENTS_PRINTF(" PRE_ONFIRE_DONE");
}
MSCH_EVENTS_PRINTF("\n");
MSCH_EVENTS_SPPRINTF1(sn, "pre_start_time: %s",
wl_msch_display_time(p->pre_start_time_h, p->pre_start_time_l));
MSCH_EVENTS_PRINTF1(", start_time: %s",
wl_msch_display_time(p->start_time_h, p->start_time_l));
MSCH_EVENTS_PRINTF1(", end_time: %s\n",
wl_msch_display_time(p->end_time_h, p->end_time_l));
if (p->p_timeslot && (p->timeslot_ptr == 0))
MSCH_EVENTS_SPPRINTF2(sn, "<%s timeslot>: 0x%08x\n", title, ntoh32(p->p_timeslot));
else
wl_msch_timeslot_profiler_data(sn, ver, title, data, p->timeslot_ptr,
(p->timeslot_ptr == 0));
}
static void
wl_msch_chan_ctxt_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_chan_ctxt_profiler_event_data_t *p =
(msch_chan_ctxt_profiler_event_data_t *)(data + ntoh16(ptr));
chanspec_t c;
char buf[CHANSPEC_STR_LEN];
UNUSED_PARAMETER(ver);
MSCH_EVENTS_SPPRINTF(sp, "<chan_ctxt>: ");
if (empty) {
MSCH_EVENTS_PRINTF(" null\n");
return;
}
else
MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_chan_ctxt), ntoh32(p->p_prev), ntoh32(p->p_next));
c = (chanspec_t)ntoh16(p->chanspec);
MSCH_EVENTS_SPPRINTF3(sn, "channel: %s, bf_sch_pending: %s, bf_skipped: %d\n",
wf_chspec_ntoa(c, buf), p->bf_sch_pending? "TRUE" : "FALSE",
ntoh32(p->bf_skipped_count));
MSCH_EVENTS_SPPRINTF2(sn, "bf_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->bf_link_prev), ntoh32(p->bf_link_next));
MSCH_EVENTS_SPPRINTF1(sn, "onchan_time: %s",
wl_msch_display_time(p->onchan_time_h, p->onchan_time_l));
MSCH_EVENTS_PRINTF1(", actual_onchan_dur: %s",
wl_msch_display_time(p->actual_onchan_dur_h, p->actual_onchan_dur_l));
MSCH_EVENTS_PRINTF1(", pend_onchan_dur: %s\n",
wl_msch_display_time(p->pend_onchan_dur_h, p->pend_onchan_dur_l));
wl_msch_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, p->req_entity_list_cnt);
wl_msch_elem_list(sn, "bf_entity", data, p->bf_entity_list_ptr, p->bf_entity_list_cnt);
}
static void
wl_msch_req_entity_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_entity_profiler_event_data_t *p =
(msch_req_entity_profiler_event_data_t *)(data + ntoh16(ptr));
char buf[CHANSPEC_STR_LEN];
chanspec_t c;
uint32 flags;
MSCH_EVENTS_SPPRINTF(sp, "<req_entity>: ");
if (empty) {
MSCH_EVENTS_PRINTF(" null\n");
return;
}
else
MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_entity), ntoh32(p->req_hdl_link_prev),
ntoh32(p->req_hdl_link_next));
MSCH_EVENTS_SPPRINTF1(sn, "req_hdl: [0x%08x]\n", ntoh32(p->p_req_hdl));
MSCH_EVENTS_SPPRINTF2(sn, "chan_ctxt_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->chan_ctxt_link_prev), ntoh32(p->chan_ctxt_link_next));
MSCH_EVENTS_SPPRINTF2(sn, "rt_specific_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->rt_specific_link_prev), ntoh32(p->rt_specific_link_next));
MSCH_EVENTS_SPPRINTF2(sn, "start_fixed_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->start_fixed_link_prev), ntoh32(p->start_fixed_link_next));
MSCH_EVENTS_SPPRINTF2(sn, "both_flex_list: prev 0x%08x, next 0x%08x\n",
ntoh32(p->both_flex_list_prev), ntoh32(p->both_flex_list_next));
c = (chanspec_t)ntoh16(p->chanspec);
if (ver >= 2) {
MSCH_EVENTS_SPPRINTF4(sn, "channel: %s, onchan Id %d, current chan Id %d, "
"priority %d", wf_chspec_ntoa(c, buf), ntoh16(p->onchan_chn_idx),
ntoh16(p->cur_chn_idx), ntoh16(p->priority));
flags = ntoh32(p->flags);
if (flags & WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE)
MSCH_EVENTS_PRINTF(" : MULTI_INSTANCE\n");
else
MSCH_EVENTS_PRINTF("\n");
MSCH_EVENTS_SPPRINTF1(sn, "actual_start_time: %s, ",
wl_msch_display_time(p->actual_start_time_h, p->actual_start_time_l));
MSCH_EVENTS_PRINTF1("curts_fire_time: %s, ",
wl_msch_display_time(p->curts_fire_time_h, p->curts_fire_time_l));
} else {
MSCH_EVENTS_SPPRINTF2(sn, "channel: %s, priority %d, ", wf_chspec_ntoa(c, buf),
ntoh16(p->priority));
}
MSCH_EVENTS_PRINTF1("bf_last_serv_time: %s\n",
wl_msch_display_time(p->bf_last_serv_time_h, p->bf_last_serv_time_l));
wl_msch_req_timing_profiler_data(sn, ver, "current", data, p->cur_slot_ptr,
(p->cur_slot_ptr == 0));
wl_msch_req_timing_profiler_data(sn, ver, "pending", data, p->pend_slot_ptr,
(p->pend_slot_ptr == 0));
if (p->p_chan_ctxt && (p->chan_ctxt_ptr == 0))
MSCH_EVENTS_SPPRINTF1(sn, "<chan_ctxt>: 0x%08x\n", ntoh32(p->p_chan_ctxt));
else
wl_msch_chan_ctxt_profiler_data(sn, ver, data, p->chan_ctxt_ptr,
(p->chan_ctxt_ptr == 0));
}
static void
wl_msch_req_handle_profiler_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_handle_profiler_event_data_t *p =
(msch_req_handle_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 flags;
MSCH_EVENTS_SPPRINTF(sp, "<req_handle>: ");
if (empty) {
MSCH_EVENTS_PRINTF(" null\n");
return;
}
else
MSCH_EVENTS_PRINTF3("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_handle), ntoh32(p->p_prev), ntoh32(p->p_next));
wl_msch_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, p->req_entity_list_cnt);
MSCH_EVENTS_SPPRINTF2(sn, "cb_func: [0x%08x], cb_func: [0x%08x]",
ntoh32(p->cb_func), ntoh32(p->cb_ctxt));
if (ver < 2) {
MSCH_EVENTS_PRINTF1(", chan_cnt: %d", ntoh16(p->chan_cnt));
}
flags = ntoh32(p->flags);
if (flags & WL_MSCH_REQ_HDL_FLAGS_NEW_REQ)
MSCH_EVENTS_PRINTF(", NEW_REQ");
MSCH_EVENTS_PRINTF("\n");
wl_msch_req_param_profiler_data(sn, ver, data, p->req_param_ptr);
if (ver >= 2) {
MSCH_EVENTS_SPPRINTF1(sn, "req_time: %s\n",
wl_msch_display_time(p->req_time_h, p->req_time_l));
MSCH_EVENTS_SPPRINTF3(sn, "chan_cnt: %d, chan idx %d, last chan idx %d\n",
ntoh16(p->chan_cnt), ntoh16(p->chan_idx), ntoh16(p->last_chan_idx));
if (p->chanspec_list && p->chanspec_cnt) {
wl_msch_chanspec_list(sn, data, p->chanspec_list, p->chanspec_cnt);
}
}
}
static void
wl_msch_profiler_profiler_data(int sp, int ver, char *data, uint16 ptr)
{
msch_profiler_profiler_event_data_t *p =
(msch_profiler_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 flags;
MSCH_EVENTS_SPPRINTF4(sp, "free list: req_hdl 0x%08x, req_entity 0x%08x,"
" chan_ctxt 0x%08x, chanspec 0x%08x\n",
ntoh32(p->free_req_hdl_list), ntoh32(p->free_req_entity_list),
ntoh32(p->free_chan_ctxt_list), ntoh32(p->free_chanspec_list));
MSCH_EVENTS_SPPRINTF5(sp, "alloc count: chanspec %d, req_entity %d, req_hdl %d, "
"chan_ctxt %d, timeslot %d\n",
ntoh16(p->msch_chanspec_alloc_cnt), ntoh16(p->msch_req_entity_alloc_cnt),
ntoh16(p->msch_req_hdl_alloc_cnt), ntoh16(p->msch_chan_ctxt_alloc_cnt),
ntoh16(p->msch_timeslot_alloc_cnt));
wl_msch_elem_list(sp, "req_hdl", data, p->msch_req_hdl_list_ptr,
p->msch_req_hdl_list_cnt);
wl_msch_elem_list(sp, "chan_ctxt", data, p->msch_chan_ctxt_list_ptr,
p->msch_chan_ctxt_list_cnt);
wl_msch_elem_list(sp, "req_timing", data, p->msch_req_timing_list_ptr,
p->msch_req_timing_list_cnt);
wl_msch_elem_list(sp, "start_fixed", data, p->msch_start_fixed_list_ptr,
p->msch_start_fixed_list_cnt);
wl_msch_elem_list(sp, "both_flex_req_entity", data,
p->msch_both_flex_req_entity_list_ptr,
p->msch_both_flex_req_entity_list_cnt);
wl_msch_elem_list(sp, "start_flex", data, p->msch_start_flex_list_ptr,
p->msch_start_flex_list_cnt);
wl_msch_elem_list(sp, "both_flex", data, p->msch_both_flex_list_ptr,
p->msch_both_flex_list_cnt);
if (p->p_cur_msch_timeslot && (p->cur_msch_timeslot_ptr == 0))
MSCH_EVENTS_SPPRINTF1(sp, "<cur_msch timeslot>: 0x%08x\n",
ntoh32(p->p_cur_msch_timeslot));
else
wl_msch_timeslot_profiler_data(sp, ver, "cur_msch", data,
p->cur_msch_timeslot_ptr, (p->cur_msch_timeslot_ptr == 0));
if (p->p_next_timeslot && (p->next_timeslot_ptr == 0))
MSCH_EVENTS_SPPRINTF1(sp, "<next timeslot>: 0x%08x\n", ntoh32(p->p_next_timeslot));
else
wl_msch_timeslot_profiler_data(sp, ver, "next", data,
p->next_timeslot_ptr, (p->next_timeslot_ptr == 0));
MSCH_EVENTS_SPPRINTF1(sp, "ts_id: %d, ", ntoh32(p->ts_id));
flags = ntoh32(p->flags);
if (flags & WL_MSCH_STATE_IN_TIEMR_CTXT)
MSCH_EVENTS_PRINTF("IN_TIEMR_CTXT, ");
if (flags & WL_MSCH_STATE_SCHD_PENDING)
MSCH_EVENTS_PRINTF("SCHD_PENDING, ");
MSCH_EVENTS_PRINTF2("slotskip_flags: %d, cur_armed_timeslot: 0x%08x\n",
(ver >= 2)? ntoh32(p->slotskip_flag) : 0, ntoh32(p->cur_armed_timeslot));
MSCH_EVENTS_SPPRINTF3(sp, "flex_list_cnt: %d, service_interval: %d, "
"max_lo_prio_interval: %d\n",
ntoh16(p->flex_list_cnt), ntoh32(p->service_interval),
ntoh32(p->max_lo_prio_interval));
}
#define MAX_NO_OF_ARG 10
#define FMTSTR_SIZE 132
#define ROMSTR_SIZE 200
#define SIZE_LOC_STR 50
static bool
check_valid_string_format(char *curr_ptr)
{
char *next_ptr;
if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) {
/* Default %s format */
if (curr_ptr == next_ptr) {
return TRUE;
}
/* Verify each charater between '%' and 's' is a valid number */
while (curr_ptr < next_ptr) {
if (bcm_isdigit(*curr_ptr) == FALSE) {
return FALSE;
}
curr_ptr++;
}
return TRUE;
} else {
return FALSE;
}
}
static void
wl_msch_profiler_event_log_data(int ver, event_log_hdr_t *hdr, uint32 *data)
{
uint16 count;
char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 };
char (*str_buf)[SIZE_LOC_STR] = NULL;
char *str_tmpptr = NULL;
uint32 addr = 0;
typedef union {
uint32 val;
char * addr;
} u_arg;
u_arg arg[MAX_NO_OF_ARG] = {{0}};
char *c_ptr = NULL;
int nbytes;
UNUSED_PARAMETER(ver);
/* print the message out in a logprint */
if (!(((raw_event.raw_sstr) || (raw_event.rom_raw_sstr)) &&
raw_event.fmts) || hdr->fmt_num == 0xffff) {
MSCH_EVENTS_PRINTF2("0.0 EL: %x %x",
hdr->tag & EVENT_LOG_TAG_FLAG_SET_MASK,
hdr->fmt_num);
for (count = 0; count < hdr->count; count++)
MSCH_EVENTS_PRINTF1(" %x", data[count]);
MSCH_EVENTS_PRINTF("\n");
return;
}
str_buf = malloc(MAX_NO_OF_ARG * SIZE_LOC_STR);
if (!str_buf) {
fprintf(stderr, "%s: malloc failed str_buf\n", __FUNCTION__);
return;
}
if ((hdr->fmt_num >> 2) < raw_event.num_fmts) {
snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s",
raw_event.fmts[hdr->fmt_num >> 2]);
c_ptr = fmtstr_loc_buf;
} else {
fprintf(stderr, "%s: fmt number out of range \n", __FUNCTION__);
goto exit;
}
for (count = 0; count < hdr->count; count++) {
if (c_ptr != NULL)
if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL)
c_ptr++;
if (c_ptr != NULL) {
if (check_valid_string_format(c_ptr)) {
if ((raw_event.raw_sstr) &&
((data[count] > raw_event.rodata_start) &&
(data[count] < raw_event.rodata_end))) {
/* ram static string */
addr = data[count] - raw_event.rodata_start;
str_tmpptr = raw_event.raw_sstr + addr;
memcpy(str_buf[count], str_tmpptr,
SIZE_LOC_STR);
str_buf[count][SIZE_LOC_STR-1] = '\0';
arg[count].addr = str_buf[count];
} else if ((raw_event.rom_raw_sstr) &&
((data[count] >
raw_event.rom_rodata_start) &&
(data[count] <
raw_event.rom_rodata_end))) {
/* rom static string */
addr = data[count] - raw_event.rom_rodata_start;
str_tmpptr = raw_event.rom_raw_sstr + addr;
memcpy(str_buf[count], str_tmpptr,
SIZE_LOC_STR);
str_buf[count][SIZE_LOC_STR-1] = '\0';
arg[count].addr = str_buf[count];
} else {
/*
* Dynamic string OR
* No data for static string.
* So store all string's address as string.
*/
snprintf(str_buf[count], SIZE_LOC_STR,
"(s)0x%x", data[count]);
arg[count].addr = str_buf[count];
}
} else {
/* Other than string */
arg[count].val = data[count];
}
}
}
nbytes = snprintf(mschbufp, WL_MSCH_PROFILER_BUFFER_SIZE, fmtstr_loc_buf,
arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
MSCH_EVENTS_PRINT(nbytes);
exit:
free(str_buf);
}
static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4];
static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, };
static bool lastMessages = FALSE;
static void wl_msch_dump_data(char *data, int type)
{
uint64 t = 0, tt = 0;
uint32 s = 0, ss = 0;
int wlc_index, ver;
ver = (type & WL_MSCH_PROFILER_VER_MASK) >> WL_MSCH_PROFILER_VER_SHIFT;
wlc_index = (type & WL_MSCH_PROFILER_WLINDEX_MASK) >> WL_MSCH_PROFILER_WLINDEX_SHIFT;
if (wlc_index >= 4)
return;
type &= WL_MSCH_PROFILER_TYPE_MASK;
if (type <= WL_MSCH_PROFILER_PROFILE_END || type == WL_MSCH_PROFILER_EVENT_LOG) {
msch_profiler_event_data_t *pevent = (msch_profiler_event_data_t *)data;
tt = ((uint64)(ntoh32(pevent->time_hi)) << 32) | ntoh32(pevent->time_lo);
s = (uint32)(tt / 1000000);
ss = (uint32)(tt % 1000000);
}
if (lastMessages && (type != WL_MSCH_PROFILER_MESSAGE) &&
(type != WL_MSCH_PROFILER_EVENT_LOG)) {
MSCH_EVENTS_PRINTF("\n");
lastMessages = FALSE;
}
switch (type) {
case WL_MSCH_PROFILER_START:
MSCH_EVENTS_PRINTF2("\n%06d.%06d START\n", s, ss);
break;
case WL_MSCH_PROFILER_EXIT:
MSCH_EVENTS_PRINTF2("\n%06d.%06d EXIT\n", s, ss);
break;
case WL_MSCH_PROFILER_REQ:
{
msch_req_profiler_event_data_t *p = (msch_req_profiler_event_data_t *)data;
MSCH_EVENTS_PRINTF("\n===============================\n");
MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] REGISTER:\n", s, ss, wlc_index);
wl_msch_req_param_profiler_data(4, ver, data, p->req_param_ptr);
wl_msch_chanspec_list(4, data, p->chanspec_ptr, p->chanspec_cnt);
MSCH_EVENTS_PRINTF("===============================\n\n");
}
break;
case WL_MSCH_PROFILER_CALLBACK:
{
msch_callback_profiler_event_data_t *p =
(msch_callback_profiler_event_data_t *)data;
char buf[CHANSPEC_STR_LEN];
uint16 cbtype;
MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] CALLBACK: ", s, ss, wlc_index);
ss = ntoh16(p->chanspec);
if (ver >= 2) {
MSCH_EVENTS_PRINTF2("req_hdl[0x%08x], channel %s --",
ntoh32(p->p_req_hdl), wf_chspec_ntoa(ss, buf));
} else {
MSCH_EVENTS_PRINTF1("channel %s --", wf_chspec_ntoa(ss, buf));
}
cbtype = ntoh16(p->type);
if (cbtype & WL_MSCH_CT_ON_CHAN)
MSCH_EVENTS_PRINTF(" ON_CHAN");
if (cbtype & WL_MSCH_CT_OFF_CHAN)
MSCH_EVENTS_PRINTF(" OFF_CHAN");
if (cbtype & WL_MSCH_CT_REQ_START)
MSCH_EVENTS_PRINTF(" REQ_START");
if (cbtype & WL_MSCH_CT_REQ_END)
MSCH_EVENTS_PRINTF(" REQ_END");
if (cbtype & WL_MSCH_CT_SLOT_START)
MSCH_EVENTS_PRINTF(" SLOT_START");
if (cbtype & WL_MSCH_CT_SLOT_SKIP)
MSCH_EVENTS_PRINTF(" SLOT_SKIP");
if (cbtype & WL_MSCH_CT_SLOT_END)
MSCH_EVENTS_PRINTF(" SLOT_END");
if (cbtype & WL_MSCH_CT_OFF_CHAN_DONE)
MSCH_EVENTS_PRINTF(" OFF_CHAN_DONE");
if (cbtype & WL_MSCH_CT_PARTIAL)
MSCH_EVENTS_PRINTF(" PARTIAL");
if (cbtype & WL_MSCH_CT_PRE_ONCHAN)
MSCH_EVENTS_PRINTF(" PRE_ONCHAN");
if (cbtype & WL_MSCH_CT_PRE_REQ_START)
MSCH_EVENTS_PRINTF(" PRE_REQ_START");
if (cbtype & (WL_MSCH_CT_ON_CHAN | WL_MSCH_CT_SLOT_SKIP)) {
MSCH_EVENTS_PRINTF("\n ");
if (cbtype & WL_MSCH_CT_ON_CHAN) {
if (ver >= 2) {
MSCH_EVENTS_PRINTF3("ID %d onchan idx %d seq_start %s ",
ntoh32(p->timeslot_id), ntoh32(p->onchan_idx),
wl_msch_display_time(p->cur_chan_seq_start_time_h,
p->cur_chan_seq_start_time_l));
} else {
MSCH_EVENTS_PRINTF1("ID %d ", ntoh32(p->timeslot_id));
}
}
t = ((uint64)(ntoh32(p->start_time_h)) << 32) |
ntoh32(p->start_time_l);
MSCH_EVENTS_PRINTF1("start %s ",
wl_msch_display_time(p->start_time_h,
p->start_time_l));
tt = ((uint64)(ntoh32(p->end_time_h)) << 32) | ntoh32(p->end_time_l);
MSCH_EVENTS_PRINTF2("end %s duration %d",
wl_msch_display_time(p->end_time_h, p->end_time_l),
(p->end_time_h == 0xffffffff && p->end_time_l == 0xffffffff)?
-1 : (int)(tt - t));
}
if (cbtype & WL_MSCH_CT_REQ_START) {
req_start[wlc_index] = 1;
req_start_time[wlc_index] = tt;
} else if (cbtype & WL_MSCH_CT_REQ_END) {
if (req_start[wlc_index]) {
MSCH_EVENTS_PRINTF1(" : REQ duration %d",
(uint32)(tt - req_start_time[wlc_index]));
req_start[wlc_index] = 0;
}
}
if (cbtype & WL_MSCH_CT_SLOT_START) {
solt_chanspec[wlc_index] = p->chanspec;
solt_start_time[wlc_index] = tt;
} else if (cbtype & WL_MSCH_CT_SLOT_END) {
if (p->chanspec == solt_chanspec[wlc_index]) {
MSCH_EVENTS_PRINTF1(" : SLOT duration %d",
(uint32)(tt - solt_start_time[wlc_index]));
solt_chanspec[wlc_index] = 0;
}
}
MSCH_EVENTS_PRINTF("\n");
}
break;
case WL_MSCH_PROFILER_EVENT_LOG:
{
msch_event_log_profiler_event_data_t *p =
(msch_event_log_profiler_event_data_t *)data;
p->hdr.fmt_num = ntoh16(p->hdr.fmt_num);
MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d]: ", s, ss, wlc_index);
wl_msch_profiler_event_log_data(ver, &p->hdr, p->data);
lastMessages = TRUE;
break;
}
case WL_MSCH_PROFILER_MESSAGE:
{
msch_message_profiler_event_data_t *p = (msch_message_profiler_event_data_t *)data;
MSCH_EVENTS_PRINTF4("%06d.%06d [wl%d]: %s", s, ss, wlc_index, p->message);
lastMessages = TRUE;
break;
}
case WL_MSCH_PROFILER_PROFILE_START:
profiler_start_time[wlc_index] = tt;
MSCH_EVENTS_PRINTF("-------------------------------\n");
MSCH_EVENTS_PRINTF3("%06d.%06d [wl%d] PROFILE DATA:\n", s, ss, wlc_index);
wl_msch_profiler_profiler_data(4, ver, data, 0);
break;
case WL_MSCH_PROFILER_PROFILE_END:
MSCH_EVENTS_PRINTF4("%06d.%06d [wl%d] PROFILE END: take time %d\n", s, ss,
wlc_index, (uint32)(tt - profiler_start_time[wlc_index]));
MSCH_EVENTS_PRINTF("-------------------------------\n\n");
break;
case WL_MSCH_PROFILER_REQ_HANDLE:
wl_msch_req_handle_profiler_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_REQ_ENTITY:
wl_msch_req_entity_profiler_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_CHAN_CTXT:
wl_msch_chan_ctxt_profiler_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_REQ_TIMING:
wl_msch_req_timing_profiler_data(4, ver, "msch", data, 0, FALSE);
break;
default:
fprintf(stderr, "[wl%d] ERROR: unsupported EVENT reason code:%d; ",
wlc_index, type);
break;
}
}
int wl_msch_dump(void *wl, cmd_t *cmd, char **argv)
{
void *ptr;
int type;
char *data, *p, opt;
char *fname = NULL, *dir = NULL, *files = NULL;
int val, err, start = 1;
UNUSED_PARAMETER(wl);
UNUSED_PARAMETER(cmd);
while ((p = *++argv) != NULL) {
if (!strcmp(p, "--help") || !strcmp(p, "-h")) {
printf("%s", cmd->help);
return BCME_OK;
}
if (!strncmp(p, "-", 1)) {
opt = p[1];
if (strlen(p) > 2) {
fprintf(stderr, "wl_msch_dump: only single char options, "
"error on param \"%s\"\n", p);
return BCME_BADARG;
}
argv++;
if (*argv == NULL) {
fprintf(stderr, "wl_msch_dump: missing value parameter "
"after \"%s\"\n", p);
return BCME_USAGE_ERROR;
}
if (opt == 'D')
dir = *argv;
else if (opt == 'F')
files = *argv;
else {
fprintf(stderr, "error param: %s\n", p);
return BCME_BADARG;
}
} else if (!fname) {
fname = p;
} else {
fprintf(stderr, "error param: %s\n", p);
return BCME_BADARG;
}
}
if ((err = wlu_iovar_getint(wl, "msch_collect", &val)) < 0)
return err;
if (!(val & WL_MSCH_CMD_ENABLE_BIT))
return BCME_NOTREADY;
if (fname) {
if (!(mschfp = fopen(fname, "wb"))) {
perror(fname);
fprintf(stderr, "Cannot open file %s\n", fname);
return BCME_BADARG;
}
}
wl_init_frm_array(dir, files);
err = wlu_var_getbuf(wl, "msch_dump", &start, sizeof(int), &ptr);
while (err >= 0) {
msch_collect_tlv_t *ptlv = (msch_collect_tlv_t *)ptr;
type = dtoh16(ptlv->type);
data = ptlv->value;
wl_msch_dump_data(data, type);
err = wlu_var_getbuf(wl, "msch_dump", NULL, 0, &ptr);
}
if (mschfp) {
fflush(mschfp);
fclose(mschfp);
mschfp = NULL;
}
fflush(stdout);
return BCME_OK;
}
#if defined(linux)
int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len);
int wl_msch_event_check(void *wl, cmd_t *cmd, char **argv)
{
int fd, err, octets;
struct sockaddr_ll sll;
struct ifreq ifr;
char ifnames[IFNAMSIZ] = {"eth0"};
bcm_event_t *event;
char *data;
int event_type, reason;
uint8 event_inds_mask[WL_EVENTING_MASK_LEN];
char *p, *fname = NULL, *dir = NULL, *files = NULL;
int opt, val;
UNUSED_PARAMETER(wl);
UNUSED_PARAMETER(cmd);
if (argv[1] == NULL) {
fprintf(stderr, "<ifname> param is missing\n");
return -1;
}
if (*++argv) {
if (!strcmp(*argv, "--help") || !strcmp(*argv, "-h")) {
printf("%s", cmd->help);
return BCME_OK;
}
strncpy(ifnames, *argv, (IFNAMSIZ - 1));
}
if ((err = wlu_iovar_getint(wl, "msch_event", &val)) < 0)
return err;
bzero(&ifr, sizeof(ifr));
strncpy(ifr.ifr_name, ifnames, (IFNAMSIZ - 1));
fd = socket(PF_PACKET, SOCK_RAW, hton16(ETHER_TYPE_BRCM));
if (fd < 0) {
fprintf(stderr, "Cannot create socket %d\n", fd);
return -1;
}
err = ioctl(fd, SIOCGIFINDEX, &ifr);
if (err < 0) {
fprintf(stderr, "Cannot get iface:%s index \n", ifr.ifr_name);
goto exit;
}
bzero(&sll, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_protocol = hton16(ETHER_TYPE_BRCM);
sll.sll_ifindex = ifr.ifr_ifindex;
err = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
if (err < 0) {
fprintf(stderr, "Cannot bind %d\n", err);
goto exit;
}
while (*++argv) {
opt = 0;
p = *argv;
if (p[0] == '+') {
opt = 1;
p++;
}
else if (p[0] == '-') {
opt = 2;
p++;
}
if (opt == 0) {
fname = p;
if (mschfp == NULL) {
if (!(mschfp = fopen(fname, "wb"))) {
perror(fname);
fprintf(stderr, "Cannot open file %s\n", fname);
err = BCME_BADARG;
goto exit;
}
}
else {
err = BCME_BADARG;
fprintf(stderr, "error param: %s\n", p);
goto exit;
}
} else {
if (opt == 2 && (!strcmp(p, "all") || !strcmp(p, "a"))) {
val &= ~WL_MSCH_CMD_ALL_BITS;
} else if (!strcmp(p, "profiler") || !strcmp(p, "p")) {
if (opt == 1)
val |= WL_MSCH_CMD_PROFILE_BIT;
else
val &= ~WL_MSCH_CMD_PROFILE_BIT;
}
else if (!strcmp(p, "callback") || !strcmp(p, "c")) {
if (opt == 1)
val |= WL_MSCH_CMD_CALLBACK_BIT;
else
val &= ~WL_MSCH_CMD_CALLBACK_BIT;
}
else if (!strcmp(p, "register") || !strcmp(p, "r")) {
if (opt == 1)
val |= WL_MSCH_CMD_REGISTER_BIT;
else
val &= ~WL_MSCH_CMD_REGISTER_BIT;
}
else if (!strcmp(p, "error") || !strcmp(p, "e")) {
if (opt == 1)
val |= WL_MSCH_CMD_ERROR_BIT;
else
val &= ~WL_MSCH_CMD_ERROR_BIT;
}
else if (!strcmp(p, "debug") || !strcmp(p, "d")) {
if (opt == 1)
val |= WL_MSCH_CMD_DEBUG_BIT;
else
val &= ~WL_MSCH_CMD_DEBUG_BIT;
}
else if (!strcmp(p, "info") || !strcmp(p, "i")) {
if (opt == 1)
val |= WL_MSCH_CMD_INFOM_BIT;
else
val &= ~WL_MSCH_CMD_INFOM_BIT;
}
else if (!strcmp(p, "trace") || !strcmp(p, "t")) {
if (opt == 1)
val |= WL_MSCH_CMD_TRACE_BIT;
else
val &= ~WL_MSCH_CMD_TRACE_BIT;
}
else if (opt == 2 && !strcmp(p, "D") && *++argv) {
dir = *argv;
printf("dir: %s\n", dir);
}
else if (opt == 2 && !strcmp(p, "F") && *++argv) {
files = *argv;
printf("files: %s\n", files);
}
else {
err = BCME_EPERM;
goto exit;
}
}
}
data = &mschdata[sizeof(bcm_event_t)];
/* read current mask state */
if ((err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
fprintf(stderr, "couldn't read event_msgs\n");
goto exit;
}
event_inds_mask[WLC_E_MSCH / 8] |= (1 << (WLC_E_MSCH % 8));
if ((err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
fprintf(stderr, "couldn't write event_msgs\n");
goto exit;
}
val &= ~WL_MSCH_CMD_VER_MASK;
val |= (WL_MSCH_CMD_ENABLE_BIT | (WL_MSCH_PROFILER_VER << WL_MSCH_CMD_VER_SHIFT));
if ((err = wlu_iovar_setint(wl, "msch_event", val))) {
fprintf(stderr, "couldn't start msch event\n");
goto exit;
}
wl_init_frm_array(dir, files);
printf("wating for MSCH events :%s\n", ifr.ifr_name);
while (1) {
fflush(stdout);
octets = recv(fd, mschdata, WL_MSCH_PROFILER_BUFFER_SIZE, 0);
if (octets <= 0) {
/* sigterm */
err = -1;
break;
}
event = (bcm_event_t *)mschdata;
event_type = ntoh32(event->event.event_type);
reason = ntoh32(event->event.reason);
if ((event_type != WLC_E_MSCH)) {
if (event_type == WLC_E_ESCAN_RESULT) {
wl_escan_result_t* escan_data = (wl_escan_result_t*)data;
uint16 i;
MSCH_EVENTS_PRINTF1("MACEVENT_%d: WLC_E_ESCAN_RESULT:", event_type);
for (i = 0; i < escan_data->bss_count; i++) {
wl_bss_info_t *bi = &escan_data->bss_info[i];
char ssidbuf[SSID_FMT_BUF_LEN];
char chspec_str[CHANSPEC_STR_LEN];
wl_format_ssid(ssidbuf, bi->SSID, bi->SSID_len);
MSCH_EVENTS_PRINTF2(" SSID: \"%s\", Channel: %s;",
ssidbuf, wf_chspec_ntoa(bi->chanspec, chspec_str));
}
MSCH_EVENTS_PRINTF("\n");
} else {
char *event_name;
switch (event_type) {
case WLC_E_JOIN:
event_name = "WLC_E_JOIN";
break;
case WLC_E_AUTH:
event_name = "WLC_E_AUTH";
break;
case WLC_E_ASSOC:
event_name = "WLC_E_ASSOC";
break;
case WLC_E_LINK:
event_name = "WLC_E_LINK";
break;
case WLC_E_ROAM:
event_name = "WLC_E_ROAM";
break;
case WLC_E_SCAN_COMPLETE:
event_name = "WLC_E_SCAN_COMPLETE";
break;
case WLC_E_SCAN_CONFIRM_IND:
event_name = "WLC_E_SCAN_CONFIRM_IND";
break;
case WLC_E_ASSOC_REQ_IE:
event_name = "WLC_E_ASSOC_REQ_IE";
break;
case WLC_E_ASSOC_RESP_IE:
event_name = "WLC_E_ASSOC_RESP_IE";
break;
case WLC_E_BSSID:
event_name = "WLC_E_BSSID";
break;
default:
event_name = "Unknown Event";
}
MSCH_EVENTS_PRINTF2("MACEVENT_%d: %s\n", event_type, event_name);
}
continue;
}
wl_msch_dump_data(data, reason);
if ((reason & WL_MSCH_PROFILER_TYPE_MASK) == WL_MSCH_PROFILER_EXIT)
goto exit;
}
exit:
/* if we ever reach here */
close(fd);
if (mschfp) {
fflush(mschfp);
fclose(mschfp);
mschfp = NULL;
}
/* Read the event mask from driver and mask the event WLC_E_MSCH */
if (!(err = wlu_iovar_get(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN))) {
event_inds_mask[WLC_E_MSCH / 8] &= (~(1 << (WLC_E_MSCH % 8)));
err = wlu_iovar_set(wl, "event_msgs", &event_inds_mask, WL_EVENTING_MASK_LEN);
}
fflush(stdout);
return (err);
}
#endif /* linux */
typedef struct wl_msch_profiler_struct {
uint32 start_ptr;
uint32 write_ptr;
uint32 write_size;
uint32 read_ptr;
uint32 read_size;
uint32 total_size;
uint32 buffer;
} wl_msch_profiler_struct_t;
#define MSCH_MAGIC_1 0x4d534348
#define MSCH_MAGIC_2 0x61676963
#undef ROUNDUP
#define ROUNDUP(x) (((x) + 3) & (~0x03))
#define MAX_PROFILE_DATA_SIZE 4096
int wl_msch_profiler(void *wl, cmd_t *cmd, char **argv)
{
char *fname_r = NULL, *fname_w = NULL, *dir = NULL, *files = NULL;
char *buffer = NULL, *p, opt;
FILE *fp = NULL;
int err = BCME_OK;
uint32 magicdata;
uint32 rptr, rsize, wsize, tsize;
wl_msch_profiler_struct_t profiler;
bool found = FALSE;
UNUSED_PARAMETER(wl);
UNUSED_PARAMETER(cmd);
while ((p = *++argv) != NULL) {
if (!strcmp(p, "--help") || !strcmp(p, "-h")) {
printf("%s", cmd->help);
return BCME_OK;
}
if (!strncmp(p, "-", 1)) {
opt = p[1];
if (strlen(p) > 2) {
fprintf(stderr, "wl_msch_profiler: only single char options, "
"error on param \"%s\"\n", p);
return BCME_BADARG;
}
argv++;
if (*argv == NULL) {
fprintf(stderr, "wl_msch_profiler: missing value parameter "
"after \"%s\"\n", p);
return BCME_USAGE_ERROR;
}
if (opt == 'D')
dir = *argv;
else if (opt == 'F')
files = *argv;
else {
fprintf(stderr, "error param: %s\n", p);
return BCME_BADARG;
}
} else if (!fname_r) {
fname_r = p;
} else if (!fname_w) {
fname_w = p;
} else {
fprintf(stderr, "error param: %s\n", p);
return BCME_BADARG;
}
}
if (fname_r == NULL) {
fprintf(stderr, "<input filename> param is missing\n");
return -1;
}
if (!(fp = fopen(fname_r, "rb"))) {
perror(fname_r);
fprintf(stderr, "Cannot open input file %s\n", fname_r);
err = BCME_BADARG;
goto exit;
}
rptr = 0;
while ((rsize = fread(&magicdata, 1, sizeof(uint32), fp)) > 0) {
rptr += rsize;
magicdata = dtoh32(magicdata);
if (magicdata != MSCH_MAGIC_1)
continue;
if ((rsize = fread(&magicdata, 1, sizeof(uint32), fp)) > 0) {
rptr += rsize;
magicdata = dtoh32(magicdata);
if (magicdata != MSCH_MAGIC_2)
continue;
}
rsize = fread(&profiler, 1, sizeof(wl_msch_profiler_struct_t), fp);
rptr += rsize;
magicdata = dtoh32(profiler.buffer);
if (((rptr ^ magicdata) & 0xffff) == 0) {
found = TRUE;
break;
}
}
if (!found) {
fprintf(stderr, "Cannot find profiler data from file %s\n", fname_r);
err = BCME_NOTFOUND;
goto exit;
}
if (fname_w) {
if (!(mschfp = fopen(fname_w, "wb"))) {
perror(fname_w);
fprintf(stderr, "Cannot open file %s\n", fname_w);
err = BCME_BADARG;
goto exit;
}
}
tsize = dtoh32(profiler.total_size);
buffer = (char*)malloc(tsize + MAX_PROFILE_DATA_SIZE);
if (buffer == NULL) {
fprintf(stderr, "Cannot not allocate %d bytes for profiler buffer\n",
tsize);
err = BCME_NOMEM;
goto exit;
}
if ((rsize = fread(buffer, 1, tsize, fp)) != tsize) {
fprintf(stderr, "Cannot read profiler data from file %s, req %d, read %d\n",
fname_r, tsize, rsize);
err = BCME_BADARG;
goto exit;
}
wsize = dtoh32(profiler.write_size);
rptr = dtoh32(profiler.start_ptr);
rsize = 0;
wl_init_frm_array(dir, files);
while (rsize < wsize) {
msch_collect_tlv_t *ptlv = (msch_collect_tlv_t *)(buffer + rptr);
int type, size, remain;
char *data;
size = ROUNDUP(WL_MSCH_PROFILE_HEAD_SIZE + dtoh16(ptlv->size));
rsize += size;
if (rsize > wsize)
break;
remain = tsize - rptr;
if (remain >= size) {
rptr += size;
if (rptr == tsize)
rptr = 0;
} else {
remain = size - remain;
memcpy(buffer + tsize, buffer, remain);
rptr = remain;
}
type = dtoh16(ptlv->type);
data = ptlv->value;
wl_msch_dump_data(data, type);
}
err = BCME_OK;
exit:
if (fp)
fclose(fp);
if (buffer)
free(buffer);
if (mschfp) {
fflush(mschfp);
fclose(mschfp);
mschfp = NULL;
}
fflush(stdout);
return err;
}