msm: msm_bus: Add new APIs for bus scaling

Add new APIs to the bus scaling driver. The new APIs make it
easier for clients to setup paths for bus scaling. The driver APIs
will return a pointer to a client handle in case of success and NULL or
error in cases of failure. For now the existing APIs will remain as is
eventually all clients will start switching over to the new APIs.

Change-Id: I22656dddf13802128ee5c4faab9f83f9c6f8e683
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
This commit is contained in:
Girish Mahadevan 2014-11-06 09:10:20 -07:00
parent fd7e6316ab
commit 3e569eb3be
6 changed files with 367 additions and 11 deletions

View file

@ -19,9 +19,11 @@
#include <linux/msm-bus.h>
#include "msm_bus_core.h"
#include "msm_bus_adhoc.h"
#include <trace/events/trace_msm_bus.h>
#define NUM_CL_HANDLES 50
#define NUM_LNODES 3
#define MAX_STR_CL 50
struct bus_search_type {
struct list_head link;
@ -951,6 +953,7 @@ static int update_request_adhoc(uint32_t cl, unsigned int index)
MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
cl, index, client->curr, client->pdata->usecase->num_paths);
msm_bus_dbg_client_data(client->pdata, index , cl);
for (i = 0; i < pdata->usecase->num_paths; i++) {
src = client->pdata->usecase[index].vectors[i].src;
dest = client->pdata->usecase[index].vectors[i].dst;
@ -980,12 +983,135 @@ static int update_request_adhoc(uint32_t cl, unsigned int index)
if (log_transaction)
getpath_debug(src, lnode, pdata->active_only);
}
msm_bus_dbg_client_data(client->pdata, index , cl);
trace_bus_update_request_end(pdata->name);
exit_update_request:
mutex_unlock(&msm_bus_adhoc_lock);
return ret;
}
static void free_cl_mem(struct msm_bus_client_handle *cl)
{
if (cl) {
kfree(cl->name);
kfree(cl);
cl = NULL;
}
}
static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
{
int ret = 0;
char *test_cl = "test-client";
bool log_transaction = false;
mutex_lock(&msm_bus_adhoc_lock);
if (!cl) {
MSM_BUS_ERR("%s: Invalid client handle %p", __func__, cl);
ret = -ENXIO;
goto exit_update_request;
}
if (!strcmp(test_cl, cl->name))
log_transaction = true;
msm_bus_dbg_rec_transaction(cl, ab, ib);
if ((cl->cur_ib == ib) && (cl->cur_ab == ab)) {
MSM_BUS_DBG("%s:no change in request", cl->name);
goto exit_update_request;
}
ret = update_path(cl->mas, cl->slv, ib, ab, cl->cur_ib, cl->cur_ab,
cl->first_hop, cl->active_only);
if (ret) {
MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
__func__, ret, cl->active_only);
goto exit_update_request;
}
cl->cur_ib = ib;
cl->cur_ab = ab;
if (log_transaction)
getpath_debug(cl->mas, cl->first_hop, cl->active_only);
trace_bus_update_request_end(cl->name);
exit_update_request:
mutex_unlock(&msm_bus_adhoc_lock);
return ret;
}
static void unregister_adhoc(struct msm_bus_client_handle *cl)
{
mutex_lock(&msm_bus_adhoc_lock);
if (!cl) {
MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
__func__);
goto exit_unregister_client;
}
MSM_BUS_DBG("%s: Unregistering client %p", __func__, cl);
remove_path(cl->mas, cl->slv, cl->cur_ib, cl->cur_ab,
cl->first_hop, cl->active_only);
msm_bus_dbg_remove_client(cl);
kfree(cl);
exit_unregister_client:
mutex_unlock(&msm_bus_adhoc_lock);
return;
}
static struct msm_bus_client_handle*
register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only)
{
struct msm_bus_client_handle *client = NULL;
int len = 0;
mutex_lock(&msm_bus_adhoc_lock);
if (!(mas && slv && name)) {
pr_err("%s: Error: src dst name num_paths are required",
__func__);
goto exit_register;
}
client = kzalloc(sizeof(struct msm_bus_client_handle), GFP_KERNEL);
if (!client) {
MSM_BUS_ERR("%s: Error allocating client data", __func__);
goto exit_register;
}
len = strnlen(name, MAX_STR_CL);
client->name = kzalloc(len, GFP_KERNEL);
if (!client->name) {
MSM_BUS_ERR("%s: Error allocating client name buf", __func__);
free_cl_mem(client);
goto exit_register;
}
strlcpy(client->name, name, MAX_STR_CL);
client->active_only = active_only;
client->mas = mas;
client->slv = slv;
client->first_hop = getpath(client->mas, client->slv);
if (client->first_hop < 0) {
MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
__func__, client->mas, client->slv);
free_cl_mem(client);
goto exit_register;
}
MSM_BUS_DBG("%s:Client handle %p %s", __func__, client,
client->name);
msm_bus_dbg_add_client(client);
exit_register:
mutex_unlock(&msm_bus_adhoc_lock);
return client;
}
/**
* msm_bus_arb_setops_adhoc() : Setup the bus arbitration ops
* @ arb_ops: pointer to the arb ops.
@ -995,4 +1121,8 @@ void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops)
arb_ops->register_client = register_client_adhoc;
arb_ops->update_request = update_request_adhoc;
arb_ops->unregister_client = unregister_client_adhoc;
arb_ops->register_cl = register_adhoc;
arb_ops->unregister = unregister_adhoc;
arb_ops->update_bw = update_bw_adhoc;
}

View file

@ -81,3 +81,62 @@ void msm_bus_scale_unregister_client(uint32_t cl)
}
}
EXPORT_SYMBOL(msm_bus_scale_unregister_client);
/**
* msm_bus_scale_register() - Register the clients with the msm bus
* driver
* @pdata: Platform data of the client, containing src, dest, ab, ib.
* Return non-zero value in case of success, 0 in case of failure.
*
* Client data contains the vectors specifying arbitrated bandwidth (ab)
* and instantaneous bandwidth (ib) requested between a particular
* src and dest.
*/
struct msm_bus_client_handle*
msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name, bool active_only)
{
if (arb_ops.register_cl)
return arb_ops.register_cl(mas, slv, name, active_only);
else {
pr_err("%s: Bus driver not ready.",
__func__);
return ERR_PTR(-EPROBE_DEFER);
}
}
EXPORT_SYMBOL(msm_bus_scale_register);
/**
* msm_bus_scale_client_update_bw() - Update the request for bandwidth
* from a particular client
*
* cl: Handle to the client
* index: Index into the vector, to which the bw and clock values need to be
* updated
*/
int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
{
if (arb_ops.update_request)
return arb_ops.update_bw(cl, ab, ib);
else {
pr_err("%s: Bus driver not ready.", __func__);
return -EPROBE_DEFER;
}
}
EXPORT_SYMBOL(msm_bus_scale_update_bw);
/**
* msm_bus_scale_unregister() - Update the request for bandwidth
* from a particular client
*
* cl: Handle to the client
*/
void msm_bus_scale_unregister(struct msm_bus_client_handle *cl)
{
if (arb_ops.unregister)
arb_ops.unregister(cl);
else
pr_err("%s: Bus driver not ready.",
__func__);
}
EXPORT_SYMBOL(msm_bus_scale_unregister);

