summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/stm/Kconfig6
-rw-r--r--drivers/stm/stm_fw.c365
-rw-r--r--drivers/stm/stm_fw.h22
-rw-r--r--drivers/stm/stm_msg.h13
-rw-r--r--drivers/stm/stm_omap_ti1.0.c489
5 files changed, 569 insertions, 326 deletions
diff --git a/drivers/stm/Kconfig b/drivers/stm/Kconfig
index 7fe21444564..96417a2e0d1 100644
--- a/drivers/stm/Kconfig
+++ b/drivers/stm/Kconfig
@@ -5,12 +5,12 @@ config STM_FW
STM Framework Driver
config STM_OMAP_TI1_0
- tristate "STM OMAP TI1.0 Drvier"
+ tristate "STM OMAP TI1.0 Driver"
depends on STM_FW
default n
help
- STM OMAP TI1.0 Driver - provides Syet, Trace Macrocell
- support for V1.0 implementation found in, eg, OMAP4
+ STM OMAP TI1.0 Driver - provides System Trace Macrocell
+ support for STM V1.0 implementation found in OMAP4.
config STM_ARM
tristate "STM ARM Driver"
diff --git a/drivers/stm/stm_fw.c b/drivers/stm/stm_fw.c
index e94c7d652e2..9e415a01464 100644
--- a/drivers/stm/stm_fw.c
+++ b/drivers/stm/stm_fw.c
@@ -46,6 +46,8 @@
#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/version.h>
#include "stm_fw.h"
#include "stm_msg.h"
@@ -57,19 +59,20 @@
#define MAX_CONFIG_STRING_BYTES 64
struct stm_chn_descriptor {
- int chn; /* Only valid if write_dentry is not NULL */
+ void *chn_id; /* Only valid if write_dentry is not NULL */
bool chn_enable;
struct dentry *write_dentry; /* NULL if not a user mode channel */
struct dentry *config_dentry; /* Always set for any chan type */
bool write_protect; /* Protect writes to the stm channel */
struct mutex lock;
- enum msg_formats msg_format;
- enum msg_types msg_type;
+ enum msg_format_t msg_format;
+ enum msg_timing_t msg_timing;
bool timestamp_enable;
bool checksum_enable;
bool ost_enable;
- char ost_entity;
- char ost_protocol;
+ uint32_t ost_entity;
+ uint32_t ost_protocol;
+ long pid;
struct list_head chn_list_link;
char chn_filename[MAX_SIZE_FILENAME];
char cfg_filename[MAX_SIZE_FILENAME];
@@ -88,7 +91,7 @@ static struct stm_device dev;
/*****************************************************************************
* Support function prototypes
*****************************************************************************/
-static uint8_t cal_checksum(char *buf, int cnt);
+static int8_t cal_checksum(unsigned char *buf, int cnt);
static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor);
@@ -96,9 +99,6 @@ static int parse_to_user(char *buf, loff_t buf_pos,
char __user *user_buf, size_t count, loff_t *ppos,
char *delims);
-static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
- char *kbuf, char *delims);
-
static int parse_strings_from_string(int num_strings, char *data[],
char *kbuf, char *delims);
@@ -122,7 +122,7 @@ static int parse_strings_from_string(int num_strings, char *data[],
static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct stm_chn_descriptor *chn_discriptor = filp->private_data;
+ struct stm_chn_descriptor *chn_descriptor = filp->private_data;
char *buf = NULL;
char *kbuf = NULL;
bool uspace = false;
@@ -132,26 +132,34 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
int header = 0;
int checksum = 0;
- if (!chn_discriptor)
+ if (!chn_descriptor)
return -EFAULT;
- if (!chn_discriptor->chn_enable)
+ if (!chn_descriptor->chn_enable)
return -EPERM;
- if (chn_discriptor->write_protect)
- if (mutex_lock_interruptible(&chn_discriptor->lock))
+ if (chn_descriptor->write_protect)
+ if (mutex_lock_interruptible(&chn_descriptor->lock))
return -ERESTARTSYS;
- switch (chn_discriptor->msg_format) {
+ /* If channel's pid has changed export a notification message */
+ if (chn_descriptor->pid != current->pid && dev.stm_ops->write_mark) {
+ dev.stm_ops->write_mark(chn_descriptor->chn_id,
+ (char *)&current->pid,
+ sizeof current->pid, uspace,
+ chn_descriptor->timestamp_enable);
+ chn_descriptor->pid = current->pid;
+ }
+ switch (chn_descriptor->msg_format) {
case USER:
- timestamp = chn_discriptor->timestamp_enable;
+ timestamp = chn_descriptor->timestamp_enable;
/*determine how much space is needed */
- if (chn_discriptor->checksum_enable)
+ if (chn_descriptor->checksum_enable)
checksum = 1;
- if (chn_discriptor->ost_enable)
+ if (chn_descriptor->ost_enable)
header = ((count + checksum) < 256) ? 4 : 8;
if (count + header + checksum > STM_MAX_XFER_BYTES) {
@@ -161,7 +169,7 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
/* TODO:: If kmalloc sleeps (low memory case) then unprotected
* messages could get out of order. Consider putting
- * in a small buffer (256 bytes) in the chn_discriptor.
+ * in a small buffer (256 bytes) in the chn_descriptor.
* In the unprotected case the user mode client is
* resposnible for using different channels per thread.
*/
@@ -177,29 +185,22 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
goto stm_file_write_exit;
}
- if (chn_discriptor->ost_enable) {
+ if (chn_descriptor->ost_enable) {
if (header == 4)
*(uint32_t *)kbuf = (uint32_t)(OST_VERSION
- | (chn_discriptor->ost_entity << 16)
- | (chn_discriptor->ost_protocol << 8)
+ | (chn_descriptor->ost_entity)
+ | (chn_descriptor->ost_protocol)
| (count + checksum));
else {
*(uint32_t *)kbuf = (uint32_t)(OST_VERSION
- | (chn_discriptor->ost_entity << 16)
- | (chn_discriptor->ost_protocol << 8)
+ | (chn_descriptor->ost_entity)
+ | (chn_descriptor->ost_protocol)
| OST_SHORT_HEADER_LENGTH_LIMIT);
*(uint32_t *)(kbuf+1) =
(uint32_t)(count + checksum);
}
}
- /* TODO:: Implement checksum. Required for INVARIANT messages.
- * May need to move the checksum to the first byte if
- * continuous (> STM_MAX_XFER_BYTES) transfer implemented.
- */
- /* Note:: TI host tools do not support checksum ( or INVARIANT
- * messages).
- */
if (checksum)
*(uint8_t *)(kbuf + header + count) =
cal_checksum(kbuf, count + header);
@@ -226,7 +227,7 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
} /* End of switch */
- ret = dev.stm_ops->write(chn_discriptor->chn, buf,
+ ret = dev.stm_ops->write(chn_descriptor->chn_id, buf,
msg_cnt, uspace, timestamp);
/* Check for user mode case */
@@ -239,8 +240,8 @@ stm_file_write_exit:
kfree(kbuf);
- if (chn_discriptor->write_protect)
- mutex_unlock(&chn_discriptor->lock);
+ if (chn_descriptor->write_protect)
+ mutex_unlock(&chn_descriptor->lock);
return ret;
}
@@ -273,7 +274,10 @@ enum config_id {
CFGID_FMT_USER,
CFGID_FMT_VENDOR,
CFGID_FMT_RAW,
- CFGID_SET_HEADER,
+ CFGID_STRING,
+ CFGID_BINARY,
+ CFGID_OST_ENABLE,
+ CFGID_OST_DISABLE,
CFGID_TIMESTAMP_ENABLE,
CFGID_TIMESTAMP_DISABLE,
CFGID_CHECKSUM_ENABLE,
@@ -290,7 +294,10 @@ static char *config_cmds[] = {
[CFGID_FMT_USER] = "fmt_user",
[CFGID_FMT_VENDOR] = "fmt_vendor",
[CFGID_FMT_RAW] = "fmt_raw",
- [CFGID_SET_HEADER] = "set_header",
+ [CFGID_STRING] = "string",
+ [CFGID_BINARY] = "binary",
+ [CFGID_OST_ENABLE] = "ost_enable",
+ [CFGID_OST_DISABLE] = "ost_disable",
[CFGID_TIMESTAMP_ENABLE] = "timestamp_enable",
[CFGID_TIMESTAMP_DISABLE] = "timestamp_disable",
[CFGID_CHECKSUM_ENABLE] = "checksum_enable",
@@ -302,104 +309,114 @@ static char *config_cmds[] = {
static ssize_t config_file_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct stm_chn_descriptor *chn_discriptor = file->private_data;
- char *kbuf = NULL;
+ struct stm_chn_descriptor *chn_descriptor = file->private_data;
+ char *kbuf = NULL, kbuffer[MAX_CONFIG_STRING_BYTES];
enum config_id cfg_id;
int cfg_len;
- const int num_ulongs = 2;
- const int max_ulong = 255;
- long data[num_ulongs];
- char delims[] = " ";
- int err;
+ int err = 0;
+ bool vendor_pass = false;
if (count > MAX_CONFIG_STRING_BYTES) {
- count = -EINVAL;
+ err = -EINVAL;
goto cfg_wrt_exit1;
}
- kbuf = kmalloc(count, GFP_KERNEL);
- if (!kbuf) {
- count = -ENOMEM;
- goto cfg_wrt_exit1;
- }
+ /* Get userspace string and assure termination */
+ if (count >= sizeof(kbuffer))
+ return -EINVAL;
+
+ if (copy_from_user(kbuffer, user_buf, count))
+ return -EFAULT;
+
+ kbuffer[count] = 0;
- copy_from_user(kbuf, user_buf, count);
+ /*
+ * Allow "echo > request" or "echo -n '' > request"
+ * to clean the filter quietly.
+ */
+ kbuf = strstrip(kbuffer);
/* Check buf against list of supported commands (config_cmds) */
- for (cfg_id = CFGID_CHN_ENABLE; cfg_id < CFGID_LAST; cfg_id++) {
+ for (cfg_id = 0; cfg_id < CFGID_LAST; cfg_id++) {
cfg_len = strlen(config_cmds[cfg_id]);
if (!strncmp(kbuf, config_cmds[cfg_id], cfg_len))
break;
}
- if (mutex_lock_interruptible(&chn_discriptor->lock))
- return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&chn_descriptor->lock)) {
+ err = -ERESTARTSYS;
+ goto cfg_wrt_exit1;
+ }
switch (cfg_id) {
case CFGID_CHN_ENABLE:
- chn_discriptor->chn_enable = true;
+ chn_descriptor->chn_enable = true;
break;
case CFGID_CHN_DISABLE:
- chn_discriptor->chn_enable = false;
+ chn_descriptor->chn_enable = false;
break;
case CFGID_PROTECTED:
- chn_discriptor->write_protect = true;
+ chn_descriptor->write_protect = true;
break;
case CFGID_UNPROTECTED:
- chn_discriptor->write_protect = false;
+ chn_descriptor->write_protect = false;
break;
case CFGID_TIMESTAMP_ENABLE:
- chn_discriptor->timestamp_enable = true;
+ chn_descriptor->timestamp_enable = true;
break;
case CFGID_TIMESTAMP_DISABLE:
- chn_discriptor->timestamp_enable = false;
+ chn_descriptor->timestamp_enable = false;
break;
case CFGID_CHECKSUM_ENABLE:
- chn_discriptor->checksum_enable = true;
+ chn_descriptor->checksum_enable = true;
break;
case CFGID_CHECKSUM_DISABLE:
- chn_discriptor->checksum_enable = false;
+ chn_descriptor->checksum_enable = false;
break;
- case CFGID_SET_HEADER:
- chn_discriptor->ost_enable = false;
- err = parse_ulongs_from_string(num_ulongs, max_ulong, data,
- kbuf, delims);
- if (err < 0) {
- count = err;
- goto cfg_wrt_exit2;
- }
- chn_discriptor->ost_entity = (char)data[0];
- chn_discriptor->ost_protocol = (char)data[1];
- chn_discriptor->ost_enable = true;
+ case CFGID_STRING:
+ chn_descriptor->ost_entity = OST_ENTITY_ID;
+ chn_descriptor->ost_protocol = OST_PROTOCOL_CHARSTREAM;
+ vendor_pass = true;
+ break;
+ case CFGID_BINARY:
+ chn_descriptor->ost_entity = OST_ENTITY_ID;
+ chn_descriptor->ost_protocol = OST_PROTOCOL_BINSTREAM;
+ vendor_pass = true;
+ break;
+ case CFGID_OST_ENABLE:
+ chn_descriptor->ost_enable = true;
+ break;
+ case CFGID_OST_DISABLE:
+ chn_descriptor->ost_enable = false;
break;
case CFGID_FMT_USER:
- chn_discriptor->msg_format = USER;
- count = dev.stm_ops->config_write(chn_discriptor->chn,
- kbuf, count);
+ chn_descriptor->msg_format = USER;
+ vendor_pass = true;
break;
case CFGID_FMT_VENDOR:
- chn_discriptor->msg_format = VENDOR;
- count = dev.stm_ops->config_write(chn_discriptor->chn,
- kbuf, count);
+ chn_descriptor->msg_format = VENDOR;
+ vendor_pass = true;
break;
case CFGID_FMT_RAW:
- chn_discriptor->msg_format = RAW;
- count = dev.stm_ops->config_write(chn_discriptor->chn,
- kbuf, count);
+ chn_descriptor->msg_format = RAW;
+ vendor_pass = true;
break;
default:
- count = dev.stm_ops->config_write(chn_discriptor->chn,
- kbuf, count);
+ vendor_pass = true;
}
-cfg_wrt_exit2:
- mutex_unlock(&chn_discriptor->lock);
+ if (vendor_pass)
+ err = dev.stm_ops->config_write(chn_descriptor->chn_id, kbuf);
+
+ mutex_unlock(&chn_descriptor->lock);
+
cfg_wrt_exit1:
- if ((int)count < 0)
- printk(KERN_ALERT "stm_fw: invalid command format for %s, error %d\n",
- chn_discriptor->cfg_filename, count);
+ if (err) {
+ pr_err("stm_fw: invalid command ""%s"" for %s, error %d\n",
+ kbuf, chn_descriptor->cfg_filename, err);
+ count = err;
+ }
- kfree(kbuf);
return count;
}
@@ -408,7 +425,7 @@ cfg_wrt_exit1:
static ssize_t config_file_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct stm_chn_descriptor *chn_discriptor = file->private_data;
+ struct stm_chn_descriptor *chn_descriptor = file->private_data;
const int max_buf = 256;
char buf[max_buf];
int buf_cnt = 0;
@@ -418,13 +435,14 @@ static ssize_t config_file_read(struct file *file, char __user *user_buf,
if (!dev.stm_ops->config_read)
return 0;
- if (mutex_lock_interruptible(&chn_discriptor->lock))
+ if (mutex_lock_interruptible(&chn_descriptor->lock))
return -ERESTARTSYS;
/* config_read puts formatted comma seperated strings in buf */
- buf_cnt = dev.stm_ops->config_read(chn_discriptor->chn, buf, max_buf);
+ buf_cnt = dev.stm_ops->config_read(chn_descriptor->chn_id,
+ buf, max_buf);
- mutex_unlock(&chn_discriptor->lock);
+ mutex_unlock(&chn_descriptor->lock);
if (buf_cnt < 0)
return buf_cnt;
@@ -508,17 +526,7 @@ static ssize_t request_file_read(struct file *file, char __user *user_buf,
}
/* Request file write commands */
-
-enum request_id {
- USER_CHANNEL_REQUEST,
- PRINTK_CHANNEL_REQUEST,
- TRACEPOINT_CHANEL_REQUEST,
- LTTNG_CHANNEL_REQUEST,
- REMOVE_CHANNEL_REQUEST,
- LAST_REQUEST
-};
-
-static char *request_cmds[] = {
+static char *usecase_cmds[] = {
[USER_CHANNEL_REQUEST] = "user",
[PRINTK_CHANNEL_REQUEST] = "printk",
[TRACEPOINT_CHANEL_REQUEST] = "tracepoint_ftrace",
@@ -535,8 +543,8 @@ static ssize_t request_file_write(struct file *filp,
{
int err = 0;
char *err_msg = "stm_fw: error creating <debugfs> file ";
- char *buf = NULL;
- enum request_id req_id;
+ char *kbuf = NULL, kbuffer[MAX_CONFIG_STRING_BYTES];
+ enum stm_usecase uc_id;
char filename[MAX_SIZE_FILENAME];
struct stm_chn_descriptor *chn_descriptor = NULL;
char *username = NULL;
@@ -544,26 +552,35 @@ static ssize_t request_file_write(struct file *filp,
struct list_head *ptr;
bool name_hit = false;
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ /* Get userspace string and assure termination */
+ if (count >= sizeof(kbuffer))
+ return -EINVAL;
+
+ copy_from_user(kbuffer, user_buf, count);
- copy_from_user(buf, user_buf, count);
+ kbuffer[count] = 0;
+
+ /*
+ * Allow "echo > request" or "echo -n '' > request"
+ * to clean the filter quietly.
+ */
+
+ kbuf = strstrip(kbuffer);
/* Check buf against the list of supported commands */
- for (req_id = USER_CHANNEL_REQUEST; req_id < LAST_REQUEST; req_id++)
- if (!strncmp(buf, request_cmds[req_id],
- strlen(request_cmds[req_id])))
+ for (uc_id = 0; uc_id < LAST_REQUEST; uc_id++)
+ if (!strncmp(kbuf, usecase_cmds[uc_id],
+ strlen(usecase_cmds[uc_id])))
break;
- if (req_id < LAST_REQUEST) {
+ if (uc_id < LAST_REQUEST) {
/*
* Parse out the filename. For all cases currently supported.
* If case not support next switch takes default to call
* vendor drvier's write config function.
*/
char *delims = " ";
- err = parse_strings_from_string(1, &username, buf, delims);
+ err = parse_strings_from_string(1, &username, kbuf, delims);
if (err < 0)
goto err_exit;
}
@@ -571,7 +588,7 @@ static ssize_t request_file_write(struct file *filp,
if (mutex_lock_interruptible(&dev.lock))
return -ERESTARTSYS;
- switch (req_id) {
+ switch (uc_id) {
case USER_CHANNEL_REQUEST:
case PRINTK_CHANNEL_REQUEST:
case TRACEPOINT_CHANEL_REQUEST:
@@ -604,14 +621,6 @@ static ssize_t request_file_write(struct file *filp,
goto err_exit;
}
- /* Allocate a channel */
- chn_descriptor->chn = dev.stm_ops->allocate_channel(
- request_cmds[req_id]);
- if (chn_descriptor->chn < 0) {
- err = chn_descriptor->chn;
- goto alloc_err_exit;
- }
-
/* Initialize chn descriptor */
chn_descriptor->write_dentry = NULL;
chn_descriptor->config_dentry = NULL;
@@ -620,12 +629,24 @@ static ssize_t request_file_write(struct file *filp,
mutex_init(&chn_descriptor->lock);
chn_descriptor->msg_format = VENDOR;
- chn_descriptor->msg_type = GUARANTEED;
+ chn_descriptor->msg_timing = GUARANTEED;
+ chn_descriptor->ost_protocol = OST_PROTOCOL_CHARSTREAM;
+ chn_descriptor->ost_entity = OST_ENTITY_ID;
chn_descriptor->timestamp_enable = true;
chn_descriptor->checksum_enable = false;
+ /* set to invlaid id so first write will export pid message */
+ chn_descriptor->pid = 0;
+
+ /* Allocate a channel */
+ err = dev.stm_ops->allocate_channel(uc_id,
+ &chn_descriptor->chn_id);
+ if (err < 0) {
+ chn_descriptor->chn_id = NULL;
+ goto alloc_err_exit;
+ }
/* If user command create debugfs message write file */
- if (req_id == USER_CHANNEL_REQUEST) {
+ if (uc_id == USER_CHANNEL_REQUEST) {
len = strlen(username);
if (len > MAX_SIZE_FILENAME || !len) {
@@ -708,7 +729,7 @@ static ssize_t request_file_write(struct file *filp,
break;
default:
- err = dev.stm_ops->config_write(-1, buf, count);
+ err = dev.stm_ops->config_write((void *)-1, kbuf);
if (err < 0) {
err = -EINVAL;
goto err_exit;
@@ -716,21 +737,25 @@ static ssize_t request_file_write(struct file *filp,
} /* End of the switch */
- kfree(buf);
*f_pos += count;
mutex_unlock(&dev.lock);
return count;
alloc_err_exit:
rm_chn_descriptor(chn_descriptor);
+ kfree(chn_descriptor);
err_exit:
- kfree(buf);
-
mutex_unlock(&dev.lock);
-
return err;
+}
+
+static int request_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!dev.stm_ops->mmap)
+ return -EACCES;
+ return dev.stm_ops->mmap(vma);
}
@@ -745,7 +770,8 @@ static int request_file_open(struct inode *inode, struct file *file)
static const struct file_operations request_fop = {
.write = request_file_write,
- .read = request_file_read,
+ .read = request_file_read,
+ .mmap = request_file_mmap,
.open = request_file_open,
};
@@ -797,7 +823,7 @@ int stm_register(struct stm_operations *module_ops)
goto stm_register_err;
}
- pr_err("stm_fw: vendor driver %s registered\n", module_ops->name);
+ pr_info("stm_fw: vendor driver %s registered\n", module_ops->name);
dev.stm_ops = module_ops;
INIT_LIST_HEAD(&dev.chn_list_head);
@@ -808,42 +834,41 @@ stm_register_err:
}
EXPORT_SYMBOL(stm_register);
-int stm_unregister(char *name)
+int stm_unregister()
{
- int ret = 0;
struct stm_chn_descriptor *chn_descriptor;
struct list_head *ptr;
if (mutex_lock_interruptible(&dev.lock))
return -ERESTARTSYS;
- if (strcmp(dev.stm_ops->name, name)) {
- ret = -EINVAL;
- goto stm_unregister_err;
- }
-
list_for_each(ptr, &dev.chn_list_head) {
chn_descriptor = list_entry(ptr, struct stm_chn_descriptor,
chn_list_link);
+ if (mutex_lock_interruptible(&chn_descriptor->lock)) {
+ mutex_unlock(&dev.lock);
+ return -ERESTARTSYS;
+ }
+
if (chn_descriptor->write_dentry)
debugfs_remove(chn_descriptor->write_dentry);
if (chn_descriptor->config_dentry)
debugfs_remove(chn_descriptor->config_dentry);
- if (chn_descriptor->chn >= 0)
- dev.stm_ops->free_channel(chn_descriptor->chn);
+ mutex_unlock(&chn_descriptor->lock);
kfree(chn_descriptor);
+
}
debugfs_remove_recursive(dev.parent);
- dev.stm_ops = NULL;
pr_info("stm_fw: vendor driver %s removed\n", dev.stm_ops->name);
-stm_unregister_err:
+ dev.stm_ops = NULL;
+
mutex_unlock(&dev.lock);
return 0;
@@ -863,10 +888,6 @@ static int stm_fw_init(void)
static void stm_fw_exit(void)
{
-
- if (dev.stm_ops)
- stm_unregister(dev.stm_ops->name); /* rm the request file*/
-
pr_info("stm_fw: driver exit\n");
}
@@ -877,12 +898,14 @@ MODULE_LICENSE("Dual BSD/GPL");
/*****************************************************************************/
/* Support functions */
/*****************************************************************************/
-
-/* TODO:: Implement cal_checksum(). */
-
-static uint8_t cal_checksum(char *buf, int cnt)
+static int8_t cal_checksum(unsigned char *buf, int cnt)
{
- return 0;
+ int i;
+ uint8_t checksum = 0;
+ for (i = 0; i < cnt; i++)
+ checksum += buf[i];
+
+ return -checksum;
}
static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
@@ -896,10 +919,9 @@ static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
if (chn_descriptor->config_dentry)
debugfs_remove(chn_descriptor->config_dentry);
- if (chn_descriptor->chn >= 0)
- dev.stm_ops->free_channel(chn_descriptor->chn);
+ if (chn_descriptor->chn_id)
+ dev.stm_ops->free_channel(chn_descriptor->chn_id);
- kfree(chn_descriptor);
}
@@ -925,7 +947,7 @@ static int parse_to_user(char *buf, loff_t buf_pos,
item = strsep(next, delims);
do {
item_len = strlen(item);
- if ((item_len <= count) && (buf_pos == *ppos)) {
+ if (item_len <= count && buf_pos == *ppos) {
loff_t copy_pos = 0;
/* copy item to user buf */
copy_len = simple_read_from_buffer(user_buf, count,
@@ -955,35 +977,6 @@ static int parse_to_user(char *buf, loff_t buf_pos,
/* Note, this function assumes first string is a command (which has already
* been evaluated) is to be thrown away.
*/
-static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
- char *kbuf, char *delims)
-{
- /* Parse the set header command */
- int i;
- int ret;
- char **item = &kbuf;
- /* Get command - throw it away */
- char *param = strsep(item, delims);
-
- /* Get next two parameter values */
- for (i = 0; i < num_longs; i++) {
- param = strsep(item, delims);
- if (!param)
- return -EINVAL;
-
- ret = kstrtol(param, 10, &data[i]);
- if (ret)
- return ret;
-
- if (data[i] < 0 || data[i] > max_ulong)
- return -EINVAL;
- }
- return 0;
-}
-
-/* Note, this function assumes first string is a command (which has already
- * been evaluated) is to be thrown away.
- */
static int parse_strings_from_string(int num_strings, char *data[],
char *kbuf, char *delims)
{
diff --git a/drivers/stm/stm_fw.h b/drivers/stm/stm_fw.h
index e6bf0411f46..bcaa307d0ad 100644
--- a/drivers/stm/stm_fw.h
+++ b/drivers/stm/stm_fw.h
@@ -39,6 +39,15 @@
#ifndef _STM_FW_H
#define _STM_FW_H
+enum stm_usecase {
+ USER_CHANNEL_REQUEST,
+ PRINTK_CHANNEL_REQUEST,
+ TRACEPOINT_CHANEL_REQUEST,
+ LTTNG_CHANNEL_REQUEST,
+ REMOVE_CHANNEL_REQUEST,
+ LAST_REQUEST
+};
+
struct stm_global_info {
int total_chn_cnt;
int reserved_chn_cnt;
@@ -51,17 +60,18 @@ struct stm_global_info {
struct stm_operations {
char *name;
int (*get_global_info)(struct stm_global_info *info);
- int (*write) (int chn, char *pbuf, int cnt, bool uspace,
+ int (*write) (void *chn_id, char *pbuf, int cnt, bool uspace,
bool timestamp);
- int (*write_mark)(int chn, char *pbuf, int cnt, bool uspace,
+ int (*write_mark)(void *chn_id, char *pbuf, int cnt, bool uspace,
bool timestamp);
- int (*allocate_channel) (char *usecase);
- int (*free_channel) (int chn);
- int (*config_write)(int chn, char *config_string, int count);
- int (*config_read)(int chn, char *config_string, int count);
+ int (*allocate_channel) (enum stm_usecase uc_id, void **chn_id);
+ int (*free_channel) (void *chn_id);
+ int (*config_write)(void *chn_id, char *config_string);
+ int (*config_read)(void *chn_id, char *config_string, int count);
int (*mmap)(struct vm_area_struct *vma);
};
int stm_register(struct stm_operations *stm_ops);
+int stm_unregister(void);
#endif
diff --git a/drivers/stm/stm_msg.h b/drivers/stm/stm_msg.h
index f40e0a971f2..9a6326a4177 100644
--- a/drivers/stm/stm_msg.h
+++ b/drivers/stm/stm_msg.h
@@ -44,17 +44,20 @@
#ifndef __STM_MSG_H_
#define __STM_MSG_H_
-enum msg_formats {USER, VENDOR, RAW};
-enum msg_types {GUARANTEED, INVARIANT};
+enum msg_format_t {USER, VENDOR, RAW};
+enum msg_data_t {STRING, BIN8, BIN16, BIN32};
+enum msg_timing_t {GUARANTEED, INVARIANT};
#define OST_VERSION (1 << 24) /* note:must be between 1 and 15 */
#define OST_ENTITY_ID (1 << 16)
-#define OST_PROTOCOL_BYTESTREAM (0x81 << 8) /* STMXport_putMsg */
+#define OST_PROTOCOL_CHARSTREAM (0x81 << 8) /* String data */
+#define OST_PROTOCOL_BINSTREAM (0x82 << 8) /* Binary data */
#define OST_SHORT_HEADER_LENGTH_LIMIT (255)
-#define STM_1_MAX_CHANNEL (240)
-/* chnls 240-255 reserved for TI debug tools */
+#define STM_1_MAX_CHANNEL (240) /* chnls 240-255 reserved for
+ * TI debug tools.
+ */
#define STM_MAX_XFER_BYTES 4096 /*
* Maximum nuimber of bytes to transfer per
diff --git a/drivers/stm/stm_omap_ti1.0.c b/drivers/stm/stm_omap_ti1.0.c
index 063525192e7..ac65e8c89d7 100644
--- a/drivers/stm/stm_omap_ti1.0.c
+++ b/drivers/stm/stm_omap_ti1.0.c
@@ -45,6 +45,8 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/version.h>
#include <plat/omap44xx.h>
@@ -63,7 +65,11 @@ static void build_ost_header(uint32_t protocol_id, uint32_t size,
static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
uint32_t msg_size, int32_t chn, bool timestamp);
-static struct chn_alloc *find_chn_object(int chn);
+static int32_t stm_put_bin(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
+ enum msg_data_t element_type, uint32_t num_bytes,
+ int32_t stm_chn, bool timestamp);
+
+static struct chn_alloc *construct_chn_obj(int chn, int chn_num);
static bool stm_app_ownership(void);
@@ -83,11 +89,11 @@ static bool stm_test_clock(void);
* any one time */
#define HW_MASTER_MASK 0x80 /* All HW masters have bit 7 set */
-#define STM_CONTROL_BASE
-
#define ATTRIBUTE_BUF_SIZE 256
static char attribute_buf[ATTRIBUTE_BUF_SIZE];
+#define CONTEXT_PID_MSG_MAX 32
+
static const uint32_t stm_base_address = L4_EMU_44XX_BASE;
static const uint32_t stm_resolution = 0x1000;
static uint32_t stm_iobase;
@@ -157,8 +163,10 @@ static struct stm_device dev;
struct chn_alloc {
u8 chn;
+ int chn_num; /* Number of consecutive channels allocated */
int xmit_byte_count;
- enum msg_formats chn_msg_format;
+ enum msg_format_t msg_format;
+ enum msg_data_t msg_data_type;
struct mutex chn_lock;
struct list_head chn_list_link;
};
@@ -212,7 +220,7 @@ int get_global_info(struct stm_global_info *info)
}
/* Write buf to STM port */
-int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
+int stm_write(void *chn_id, char *buf, int cnt, bool uspace, bool timestamp)
{
/*
@@ -223,17 +231,13 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
*/
int ret = 0;
const char *local_buf = NULL;
- struct chn_alloc *chn_obj = find_chn_object(chn);
+ struct chn_alloc *chn_obj = chn_id;
int hdr_size = 0;
uint32_t ost_header[2] = { 0 };
+ uint32_t ost_protocol;
- if (chn_obj < 0)
- return (int)chn_obj;
-
- if (!buf || cnt < 1 || !chn_obj) {
- ret = -EINVAL;
- goto stm_write_exit;
- }
+ if (!buf || cnt < 1 || !chn_obj)
+ return -EINVAL;
/*
* Provide protection for chn_obj accesses and keeps all
@@ -242,7 +246,7 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
if (mutex_lock_interruptible(&chn_obj->chn_lock))
return -ERESTARTSYS;
- switch (chn_obj->chn_msg_format) {
+ switch (chn_obj->msg_format) {
case VENDOR:
if (uspace) {
@@ -260,16 +264,32 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
ret = -EFAULT;
goto stm_write_exit;
}
+ } else {
+ local_buf = buf;
}
/* Send message over STM channel */
- build_ost_header((uint32_t)OST_PROTOCOL_BYTESTREAM, cnt,
- (uint32_t *)ost_header, &hdr_size);
- ret = stm_put_msg((void *)ost_header, hdr_size,
- (void *)local_buf, cnt, chn, timestamp);
+ ost_protocol = (STRING == chn_obj->msg_data_type)
+ ? OST_PROTOCOL_CHARSTREAM
+ : OST_PROTOCOL_BINSTREAM;
+
+ build_ost_header(ost_protocol, cnt,
+ (uint32_t *)ost_header, &hdr_size);
+
+ if (STRING == chn_obj->msg_data_type)
+ ret = stm_put_msg((void *)ost_header, hdr_size,
+ (void *)local_buf, cnt,
+ chn_obj->chn, timestamp);
+ else
+ ret = stm_put_bin((void *)ost_header, hdr_size,
+ (void *)local_buf, chn_obj->msg_data_type,
+ cnt, chn_obj->chn, timestamp);
if (!ret)
ret = cnt;
+ if (!uspace)
+ local_buf = NULL;
+
break;
case USER:
@@ -277,7 +297,14 @@ int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
* No need to worry about exceeding STM_MAX_XFER_BYTES because
* stm_fw driver takes care of this check.
*/
- ret = stm_put_msg(NULL, 0, (void *)buf, cnt, chn, timestamp);
+ if (STRING == chn_obj->msg_data_type) {
+ ret = stm_put_msg(NULL, 0, (void *)buf, cnt,
+ chn_obj->chn, timestamp);
+ } else {
+ ret = stm_put_bin(NULL, 0, (void *)buf,
+ chn_obj->msg_data_type,
+ cnt, chn_obj->chn, timestamp);
+ }
if (!ret)
ret = cnt;
@@ -300,45 +327,53 @@ stm_write_exit:
return ret;
}
-enum usecase_id {
- USECASE_USER,
- USECASE_PRINTK,
- USECASE_LAST
-};
+int stm_write_mark(void *chn_id, char *pbuf, int cnt, bool uspace,
+ bool timestamp)
+{
+ int ret = 0;
+ const int pid_msg_max = 64;
+ char pid_msg[pid_msg_max];
+ uint msg_cnt;
+ struct chn_alloc *chn_obj = chn_id;
+ enum msg_format_t orig_msg_format = chn_obj->msg_format;
+ enum msg_data_t orig_msg_data_type = chn_obj->msg_data_type;
-static char *usecase_cmds[] = {
- [USECASE_USER] = "user",
- [USECASE_PRINTK] = "printk"
-};
+ msg_cnt = snprintf(pid_msg, pid_msg_max, "PID %d using STM Channel %d",
+ *(pid_t *)pbuf, chn_obj->chn);
+
+ chn_obj->msg_format = VENDOR;
+ chn_obj->msg_data_type = STRING;
+
+ ret = stm_write(chn_id, pid_msg, msg_cnt, uspace, timestamp);
-int stm_allocate_channel(char *usecase)
+ chn_obj->msg_format = orig_msg_format;
+ chn_obj->msg_data_type = orig_msg_data_type;
+
+ return ret;
+}
+
+int stm_allocate_channel(enum stm_usecase uc_id, void **chn_id)
{
int chn;
int ret = 0;
int chn_offset;
int chn_num;
int chn_last;
- enum usecase_id uc_id;
struct chn_alloc *chn_obj;
+ *chn_id = NULL;
+
if (mutex_lock_interruptible(&dev.lock))
return -ERESTARTSYS;
- /* Search for the supported usecase id */
- for (uc_id = USECASE_USER; uc_id < USECASE_LAST; uc_id++)
- if (!strncmp(usecase, usecase_cmds[uc_id],
- strlen(usecase_cmds[uc_id])))
- break;
-
switch (uc_id) {
-
- case USECASE_USER:
+ case USER_CHANNEL_REQUEST:
chn_num = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
chn_offset = STM_START_ALLOC;
chn_last = chn_num;
break;
- case USECASE_PRINTK:
+ case PRINTK_CHANNEL_REQUEST:
chn_num = STM_CHANNEL_RESERVED;
chn_offset = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
chn_last = STM_CHANNEL_TOTAL;
@@ -349,6 +384,8 @@ int stm_allocate_channel(char *usecase)
goto stm_allocate_channel_exit;
}
+/*TODO: Can simplify since using a mutex to protect */
+
/* Look for a free channel from channel map - note thread safe test */
do {
chn = find_next_zero_bit(dev.chn_map, chn_num, chn_offset);
@@ -359,20 +396,13 @@ int stm_allocate_channel(char *usecase)
goto stm_allocate_channel_exit;
}
- chn_obj = kmalloc(sizeof(struct chn_alloc), GFP_KERNEL);
- if (!chn_obj) {
- ret = -ENOMEM;
+ chn_obj = construct_chn_obj(chn, 1);
+ if (IS_ERR(chn_obj)) {
+ ret = PTR_ERR(chn_obj);
goto stm_allocate_channel_exit;
}
- mutex_init(&chn_obj->chn_lock);
- chn_obj->chn = chn;
- chn_obj->chn_msg_format = VENDOR;
- chn_obj->xmit_byte_count = 0;
-
- list_add(&chn_obj->chn_list_link, &dev.chn_list_head);
- dev.user_allocated_chn_cnt++;
- ret = chn;
+ *chn_id = chn_obj;
stm_allocate_channel_exit:
@@ -381,51 +411,165 @@ stm_allocate_channel_exit:
}
-int stm_free_channel(int chn)
+int stm_free_channel(void *chn_id)
{
- struct list_head *ptr;
- struct chn_alloc *chn_obj = NULL;
+ int i;
+ struct chn_alloc *chn_obj = chn_id;
if (mutex_lock_interruptible(&dev.lock))
return -ERESTARTSYS;
- list_for_each(ptr, &dev.chn_list_head) {
- chn_obj = list_entry(ptr, struct chn_alloc, chn_list_link);
- if (!chn_obj || chn != chn_obj->chn)
- continue;
+ /* Make sure nobody else is using the channel. */
+ if (mutex_lock_interruptible(&chn_obj->chn_lock)) {
+ mutex_unlock(&dev.lock);
+ return -ERESTARTSYS;
+ }
- /* Make sure nobody else is using the channel. */
- if (mutex_lock_interruptible(&chn_obj->chn_lock)) {
- mutex_unlock(&dev.lock);
- return -ERESTARTSYS;
- }
- /* Remove the channel from the link list. */
- list_del(ptr);
- /* Safe to unlock. */
- mutex_unlock(&chn_obj->chn_lock);
+ /* Remove the channel from the link list. */
+ list_del(&chn_obj->chn_list_link);
+
+ /* Safe to unlock. */
+ mutex_unlock(&chn_obj->chn_lock);
- clear_bit(chn, dev.chn_map);
+ /* Free channels */
+ for (i = chn_obj->chn; i < chn_obj->chn + chn_obj->chn_num; i++) {
+ clear_bit(i, dev.chn_map);
dev.user_allocated_chn_cnt--;
- kfree(chn_obj);
- break;
}
+ kfree(chn_obj);
+
mutex_unlock(&dev.lock);
return 0;
}
+/* close function used to free the allocated channels */
+void vm_mmap_close(struct vm_area_struct *vma)
+{
+ struct chn_alloc *chn_obj = vma->vm_private_data;
+
+ stm_free_channel(chn_obj);
+
+}
+
+/* nopage currently simply sends a NOPAGE signal */
+int vm_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+
+ return VM_FAULT_SIGBUS;
+}
+/* Note: Can add vma_mmap_open to support allocating new
+ * STM channels for a forked process. Our assuption is users
+ * will mmap channles required after fork.
+ * Can add a vma_mmap_nopage to deal with page faults and mremap
+ * to allocat or extend an existing allocation of physical
+ * STM port addresses, automatically mapping them for the
+ * user space application. Our assumption is users will simply
+ * use mmap.
+ */
+static struct vm_operations_struct vma_mmap_ops = {
+ .close = vm_mmap_close,
+ .fault = vm_mmap_fault
+};
+
+/* Map each 4K (stm channel resolution) of user virtual address space
+ * to physical STM channel ports.
+ */
+int stm_mmap_channels(struct vm_area_struct *vma)
+{
+ int ret = 0;
+ int i;
+ unsigned long vma_size = vma->vm_end - vma->vm_start;
+ int num_chn_requested = vma_size/stm_resolution;
+ int orig_num_chan_requested = num_chn_requested;
+
+ int chn_num = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
+
+ int first_chn = STM_START_ALLOC;
+ int next_chn = STM_START_ALLOC;
+ int this_chn;
+
+ uint32_t phy_stm_address;
+ struct chn_alloc *chn_obj;
+
+ if (!num_chn_requested)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&dev.lock))
+ return -ERESTARTSYS;
+
+ /* Search for a block of free channels */
+ while (num_chn_requested-- > 0) {
+
+ /* Test the next channel is avaiable */
+ this_chn = find_next_zero_bit(dev.chn_map, chn_num, next_chn);
+
+ /* Check we have run out of channels */
+ if (this_chn == chn_num) {
+ ret = -EACCES;
+ goto stm_mmap_channels_err;
+ }
+
+ /* Test for the next consecutive channel not free */
+ if (this_chn != next_chn) {
+ first_chn = this_chn;
+ num_chn_requested = orig_num_chan_requested - 1;
+ }
+ next_chn = this_chn + 1;
+
+ }
+ /* Set the bits for each channel found where next_chn is now
+ * the next channel outside the range.
+ */
+ for (i = first_chn; i < next_chn; i++)
+ set_bit(i, dev.chn_map);
+
+ chn_obj = construct_chn_obj(first_chn, orig_num_chan_requested);
+ if (IS_ERR(chn_obj)) {
+ ret = PTR_ERR(chn_obj);
+ goto stm_mmap_channels_err;
+ }
+
+ mutex_unlock(&dev.lock);
+
+ /* Can now map range of first_chn to next_chn-1 */
+ phy_stm_address = stm_base_address + (first_chn * stm_resolution);
+ if (remap_pfn_range(vma, vma->vm_start, phy_stm_address>>PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ ret = -EAGAIN;
+
+ vma->vm_private_data = (void *)chn_obj;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_page_prot |= PAGE_SHARED;
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP;
+ vma->vm_ops = &vma_mmap_ops;
+
+ return ret;
+
+
+stm_mmap_channels_err:
+
+ mutex_unlock(&dev.lock);
+
+ return ret;
+}
+
enum config_id {
CFGID_FMT_USER,
CFGID_FMT_VENDOR,
CFGID_FMT_RAW,
+ CFGID_STRING,
+ CFGID_BIN8,
+ CFGID_BIN16,
+ CFGID_BIN32,
+ CFGID_GUARANTEED_TIMING,
CFGID_ROUTE_TO_PTI,
CFGID_ROUTE_TO_ETB,
CFGID_SET_MASTER,
CFGID_CLR_MASTER,
CFGID_STM_ENABLE,
CFGID_STM_DISABLE,
- CFGID_GUARANTEED_TIMING,
CFGID_LAST
};
@@ -433,17 +577,22 @@ static char *config_cmds[] = {
[CFGID_FMT_USER] = "fmt_user",
[CFGID_FMT_VENDOR] = "fmt_vendor",
[CFGID_FMT_RAW] = "fmt_raw",
+ [CFGID_STRING] = "string",
+ [CFGID_BIN8] = "binary8",
+ [CFGID_BIN16] = "binary16",
+ [CFGID_BIN32] = "binary32",
+ [CFGID_GUARANTEED_TIMING] = "guaranteed",
[CFGID_ROUTE_TO_PTI] = "route_stm_to_pti",
[CFGID_ROUTE_TO_ETB] = "route_stm_to_etb",
[CFGID_SET_MASTER] = "set_master",
[CFGID_CLR_MASTER] = "clr_master",
[CFGID_STM_ENABLE] = "stm_enable",
[CFGID_STM_DISABLE] = "stm_disable",
- [CFGID_GUARANTEED_TIMING] = "guaranteed"
+
};
-int stm_config_write(int chn, char *config_buf, int count)
+int stm_config_write(void *chn_id, char *config_buf)
{
int ret = 0;
struct chn_alloc *chn_obj;
@@ -459,19 +608,17 @@ int stm_config_write(int chn, char *config_buf, int count)
char delims[] = " ";
uint32_t control;
- chn_obj = (chn > -1) ? find_chn_object(chn) : NULL;
- if (chn_obj < 0)
- return (int)chn_obj;
-
- if (!config_buf || count < 1 || (!chn_obj && chn > -1))
+ if (!config_buf || !chn_id)
return -EINVAL;
+ chn_obj = ((int)chn_id != -1) ? chn_id : NULL;
+
if (chn_obj)
if (mutex_lock_interruptible(&chn_obj->chn_lock))
return -ERESTARTSYS;
/* check buf against list of supported features */
- for (cfg_id = CFGID_FMT_USER; cfg_id < CFGID_LAST; cfg_id++)
+ for (cfg_id = 0; cfg_id < CFGID_LAST; cfg_id++)
if (!strncmp(config_buf, config_cmds[cfg_id],
strlen(config_cmds[cfg_id])))
break;
@@ -485,18 +632,29 @@ int stm_config_write(int chn, char *config_buf, int count)
switch (cfg_id) {
case CFGID_FMT_USER:
- chn_obj->chn_msg_format = USER;
+ chn_obj->msg_format = USER;
break;
case CFGID_FMT_VENDOR:
- chn_obj->chn_msg_format = VENDOR;
+ chn_obj->msg_format = VENDOR;
break;
case CFGID_FMT_RAW:
- chn_obj->chn_msg_format = RAW;
+ chn_obj->msg_format = RAW;
ret = -EINVAL;
goto stm_config_write_exit;
-
+ case CFGID_STRING:
+ chn_obj->msg_data_type = STRING;
+ break;
+ case CFGID_BIN8:
+ chn_obj->msg_data_type = BIN8;
+ break;
+ case CFGID_BIN16:
+ chn_obj->msg_data_type = BIN16;
+ break;
+ case CFGID_BIN32:
+ chn_obj->msg_data_type = BIN32;
+ break;
case CFGID_ROUTE_TO_ETB:
/* Note: call stm_app_ownership first*/
/* Note: need to set rate at which masters are generated
@@ -582,8 +740,10 @@ int stm_config_write(int chn, char *config_buf, int count)
control = ioread32((void *)(stm_cntl_iobase
+ STM_SWMCTRL0_OFFSET));
- if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_ENABLED)
- return -EFAULT;
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_ENABLED) {
+ ret = -EFAULT;
+ goto stm_config_write_exit;
+ }
break;
@@ -604,8 +764,10 @@ int stm_config_write(int chn, char *config_buf, int count)
control = ioread32((void *)(stm_cntl_iobase
+ STM_SWMCTRL0_OFFSET));
- if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE)
- return -EFAULT;
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE) {
+ ret = -EFAULT;
+ goto stm_config_write_exit;
+ }
break;
@@ -614,11 +776,9 @@ int stm_config_write(int chn, char *config_buf, int count)
break;
default:
/* If the config request not supported */
- count = -EINVAL;
+ ret = -EINVAL;
}
- ret = count;
-
stm_config_write_exit:
if (chn_obj)
@@ -629,16 +789,13 @@ stm_config_write_exit:
}
/* Provide comma seperated list of configuration and channel state info. */
-int stm_config_read(int chn, char *config_string, int count)
+int stm_config_read(void *chn_id, char *config_string, int count)
{
- struct chn_alloc *chn_obj = find_chn_object(chn);
+ struct chn_alloc *chn_obj = chn_id;
int buf_cnt = 0;
char *chn_format = NULL;
- if (IS_ERR(chn_obj))
- return PTR_ERR(chn_obj);
-
if (!config_string || count < 1 || !chn_obj)
return -EINVAL;
@@ -648,7 +805,7 @@ int stm_config_read(int chn, char *config_string, int count)
buf_cnt = snprintf(config_string, count, "STM channel %d\n,",
chn_obj->chn);
- switch (chn_obj->chn_msg_format) {
+ switch (chn_obj->msg_format) {
case VENDOR:
chn_format = config_cmds[CFGID_FMT_VENDOR];
break;
@@ -679,10 +836,12 @@ static struct stm_operations stm_ti_ops = {
.name = "stm_ti1.0",
.get_global_info = get_global_info,
.write = stm_write,
+ .write_mark = stm_write_mark,
.allocate_channel = stm_allocate_channel,
.free_channel = stm_free_channel,
.config_write = stm_config_write,
- .config_read = stm_config_read
+ .config_read = stm_config_read,
+ .mmap = stm_mmap_channels
};
@@ -696,19 +855,18 @@ void stm_ti_clean(void)
kfree(chn_obj);
}
- release_mem_region(stm_base_address, STM_ADDRESS_SPACE);
- release_mem_region(stm_control_base, STM_ADDRESS_SPACE);
-
-
- if (!stm_iobase) {
+ if (stm_iobase) {
iounmap((void *)stm_iobase);
stm_iobase = 0;
}
- if (!stm_cntl_iobase) {
+ if (stm_cntl_iobase) {
iounmap((void *)stm_cntl_iobase);
stm_cntl_iobase = 0;
}
+
+ release_mem_region(stm_base_address, STM_ADDRESS_SPACE);
+ release_mem_region(stm_control_base, STM_ADDRESS_SPACE);
}
@@ -716,10 +874,9 @@ int __init stm_ti_init(void)
{
int ret = 0;
- char *mod_name = "STM 1.0 Module";
if (!request_mem_region(stm_base_address, STM_ADDRESS_SPACE,
- mod_name)) {
+ stm_ti_ops.name)) {
ret = -ENODEV;
goto init_err;
}
@@ -732,7 +889,7 @@ int __init stm_ti_init(void)
}
if (!request_mem_region(stm_control_base, STM_ADDRESS_SPACE,
- mod_name)) {
+ stm_ti_ops.name)) {
ret = -ENODEV;
goto init_err;
}
@@ -764,8 +921,9 @@ init_err:
void __exit stm_ti_exit(void)
{
- pr_info("stm_ti1.0: driver exit\n");
+ stm_unregister();
stm_ti_clean();
+ pr_info("stm_ti1.0: driver exit\n");
}
module_init(stm_ti_init);
@@ -777,25 +935,27 @@ MODULE_LICENSE("Dual BSD/GPL");
/*****************************************************************************
* Support functions
*****************************************************************************/
-static struct chn_alloc *find_chn_object(int chn)
+
+/* Assumpti0on this function called with dev.lock mutex already locked */
+static struct chn_alloc *construct_chn_obj(int chn, int chn_num)
{
- struct list_head *ptr;
- struct chn_alloc *chn_obj = NULL;
- struct chn_alloc *chn_obj_ret = NULL;
+ struct chn_alloc *chn_obj;
- if (mutex_lock_interruptible(&dev.lock))
- return (struct chn_alloc *)-ERESTARTSYS;
+ chn_obj = kmalloc(sizeof(struct chn_alloc), GFP_KERNEL);
+ if (!chn_obj)
+ return (struct chn_alloc *)-ENOMEM;
- list_for_each(ptr, &dev.chn_list_head) {
- chn_obj = list_entry(ptr, struct chn_alloc, chn_list_link);
- if (chn == chn_obj->chn) {
- chn_obj_ret = chn_obj;
- break;
- }
- }
+ mutex_init(&chn_obj->chn_lock);
+ chn_obj->chn = chn;
+ chn_obj->chn_num = chn_num;
+ chn_obj->msg_format = VENDOR;
+ chn_obj->msg_data_type = STRING;
+ chn_obj->xmit_byte_count = 0;
- mutex_unlock(&dev.lock);
- return chn_obj_ret;
+ list_add(&chn_obj->chn_list_link, &dev.chn_list_head);
+ dev.user_allocated_chn_cnt += chn_num;
+
+ return chn_obj;
}
static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
@@ -803,7 +963,7 @@ static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
{
/* Parse the set header command */
int i;
- int ret;
+ int ret = 0;
char **item = &kbuf;
/* Get command - throw it away */
char *param = strsep(item, delims);
@@ -813,16 +973,20 @@ static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
param = strsep(item, delims);
if (!param)
return -EINVAL;
-
+#if (LINUX_VERSION_CODE == 132643) /*2.6.35*/
+ ret = strict_strtol(param, 0, &data[i]);
+#else
ret = kstrtol(param, 10, &data[i]);
+#endif
if (ret)
return ret;
+
if (data[i] < 0 || data[i] > max_ulong)
return -EINVAL;
}
- return 0;
+ return ret;
}
static inline uint32_t compose_address(uint32_t addr_type, int32_t stm_chn)
@@ -854,8 +1018,8 @@ static void build_ost_header(uint32_t protocol_id, uint32_t size,
static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
uint32_t msg_size, int32_t stm_chn, bool timestamp)
{
- volatile void * __restrict msg_address;
- volatile void * __restrict end_address;
+ void *__restrict msg_address;
+ void *__restrict end_address;
uint32_t msg_buf_alignemnt;
uint32_t hdr_wrd_cnt;
uint16_t *short_address;
@@ -943,6 +1107,79 @@ static int32_t stm_put_msg(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
return 0;
}
+static int32_t stm_put_bin(void *phdr_buf, int32_t hdr_size, void *pmsg_buf,
+ enum msg_data_t element_type, uint32_t num_bytes,
+ int32_t stm_chn, bool timestamp)
+{
+ void *__restrict msg_address;
+ void *__restrict end_address;
+ int i;
+ uint8_t *__restrict pmsg_byte = (uint8_t *)pmsg_buf;
+ uint16_t *__restrict pmsg_short = (uint16_t *)pmsg_buf;
+ uint32_t *__restrict pmsg_word = (uint32_t *)pmsg_buf;
+
+ if (!num_bytes)
+ return 0;
+
+ msg_address = (void *)compose_address(STM_REGULAR, stm_chn);
+ if (true == timestamp)
+ end_address = (void *)compose_address(STM_TIMESTAMP, stm_chn);
+ else
+ end_address = msg_address;
+
+ /* If the header pointer is not null and the header
+ * word count is greater than 0, send the header.
+ * Else (header word count 0 or header pointer null)
+ * then it's assumed the header is contained in the message.
+ */
+ if (hdr_size && phdr_buf) {
+ uint32_t hdr_wrd_cnt = hdr_size/STM_WORD_SIZE;
+ while (hdr_wrd_cnt--) {
+ iowrite32(*(uint32_t *)phdr_buf++,
+ (uint32_t *)msg_address);
+ }
+ }
+
+ switch (element_type) {
+ case BIN8:
+ {
+ i = num_bytes - 1;
+
+ while (i--)
+ iowrite8(*pmsg_byte++, (uint8_t *)msg_address);
+
+ iowrite8(*pmsg_byte, (uint8_t *)end_address);
+
+ break;
+ }
+ case BIN16:
+ {
+ i = num_bytes/2 - 1;
+
+ while (i--)
+ iowrite16(*pmsg_short++, (uint16_t *)msg_address);
+
+ iowrite16(*pmsg_short, (uint16_t *)end_address);
+
+ break;
+ }
+ case BIN32:
+ {
+ i = num_bytes/4 - 1;
+
+ while (i--)
+ iowrite32(*pmsg_word++, (uint32_t *)msg_address);
+
+ iowrite32(*pmsg_word, (uint32_t *)end_address);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
static bool stm_app_ownership(void)
{
uint32_t control;