blob: 0a6dea9e8b26b74b7a99f6eb91282c43633de374 [file] [log] [blame]
/****************************************************************************
**+-----------------------------------------------------------------------+**
**| |**
**| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |**
**| All rights reserved. |**
**| |**
**| Redistribution and use in source and binary forms, with or without |**
**| modification, are permitted provided that the following conditions |**
**| are met: |**
**| |**
**| * Redistributions of source code must retain the above copyright |**
**| notice, this list of conditions and the following disclaimer. |**
**| * Redistributions in binary form must reproduce the above copyright |**
**| notice, this list of conditions and the following disclaimer in |**
**| the documentation and/or other materials provided with the |**
**| distribution. |**
**| * Neither the name Texas Instruments nor the names of its |**
**| contributors may be used to endorse or promote products derived |**
**| from this software without specific prior written permission. |**
**| |**
**| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |**
**| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |**
**| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
**| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |**
**| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
**| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |**
**| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
**| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
**| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |**
**| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
**| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |**
**| |**
**+-----------------------------------------------------------------------+**
****************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include "osApi.h"
#include "esta_drv.h"
#include "bmtrace.h"
#define OS_READ_REG(drv,reg,p_val) \
os_hwReadMemRegisterUINT32(drv, (UINT32 *)((unsigned long)drv->acx_reg.va + reg), p_val)
typedef struct {
unsigned long loc;/* trace entry identification */
unsigned long ts;/* Timestamp */
unsigned long p1; /* Parameter 1 */
unsigned long p2; /* Parameter 2 */
} bm_entry_t;
typedef struct {
int pos;
int count;
int print_pos;
int nusers;
unsigned long self_delay;
tiwlan_net_dev_t *drv;
bm_entry_t entry[1]; /* Array of entries */
} bm_control_t;
static bm_control_t *bm_control;
static inline int bm_control_size(void)
{
return offsetof(bm_control_t, entry) + sizeof(bm_entry_t)*BM_NUM_ENTRIES;
}
static int bm_res_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int i;
int len=0;
int limit=count-80;
int entry_count;
unsigned long prev=0;
int print_pos;
print_pos = bm_control->print_pos++; /* It will disable tracing as well */
entry_count = (bm_control->count > BM_NUM_ENTRIES) ? BM_NUM_ENTRIES : bm_control->count;
/* Skip off entries */
if ( print_pos >= entry_count) /* paranoid */
{
bm_control->pos = bm_control->count = bm_control->print_pos = 0;
*eof = 1;
return 0;
}
if (!off)
{
len = sprintf(page, "Events stored: %u discarded: %u\n",
entry_count, bm_control->count-entry_count);
len += sprintf(page+len, "loc delta ts p1 p2\n");
}
/* Initial index */
if (bm_control->count > BM_NUM_ENTRIES)
i = (bm_control->pos+print_pos-1)%BM_NUM_ENTRIES;
else
i = bm_control->print_pos-1;
for(; (print_pos<entry_count) && (len<=limit); print_pos++)
{
bm_entry_t *bme= &bm_control->entry[i];
len += sprintf(page+len,
"%-3lu %-10lu %-10lu %-10lu %-10lu\n",
bme->loc,
((bme->ts-prev)>bm_control->self_delay)?bme->ts-prev-bm_control->self_delay:0,
bme->ts,
bme->p1, bme->p2);
prev = bme->ts;
++i;
i %= BM_NUM_ENTRIES;
}
if (print_pos >= entry_count)
{
*eof = 1;
bm_control->pos = bm_control->count = bm_control->print_pos = 0;
}
else
bm_control->print_pos = print_pos;
return len;
}
/* Initialization */
int bm_init(struct tiwlan_net_dev *drv)
{
if (bm_control)
{
++bm_control->nusers;
return 0;
}
bm_control = (bm_control_t *)kmalloc(bm_control_size(), GFP_KERNEL);
if (!bm_control)
return -ENOMEM;
memset(bm_control, 0, offsetof(bm_control_t, entry) + sizeof(bm_entry_t)*BM_NUM_ENTRIES);
bm_control->nusers = 1;
bm_control->drv = drv;
create_proc_read_entry("bmtrace", 0, NULL, bm_res_read_proc, NULL);
/* Measure self-delay */
bm_trace(0, 0, 0);
bm_trace(0, 0, 0);
bm_control->self_delay = bm_control->entry[1].ts - bm_control->entry[0].ts;
bm_control->pos = bm_control->count = 0;
print_info("%s: self_delay=%lu\n", __FUNCTION__, bm_control->self_delay);
return 0;
}
/* De-initialization */
void bm_destroy(void)
{
if (--bm_control->nusers)
return;
remove_proc_entry("bmtrace", NULL);
kfree( bm_control );
}
/* Add trace entry. not safe, but will do */
void bm_trace(int loc, unsigned long p1, unsigned long p2)
{
int pos;
if (!bm_control || bm_control->print_pos)
return;
pos = bm_control->pos;
bm_control->pos = (pos+1) % BM_NUM_ENTRIES;
++bm_control->count;
bm_control->entry[pos].ts = os_timeStampUs(NULL);
bm_control->entry[pos].loc= loc;
bm_control->entry[pos].p1 = p1;
bm_control->entry[pos].p2 = p2;
}