View file

@ -58,6 +58,11 @@ struct msm_bus_arb_ops {
uint32_t (*register_client)(struct msm_bus_scale_pdata *pdata);
int (*update_request)(uint32_t cl, unsigned int index);
void (*unregister_client)(uint32_t cl);
struct msm_bus_client_handle*
(*register_cl)(uint32_t mas, uint32_t slv, char *name,
bool active_only);
int (*update_bw)(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
void (*unregister)(struct msm_bus_client_handle *cl);
};
enum {
@ -313,6 +318,11 @@ void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
uint32_t cl);
void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
int nmasters, int nslaves, int ntslaves, int op);
int msm_bus_dbg_add_client(const struct msm_bus_client_handle *pdata);
int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata,
u64 ab, u64 ib);
void msm_bus_dbg_remove_client(const struct msm_bus_client_handle *pdata);
#else
static inline void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata,
int index, uint32_t cl)
@ -323,6 +333,23 @@ static inline void msm_bus_dbg_commit_data(const char *fabname,
int op)
{
}
static inline void void msm_bus_dbg_remove_client
(const struct msm_bus_client_handle *pdata)
{
}
static inline int
msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata,
u64 ab, u64 ib)
{
return 0;
}
static inline int
msm_bus_dbg_add_client(const struct msm_bus_client_handle *pdata)
{
return 0;
}
#endif
#ifdef CONFIG_CORESIGHT

View file

