diff options
-rw-r--r-- | drivers/stm/Kconfig | 6 | ||||
-rw-r--r-- | drivers/stm/stm_fw.c | 365 | ||||
-rw-r--r-- | drivers/stm/stm_fw.h | 22 | ||||
-rw-r--r-- | drivers/stm/stm_msg.h | 13 | ||||
-rw-r--r-- | drivers/stm/stm_omap_ti1.0.c | 489 |
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 *)¤t->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; |