716 lines
18 KiB
C
716 lines
18 KiB
C
|
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
* only version 2 as published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/seq_file.h>
|
||
|
#include <linux/debugfs.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/mutex.h>
|
||
|
#include <linux/string.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/hrtimer.h>
|
||
|
#include <mach/msm_bus_board.h>
|
||
|
#include <mach/msm_bus.h>
|
||
|
#include "msm_bus_core.h"
|
||
|
|
||
|
#define MAX_BUFF_SIZE 4096
|
||
|
#define FILL_LIMIT 128
|
||
|
|
||
|
static struct dentry *clients;
|
||
|
static struct dentry *dir;
|
||
|
static DEFINE_MUTEX(msm_bus_dbg_fablist_lock);
|
||
|
struct msm_bus_dbg_state {
|
||
|
uint32_t cl;
|
||
|
uint8_t enable;
|
||
|
uint8_t current_index;
|
||
|
} clstate;
|
||
|
|
||
|
struct msm_bus_cldata {
|
||
|
const struct msm_bus_scale_pdata *pdata;
|
||
|
int index;
|
||
|
uint32_t clid;
|
||
|
int size;
|
||
|
struct dentry *file;
|
||
|
struct list_head list;
|
||
|
char buffer[MAX_BUFF_SIZE];
|
||
|
};
|
||
|
|
||
|
struct msm_bus_fab_list {
|
||
|
const char *name;
|
||
|
int size;
|
||
|
struct dentry *file;
|
||
|
struct list_head list;
|
||
|
char buffer[MAX_BUFF_SIZE];
|
||
|
};
|
||
|
|
||
|
LIST_HEAD(fabdata_list);
|
||
|
LIST_HEAD(cl_list);
|
||
|
|
||
|
/**
|
||
|
* The following structures and funtions are used for
|
||
|
* the test-client which can be created at run-time.
|
||
|
*/
|
||
|
|
||
|
static struct msm_bus_vectors init_vectors[1];
|
||
|
static struct msm_bus_vectors current_vectors[1];
|
||
|
static struct msm_bus_vectors requested_vectors[1];
|
||
|
|
||
|
static struct msm_bus_paths shell_client_usecases[] = {
|
||
|
{
|
||
|
.num_paths = ARRAY_SIZE(init_vectors),
|
||
|
.vectors = init_vectors,
|
||
|
},
|
||
|
{
|
||
|
.num_paths = ARRAY_SIZE(current_vectors),
|
||
|
.vectors = current_vectors,
|
||
|
},
|
||
|
{
|
||
|
.num_paths = ARRAY_SIZE(requested_vectors),
|
||
|
.vectors = requested_vectors,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static struct msm_bus_scale_pdata shell_client = {
|
||
|
.usecase = shell_client_usecases,
|
||
|
.num_usecases = ARRAY_SIZE(shell_client_usecases),
|
||
|
.name = "test-client",
|
||
|
};
|
||
|
|
||
|
static void msm_bus_dbg_init_vectors(void)
|
||
|
{
|
||
|
init_vectors[0].src = -1;
|
||
|
init_vectors[0].dst = -1;
|
||
|
init_vectors[0].ab = 0;
|
||
|
init_vectors[0].ib = 0;
|
||
|
current_vectors[0].src = -1;
|
||
|
current_vectors[0].dst = -1;
|
||
|
current_vectors[0].ab = 0;
|
||
|
current_vectors[0].ib = 0;
|
||
|
requested_vectors[0].src = -1;
|
||
|
requested_vectors[0].dst = -1;
|
||
|
requested_vectors[0].ab = 0;
|
||
|
requested_vectors[0].ib = 0;
|
||
|
clstate.enable = 0;
|
||
|
clstate.current_index = 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_update_cl_request(uint32_t cl)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
if (clstate.current_index < 2)
|
||
|
clstate.current_index = 2;
|
||
|
else {
|
||
|
clstate.current_index = 1;
|
||
|
current_vectors[0].ab = requested_vectors[0].ab;
|
||
|
current_vectors[0].ib = requested_vectors[0].ib;
|
||
|
}
|
||
|
|
||
|
if (clstate.enable) {
|
||
|
MSM_BUS_DBG("Updating request for shell client, index: %d\n",
|
||
|
clstate.current_index);
|
||
|
ret = msm_bus_scale_client_update_request(clstate.cl,
|
||
|
clstate.current_index);
|
||
|
} else
|
||
|
MSM_BUS_DBG("Enable bit not set. Skipping update request\n");
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void msm_bus_dbg_unregister_client(uint32_t cl)
|
||
|
{
|
||
|
MSM_BUS_DBG("Unregistering shell client\n");
|
||
|
msm_bus_scale_unregister_client(clstate.cl);
|
||
|
clstate.cl = 0;
|
||
|
}
|
||
|
|
||
|
static uint32_t msm_bus_dbg_register_client(void)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
if (init_vectors[0].src != requested_vectors[0].src) {
|
||
|
MSM_BUS_DBG("Shell client master changed. Unregistering\n");
|
||
|
msm_bus_dbg_unregister_client(clstate.cl);
|
||
|
}
|
||
|
if (init_vectors[0].dst != requested_vectors[0].dst) {
|
||
|
MSM_BUS_DBG("Shell client slave changed. Unregistering\n");
|
||
|
msm_bus_dbg_unregister_client(clstate.cl);
|
||
|
}
|
||
|
|
||
|
if (!clstate.enable) {
|
||
|
MSM_BUS_DBG("Enable bit not set, skipping registration: cl "
|
||
|
"%d\n", clstate.cl);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (clstate.cl) {
|
||
|
MSM_BUS_DBG("Client registered, skipping registration\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
current_vectors[0].src = init_vectors[0].src;
|
||
|
requested_vectors[0].src = init_vectors[0].src;
|
||
|
current_vectors[0].dst = init_vectors[0].dst;
|
||
|
requested_vectors[0].dst = init_vectors[0].dst;
|
||
|
MSM_BUS_DBG("Registering shell client\n");
|
||
|
ret = msm_bus_scale_register_client(&shell_client);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_mas_get(void *data, u64 *val)
|
||
|
{
|
||
|
*val = init_vectors[0].src;
|
||
|
MSM_BUS_DBG("Get master: %llu\n", *val);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_mas_set(void *data, u64 val)
|
||
|
{
|
||
|
init_vectors[0].src = val;
|
||
|
MSM_BUS_DBG("Set master: %llu\n", val);
|
||
|
clstate.cl = msm_bus_dbg_register_client();
|
||
|
return 0;
|
||
|
}
|
||
|
DEFINE_SIMPLE_ATTRIBUTE(shell_client_mas_fops, msm_bus_dbg_mas_get,
|
||
|
msm_bus_dbg_mas_set, "%llu\n");
|
||
|
|
||
|
static int msm_bus_dbg_slv_get(void *data, u64 *val)
|
||
|
{
|
||
|
*val = init_vectors[0].dst;
|
||
|
MSM_BUS_DBG("Get slave: %llu\n", *val);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_slv_set(void *data, u64 val)
|
||
|
{
|
||
|
init_vectors[0].dst = val;
|
||
|
MSM_BUS_DBG("Set slave: %llu\n", val);
|
||
|
clstate.cl = msm_bus_dbg_register_client();
|
||
|
return 0;
|
||
|
}
|
||
|
DEFINE_SIMPLE_ATTRIBUTE(shell_client_slv_fops, msm_bus_dbg_slv_get,
|
||
|
msm_bus_dbg_slv_set, "%llu\n");
|
||
|
|
||
|
static int msm_bus_dbg_ab_get(void *data, u64 *val)
|
||
|
{
|
||
|
*val = requested_vectors[0].ab;
|
||
|
MSM_BUS_DBG("Get ab: %llu\n", *val);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_ab_set(void *data, u64 val)
|
||
|
{
|
||
|
requested_vectors[0].ab = val;
|
||
|
MSM_BUS_DBG("Set ab: %llu\n", val);
|
||
|
return 0;
|
||
|
}
|
||
|
DEFINE_SIMPLE_ATTRIBUTE(shell_client_ab_fops, msm_bus_dbg_ab_get,
|
||
|
msm_bus_dbg_ab_set, "%llu\n");
|
||
|
|
||
|
static int msm_bus_dbg_ib_get(void *data, u64 *val)
|
||
|
{
|
||
|
*val = requested_vectors[0].ib;
|
||
|
MSM_BUS_DBG("Get ib: %llu\n", *val);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_ib_set(void *data, u64 val)
|
||
|
{
|
||
|
requested_vectors[0].ib = val;
|
||
|
MSM_BUS_DBG("Set ib: %llu\n", val);
|
||
|
return 0;
|
||
|
}
|
||
|
DEFINE_SIMPLE_ATTRIBUTE(shell_client_ib_fops, msm_bus_dbg_ib_get,
|
||
|
msm_bus_dbg_ib_set, "%llu\n");
|
||
|
|
||
|
static int msm_bus_dbg_en_get(void *data, u64 *val)
|
||
|
{
|
||
|
*val = clstate.enable;
|
||
|
MSM_BUS_DBG("Get enable: %llu\n", *val);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_en_set(void *data, u64 val)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
clstate.enable = val;
|
||
|
if (clstate.enable) {
|
||
|
if (!clstate.cl) {
|
||
|
MSM_BUS_DBG("client: %u\n", clstate.cl);
|
||
|
clstate.cl = msm_bus_dbg_register_client();
|
||
|
if (clstate.cl)
|
||
|
ret = msm_bus_dbg_update_cl_request(clstate.cl);
|
||
|
} else {
|
||
|
MSM_BUS_DBG("update request for cl: %u\n", clstate.cl);
|
||
|
ret = msm_bus_dbg_update_cl_request(clstate.cl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MSM_BUS_DBG("Set enable: %llu\n", val);
|
||
|
return ret;
|
||
|
}
|
||
|
DEFINE_SIMPLE_ATTRIBUTE(shell_client_en_fops, msm_bus_dbg_en_get,
|
||
|
msm_bus_dbg_en_set, "%llu\n");
|
||
|
|
||
|
/**
|
||
|
* The following funtions are used for viewing the client data
|
||
|
* and changing the client request at run-time
|
||
|
*/
|
||
|
|
||
|
static ssize_t client_data_read(struct file *file, char __user *buf,
|
||
|
size_t count, loff_t *ppos)
|
||
|
{
|
||
|
int bsize = 0;
|
||
|
uint32_t cl = (uint32_t)file->private_data;
|
||
|
struct msm_bus_cldata *cldata = NULL;
|
||
|
|
||
|
list_for_each_entry(cldata, &cl_list, list) {
|
||
|
if (cldata->clid == cl)
|
||
|
break;
|
||
|
}
|
||
|
bsize = cldata->size;
|
||
|
return simple_read_from_buffer(buf, count, ppos,
|
||
|
cldata->buffer, bsize);
|
||
|
}
|
||
|
|
||
|
static int client_data_open(struct inode *inode, struct file *file)
|
||
|
{
|
||
|
file->private_data = inode->i_private;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct file_operations client_data_fops = {
|
||
|
.open = client_data_open,
|
||
|
.read = client_data_read,
|
||
|
};
|
||
|
|
||
|
struct dentry *msm_bus_dbg_create(const char *name, mode_t mode,
|
||
|
struct dentry *dent, uint32_t clid)
|
||
|
{
|
||
|
if (dent == NULL) {
|
||
|
MSM_BUS_DBG("debugfs not ready yet\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
return debugfs_create_file(name, mode, dent, (void *)clid,
|
||
|
&client_data_fops);
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
|
||
|
int index, uint32_t clid, struct dentry *file)
|
||
|
{
|
||
|
struct msm_bus_cldata *cldata;
|
||
|
|
||
|
cldata = kmalloc(sizeof(struct msm_bus_cldata), GFP_KERNEL);
|
||
|
if (!cldata) {
|
||
|
MSM_BUS_DBG("Failed to allocate memory for client data\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
cldata->pdata = pdata;
|
||
|
cldata->index = index;
|
||
|
cldata->clid = clid;
|
||
|
cldata->file = file;
|
||
|
cldata->size = 0;
|
||
|
list_add_tail(&cldata->list, &cl_list);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void msm_bus_dbg_free_client(uint32_t clid)
|
||
|
{
|
||
|
struct msm_bus_cldata *cldata = NULL;
|
||
|
|
||
|
list_for_each_entry(cldata, &cl_list, list) {
|
||
|
if (cldata->clid == clid) {
|
||
|
debugfs_remove(cldata->file);
|
||
|
list_del(&cldata->list);
|
||
|
kfree(cldata);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
|
||
|
int index, uint32_t clid)
|
||
|
{
|
||
|
int i = 0, j;
|
||
|
char *buf = NULL;
|
||
|
struct msm_bus_cldata *cldata = NULL;
|
||
|
struct timespec ts;
|
||
|
|
||
|
list_for_each_entry(cldata, &cl_list, list) {
|
||
|
if (cldata->clid == clid)
|
||
|
break;
|
||
|
}
|
||
|
if (cldata->file == NULL) {
|
||
|
if (pdata->name == NULL) {
|
||
|
MSM_BUS_DBG("Client doesn't have a name\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
cldata->file = msm_bus_dbg_create(pdata->name, S_IRUGO,
|
||
|
clients, clid);
|
||
|
}
|
||
|
|
||
|
if (cldata->size < (MAX_BUFF_SIZE - FILL_LIMIT))
|
||
|
i = cldata->size;
|
||
|
else {
|
||
|
i = 0;
|
||
|
cldata->size = 0;
|
||
|
}
|
||
|
buf = cldata->buffer;
|
||
|
ts = ktime_to_timespec(ktime_get());
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
|
||
|
(int)ts.tv_sec, (int)ts.tv_nsec);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "curr : %d\n", index);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "masters: ");
|
||
|
|
||
|
for (j = 0; j < pdata->usecase->num_paths; j++)
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d ",
|
||
|
pdata->usecase[index].vectors[j].src);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nslaves : ");
|
||
|
for (j = 0; j < pdata->usecase->num_paths; j++)
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d ",
|
||
|
pdata->usecase[index].vectors[j].dst);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nab : ");
|
||
|
for (j = 0; j < pdata->usecase->num_paths; j++)
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ",
|
||
|
pdata->usecase[index].vectors[j].ab);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nib : ");
|
||
|
for (j = 0; j < pdata->usecase->num_paths; j++)
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ",
|
||
|
pdata->usecase[index].vectors[j].ib);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
|
||
|
|
||
|
cldata->size = i;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
if ((index < 0) || (index > cldata->pdata->num_usecases)) {
|
||
|
MSM_BUS_DBG("Invalid index!\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
ret = msm_bus_scale_client_update_request(cldata->clid, index);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static ssize_t msm_bus_dbg_update_request_write(struct file *file,
|
||
|
const char __user *ubuf, size_t cnt, loff_t *ppos)
|
||
|
{
|
||
|
struct msm_bus_cldata *cldata;
|
||
|
unsigned long index = 0;
|
||
|
int ret = 0;
|
||
|
char *chid;
|
||
|
char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL);
|
||
|
|
||
|
if (!buf || IS_ERR(buf)) {
|
||
|
MSM_BUS_ERR("Memory allocation for buffer failed\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
if (cnt == 0)
|
||
|
return 0;
|
||
|
if (copy_from_user(buf, ubuf, cnt))
|
||
|
return -EFAULT;
|
||
|
buf[cnt] = '\0';
|
||
|
chid = buf;
|
||
|
MSM_BUS_DBG("buffer: %s\n size: %d\n", buf, sizeof(ubuf));
|
||
|
|
||
|
list_for_each_entry(cldata, &cl_list, list) {
|
||
|
if (strstr(chid, cldata->pdata->name)) {
|
||
|
cldata = cldata;
|
||
|
strsep(&chid, " ");
|
||
|
if (chid) {
|
||
|
ret = strict_strtoul(chid, 10, &index);
|
||
|
if (ret) {
|
||
|
MSM_BUS_DBG("Index conversion"
|
||
|
" failed\n");
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
} else
|
||
|
MSM_BUS_DBG("Error parsing input. Index not"
|
||
|
" found\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
msm_bus_dbg_update_request(cldata, index);
|
||
|
kfree(buf);
|
||
|
return cnt;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The following funtions are used for viewing the commit data
|
||
|
* for each fabric
|
||
|
*/
|
||
|
static ssize_t fabric_data_read(struct file *file, char __user *buf,
|
||
|
size_t count, loff_t *ppos)
|
||
|
{
|
||
|
struct msm_bus_fab_list *fablist = NULL;
|
||
|
int bsize = 0;
|
||
|
ssize_t ret;
|
||
|
const char *name = file->private_data;
|
||
|
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
list_for_each_entry(fablist, &fabdata_list, list) {
|
||
|
if (strcmp(fablist->name, name) == 0)
|
||
|
break;
|
||
|
}
|
||
|
bsize = fablist->size;
|
||
|
ret = simple_read_from_buffer(buf, count, ppos,
|
||
|
fablist->buffer, bsize);
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static const struct file_operations fabric_data_fops = {
|
||
|
.open = client_data_open,
|
||
|
.read = fabric_data_read,
|
||
|
};
|
||
|
|
||
|
static int msm_bus_dbg_record_fabric(const char *fabname, struct dentry *file)
|
||
|
{
|
||
|
struct msm_bus_fab_list *fablist;
|
||
|
int ret = 0;
|
||
|
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
fablist = kmalloc(sizeof(struct msm_bus_fab_list), GFP_KERNEL);
|
||
|
if (!fablist) {
|
||
|
MSM_BUS_DBG("Failed to allocate memory for commit data\n");
|
||
|
ret = -ENOMEM;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
fablist->name = fabname;
|
||
|
fablist->size = 0;
|
||
|
list_add_tail(&fablist->list, &fabdata_list);
|
||
|
err:
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void msm_bus_dbg_free_fabric(const char *fabname)
|
||
|
{
|
||
|
struct msm_bus_fab_list *fablist = NULL;
|
||
|
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
list_for_each_entry(fablist, &fabdata_list, list) {
|
||
|
if (strcmp(fablist->name, fabname) == 0) {
|
||
|
debugfs_remove(fablist->file);
|
||
|
list_del(&fablist->list);
|
||
|
kfree(fablist);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
}
|
||
|
|
||
|
static int msm_bus_dbg_fill_fab_buffer(const char *fabname,
|
||
|
void *cdata, int nmasters, int nslaves,
|
||
|
int ntslaves)
|
||
|
{
|
||
|
int i;
|
||
|
char *buf = NULL;
|
||
|
struct msm_bus_fab_list *fablist = NULL;
|
||
|
struct timespec ts;
|
||
|
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
list_for_each_entry(fablist, &fabdata_list, list) {
|
||
|
if (strcmp(fablist->name, fabname) == 0)
|
||
|
break;
|
||
|
}
|
||
|
if (fablist->file == NULL) {
|
||
|
MSM_BUS_DBG("Fabric dbg entry does not exist\n");
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
if (fablist->size < MAX_BUFF_SIZE - 256)
|
||
|
i = fablist->size;
|
||
|
else {
|
||
|
i = 0;
|
||
|
fablist->size = 0;
|
||
|
}
|
||
|
buf = fablist->buffer;
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
ts = ktime_to_timespec(ktime_get());
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
|
||
|
(int)ts.tv_sec, (int)ts.tv_nsec);
|
||
|
|
||
|
msm_bus_rpm_fill_cdata_buffer(&i, buf, MAX_BUFF_SIZE, cdata,
|
||
|
nmasters, nslaves, ntslaves);
|
||
|
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
fablist->size = i;
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct file_operations msm_bus_dbg_update_request_fops = {
|
||
|
.open = client_data_open,
|
||
|
.write = msm_bus_dbg_update_request_write,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* msm_bus_dbg_client_data() - Add debug data for clients
|
||
|
* @pdata: Platform data of the client
|
||
|
* @index: The current index or operation to be performed
|
||
|
* @clid: Client handle obtained during registration
|
||
|
*/
|
||
|
void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
|
||
|
uint32_t clid)
|
||
|
{
|
||
|
struct dentry *file = NULL;
|
||
|
|
||
|
if (index == MSM_BUS_DBG_REGISTER) {
|
||
|
msm_bus_dbg_record_client(pdata, index, clid, file);
|
||
|
if (!pdata->name) {
|
||
|
MSM_BUS_DBG("Cannot create debugfs entry. Null name\n");
|
||
|
return;
|
||
|
}
|
||
|
} else if (index == MSM_BUS_DBG_UNREGISTER) {
|
||
|
msm_bus_dbg_free_client(clid);
|
||
|
MSM_BUS_DBG("Client %d unregistered\n", clid);
|
||
|
} else
|
||
|
msm_bus_dbg_fill_cl_buffer(pdata, index, clid);
|
||
|
}
|
||
|
EXPORT_SYMBOL(msm_bus_dbg_client_data);
|
||
|
|
||
|
/**
|
||
|
* msm_bus_dbg_commit_data() - Add commit data from fabrics
|
||
|
* @fabname: Fabric name specified in platform data
|
||
|
* @cdata: Commit Data
|
||
|
* @nmasters: Number of masters attached to fabric
|
||
|
* @nslaves: Number of slaves attached to fabric
|
||
|
* @ntslaves: Number of tiered slaves attached to fabric
|
||
|
* @op: Operation to be performed
|
||
|
*/
|
||
|
void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
|
||
|
int nmasters, int nslaves, int ntslaves, int op)
|
||
|
{
|
||
|
struct dentry *file = NULL;
|
||
|
|
||
|
if (op == MSM_BUS_DBG_REGISTER)
|
||
|
msm_bus_dbg_record_fabric(fabname, file);
|
||
|
else if (op == MSM_BUS_DBG_UNREGISTER)
|
||
|
msm_bus_dbg_free_fabric(fabname);
|
||
|
else
|
||
|
msm_bus_dbg_fill_fab_buffer(fabname, cdata, nmasters,
|
||
|
nslaves, ntslaves);
|
||
|
}
|
||
|
EXPORT_SYMBOL(msm_bus_dbg_commit_data);
|
||
|
|
||
|
static int __init msm_bus_debugfs_init(void)
|
||
|
{
|
||
|
struct dentry *commit, *shell_client;
|
||
|
struct msm_bus_fab_list *fablist;
|
||
|
struct msm_bus_cldata *cldata = NULL;
|
||
|
uint64_t val = 0;
|
||
|
|
||
|
dir = debugfs_create_dir("msm-bus-dbg", NULL);
|
||
|
if ((!dir) || IS_ERR(dir)) {
|
||
|
MSM_BUS_ERR("Couldn't create msm-bus-dbg\n");
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
clients = debugfs_create_dir("client-data", dir);
|
||
|
if ((!dir) || IS_ERR(dir)) {
|
||
|
MSM_BUS_ERR("Couldn't create clients\n");
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
shell_client = debugfs_create_dir("shell-client", dir);
|
||
|
if ((!dir) || IS_ERR(dir)) {
|
||
|
MSM_BUS_ERR("Couldn't create clients\n");
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
commit = debugfs_create_dir("commit-data", dir);
|
||
|
if ((!dir) || IS_ERR(dir)) {
|
||
|
MSM_BUS_ERR("Couldn't create commit\n");
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if (debugfs_create_file("update_request", S_IRUGO | S_IWUSR,
|
||
|
shell_client, &val, &shell_client_en_fops) == NULL)
|
||
|
goto err;
|
||
|
if (debugfs_create_file("ib", S_IRUGO | S_IWUSR, shell_client, &val,
|
||
|
&shell_client_ib_fops) == NULL)
|
||
|
goto err;
|
||
|
if (debugfs_create_file("ab", S_IRUGO | S_IWUSR, shell_client, &val,
|
||
|
&shell_client_ab_fops) == NULL)
|
||
|
goto err;
|
||
|
if (debugfs_create_file("slv", S_IRUGO | S_IWUSR, shell_client,
|
||
|
&val, &shell_client_slv_fops) == NULL)
|
||
|
goto err;
|
||
|
if (debugfs_create_file("mas", S_IRUGO | S_IWUSR, shell_client,
|
||
|
&val, &shell_client_mas_fops) == NULL)
|
||
|
goto err;
|
||
|
if (debugfs_create_file("update-request", S_IRUGO | S_IWUSR,
|
||
|
clients, NULL, &msm_bus_dbg_update_request_fops) == NULL)
|
||
|
goto err;
|
||
|
|
||
|
list_for_each_entry(cldata, &cl_list, list) {
|
||
|
if (cldata->pdata->name == NULL) {
|
||
|
MSM_BUS_DBG("Client name not found\n");
|
||
|
continue;
|
||
|
}
|
||
|
cldata->file = msm_bus_dbg_create(cldata->
|
||
|
pdata->name, S_IRUGO, clients, cldata->clid);
|
||
|
}
|
||
|
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
list_for_each_entry(fablist, &fabdata_list, list) {
|
||
|
fablist->file = debugfs_create_file(fablist->name, S_IRUGO,
|
||
|
commit, (void *)fablist->name, &fabric_data_fops);
|
||
|
if (fablist->file == NULL) {
|
||
|
MSM_BUS_DBG("Cannot create files for commit data\n");
|
||
|
goto err;
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
|
||
|
msm_bus_dbg_init_vectors();
|
||
|
return 0;
|
||
|
err:
|
||
|
debugfs_remove_recursive(dir);
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
late_initcall(msm_bus_debugfs_init);
|
||
|
|
||
|
static void __exit msm_bus_dbg_teardown(void)
|
||
|
{
|
||
|
struct msm_bus_fab_list *fablist = NULL, *fablist_temp;
|
||
|
struct msm_bus_cldata *cldata = NULL, *cldata_temp;
|
||
|
|
||
|
debugfs_remove_recursive(dir);
|
||
|
list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) {
|
||
|
list_del(&cldata->list);
|
||
|
kfree(cldata);
|
||
|
}
|
||
|
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||
|
list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) {
|
||
|
list_del(&fablist->list);
|
||
|
kfree(fablist);
|
||
|
}
|
||
|
mutex_unlock(&msm_bus_dbg_fablist_lock);
|
||
|
}
|
||
|
module_exit(msm_bus_dbg_teardown);
|
||
|
MODULE_DESCRIPTION("Debugfs for msm bus scaling client");
|
||
|
MODULE_LICENSE("GPL v2");
|
||
|
MODULE_AUTHOR("Gagan Mac <gmac@codeaurora.org>");
|