@ -45,6 +45,7 @@ struct msm_bus_dbg_state {
struct msm_bus_cldata {
const struct msm_bus_scale_pdata *pdata;
const struct msm_bus_client_handle *handle;
int index;
uint32_t clid;
int size;
@ -285,14 +286,17 @@ static ssize_t client_data_read(struct file *file, char __user *buf,
int bsize = 0;
uint32_t cl = (uint32_t)(uintptr_t)file->private_data;
struct msm_bus_cldata *cldata = NULL;
const struct msm_bus_client_handle *handle = file->private_data;
int found = 0;
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->clid == cl) {
if ((cldata->clid == cl) ||
(cldata->handle && (cldata->handle == handle))) {
found = 1;
break;
}
}
if (!found)
return 0;
@ -323,6 +327,93 @@ struct dentry *msm_bus_dbg_create(const char *name, mode_t mode,
&client_data_fops);
}
int msm_bus_dbg_add_client(const struct msm_bus_client_handle *pdata)
{
struct msm_bus_cldata *cldata;
cldata = kzalloc(sizeof(struct msm_bus_cldata), GFP_KERNEL);
if (!cldata) {
MSM_BUS_DBG("Failed to allocate memory for client data\n");
return -ENOMEM;
}
cldata->handle = pdata;
list_add_tail(&cldata->list, &cl_list);
return 0;
}
int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata,
u64 ab, u64 ib)
{
struct msm_bus_cldata *cldata;
int i;
struct timespec ts;
bool found = false;
char *buf = NULL;
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->handle == pdata) {
found = true;
break;
}
}
if (!found)
return -ENOENT;
if (cldata->file == NULL) {
if (pdata->name == NULL) {
MSM_BUS_DBG("Client doesn't have a name\n");
return -EINVAL;
}
pr_err("\n%s setting up debugfs %s", __func__, pdata->name);
cldata->file = debugfs_create_file(pdata->name, S_IRUGO,
clients, (void *)pdata, &client_data_fops);
}
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, "master: ");
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d ", pdata->mas);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nslave : ");
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d ", pdata->slv);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nab : ");
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", ab);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nib : ");
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu ", ib);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
cldata->size = i;
trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec,
pdata->name, pdata->mas, pdata->slv, ab, ib);
return i;
}
void msm_bus_dbg_remove_client(const struct msm_bus_client_handle *pdata)
{
struct msm_bus_cldata *cldata = NULL;
list_for_each_entry(cldata, &cl_list, list) {
if (cldata->handle == pdata) {
debugfs_remove(cldata->file);
list_del(&cldata->list);
kfree(cldata);
break;
}
}
}
static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
int index, uint32_t clid, struct dentry *file)
{
@ -416,12 +507,13 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
for (j = 0; j < pdata->usecase->num_paths; j++)
trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec,
pdata->name, index,
pdata->name,
pdata->usecase[index].vectors[j].src,
pdata->usecase[index].vectors[j].dst,
pdata->usecase[index].vectors[j].ab,
pdata->usecase[index].vectors[j].ib);
cldata->index = index;
cldata->size = i;
return i;
}

View file

@ -66,6 +66,16 @@ struct msm_bus_scale_pdata {
unsigned int active_only;
};
struct msm_bus_client_handle {
char *name;
int mas;
int slv;
int first_hop;
u64 cur_ib;
u64 cur_ab;
bool active_only;
};
/* Scaling APIs */
/*
@ -79,12 +89,19 @@ int __init msm_bus_fabric_init_driver(void);
uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
void msm_bus_scale_unregister_client(uint32_t cl);
struct msm_bus_client_handle*
msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name,
bool active_only);
void msm_bus_scale_unregister(struct msm_bus_client_handle *cl);
int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
/* AXI Port configuration APIs */
int msm_bus_axi_porthalt(int master_port);
int msm_bus_axi_portunhalt(int master_port);
#else
static inline int __init msm_bus_fabric_init_driver(void) { return 0; }
static struct msm_bus_client_handle dummy_cl;
static inline uint32_t
msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
@ -112,6 +129,24 @@ static inline int msm_bus_axi_portunhalt(int master_port)
{
return 0;
}
static inline struct msm_bus_client_handle*
msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name,
bool active_only)
{
return &dummy_cl;
}
static inline void msm_bus_scale_unregister(struct msm_bus_client_handle *cl)
{
}
static inline int
msm_bus_scale_update_bw(uint32_t cl, u64 ab, u64 ib)
{
return 0;
}
#endif
#if defined(CONFIG_OF) && defined(CONFIG_MSM_BUS_SCALING)

View file

@ -20,17 +20,15 @@
TRACE_EVENT(bus_update_request,
TP_PROTO(int sec, int nsec, const char *name, unsigned int index,
int src, int dest, unsigned long long ab,
unsigned long long ib),
TP_PROTO(int sec, int nsec, const char *name, int src, int dest,
unsigned long long ab, unsigned long long ib),
TP_ARGS(sec, nsec, name, index, src, dest, ab, ib),
TP_ARGS(sec, nsec, name, src, dest, ab, ib),
TP_STRUCT__entry(
__field(int, sec)
__field(int, nsec)
__string(name, name)
__field(u32, index)
__field(int, src)
__field(int, dest)
__field(u64, ab)
@ -41,24 +39,39 @@ TRACE_EVENT(bus_update_request,
__entry->sec = sec;
__entry->nsec = nsec;
__assign_str(name, name);
__entry->index = index;
__entry->src = src;
__entry->dest = dest;
__entry->ab = ab;
__entry->ib = ib;
),
TP_printk("time= %d.%d name=%s index=%u src=%d dest=%d ab=%llu ib=%llu",
TP_printk("time= %d.%d name=%s src=%d dest=%d ab=%llu ib=%llu",
__entry->sec,
__entry->nsec,
__get_str(name),
(unsigned int)__entry->index,
__entry->src,
__entry->dest,
(unsigned long long)__entry->ab,
(unsigned long long)__entry->ib)
);
TRACE_EVENT(bus_update_request_end,
TP_PROTO(const char *name),
TP_ARGS(name),
TP_STRUCT__entry(
__string(name, name)
),
TP_fast_assign(
__assign_str(name, name);
),
TP_printk("client-name=%s", __get_str(name))
);
TRACE_EVENT(bus_bimc_config_limiter,
TP_PROTO(int mas_id, unsigned long long cur_lim_bw),