summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuodong Xu <guodong.xu@linaro.org>2012-07-10 07:53:31 +0800
committerRyan Harkin <ryan.harkin@linaro.org>2012-08-10 11:44:48 +0100
commited129e110b9e5879d7953f3ed4d8ac71bd4ec7ab (patch)
tree2c3ca30e41404683b86eead9f0a0bfaea299b959
parent8bd40919c0f41fd626cc5fe8a2dbfb43443116f6 (diff)
drivers/stm: Add stm_dummy.c for STM testing purpose when no real STM hardware
-rw-r--r--drivers/stm/stm_dummy.c965
1 files changed, 965 insertions, 0 deletions
diff --git a/drivers/stm/stm_dummy.c b/drivers/stm/stm_dummy.c
new file mode 100644
index 00000000000..796481d1ac4
--- /dev/null
+++ b/drivers/stm/stm_dummy.c
@@ -0,0 +1,965 @@
+/*
+ * stm_dummy.c
+ *
+ * System Trace Module (STM) Framework Dummy Driver Implementation
+ * Purpose of this is to assist verification of STM features in platforms
+ * without real STM hardware.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2012 Linaro - http://www.linaro.org
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "stm_fw.h"
+#include "stm_msg.h"
+
+/*****************************************************************************
+ * Support function prototypes
+ *****************************************************************************/
+static int parse_ulongs_from_string(int num_longs, int max_ulong, long *data,
+ char *kbuf, char *delims);
+
+static void build_ost_header(uint32_t protocol_id, uint32_t size,
+ uint32_t *ret_buf, int32_t *buf_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 bool stm_app_ownership(void);
+
+static bool stm_test_enable(void);
+
+static bool stm_test_clock(void);
+
+/*****************************************************************************
+ * Local definitions and statics variables
+ *****************************************************************************/
+#define STM_CHANNEL_TOTAL 256 /* Total number of channels. */
+#define STM_CHANNEL_RESERVED 32 /* Number of reserved channels. */
+#define STM_START_ALLOC 0 /* Start allocating channels with chn 0. */
+#define STM_MAX_SW_MASTERS 4 /* Maximum number of sw masters active at
+ * any one time (not including masking) */
+#define STM_MAX_HW_MASTERS 4 /* Maximum number of hw masters active at
+ * 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];
+
+//RMH static const uint32_t stm_base_address = L4_EMU_44XX_BASE;
+static const uint32_t stm_resolution = 0x1000;
+//RMH static uint32_t stm_iobase;
+#define STM_ADDRESS_SPACE (stm_resolution * STM_CHANNEL_TOTAL)
+
+//RMH static const uint32_t stm_control_base = L4_EMU_44XX_BASE + 0x161000;
+//RMH static const uint32_t stm_control_size = 4096;
+//RMH static uint32_t stm_cntl_iobase;
+
+/* These are offsets from stm_control_base */
+/* non ARM STM spec v1.0 */
+#define STM_SWMCTRL0_OFFSET 0x024
+#define STM_SWMCTRL1_OFFSET 0x028
+#define STM_SWMCTRL2_OFFSET 0x02c
+#define STM_SWMCTRL3_OFFSET 0x030
+#define STM_SWMCTRL4_OFFSET 0x034
+#define STM_HWMCTRL_OFFSET 0x038
+
+/* ARM STM spec v1.0 */
+#define STM_LOCK_OFFSET 0xFB0 /* STMLAR */
+#define STM_LOCK_STATUS_OFFSET 0xFB4 /* STMLSR */
+
+/* STM_SWMCTRL0 bit definitions */
+/* non ARM STM spec v1.0 */
+#define STM_OWNERSHIP_MASK 0xC0000000
+#define STM_OWNERSHIP_AVAILABLE 0x00000000
+#define STM_OWNERSHIP_CLAIMED 0x40000000
+#define STM_OWNERSHIP_ENABLED 0x80000000
+#define STM_OWNERSHIP_OVERRIDE 0x20000000
+#define STM_CURRENT_OWNER_MASK 0x10000000
+#define STM_CURRENT_OWNER_APP 0x10000000
+#define STM_MODULE_ENABLE 0x80010000
+#define STM_MODULE_DISABLE 0x00000000
+
+/* ARM STM spec v1.0 */
+/* STM Lock Access Register value */
+#define STM_MODULE_UNLOCK 0xC5ACCE55
+/* STM Lock Status bits */
+#define STM_LOCK_STATUS_MASK 0x2
+#define STM_LOCK_STATUS_LOCKED 0x2
+#define STM_LOCK_IMPLEMENTED 0x1
+
+/* STM element size */
+enum {
+ STM_BYTE_SIZE = BIT(0), /* Byte element size */
+ STM_SHORT_SIZE = BIT(1), /* Short element size */
+ STM_WORD_SIZE = BIT(2) /* Word element size */
+};
+
+enum {
+ STM_BYTE1_ALIGN = 1,
+ STM_SHORT_ALIGN = 2,
+ STM_BYTE3_ALIGN = 3,
+ STM_WORD_ALIGN = 4
+};
+
+/* STM address types */
+enum {
+ STM_REGULAR = 1,
+ STM_TIMESTAMP = 2
+};
+
+struct stm_dummy_device {
+ struct mutex lock;
+ struct list_head chn_list_head;
+ int user_allocated_chn_cnt;
+ DECLARE_BITMAP(chn_map, STM_CHANNEL_TOTAL);
+ DECLARE_BITMAP(sw_master_map, STM_MAX_SW_MASTERS);
+ DECLARE_BITMAP(hw_master_map, STM_MAX_HW_MASTERS);
+};
+
+static struct stm_dummy_device dev;
+
+struct chn_alloc {
+ u8 chn;
+ int xmit_byte_count;
+ enum msg_formats chn_msg_format;
+ struct mutex chn_lock;
+ struct list_head chn_list_link;
+};
+
+/*****************************************************************************
+ * Public Functions registered with the stm_fw driver
+ *****************************************************************************/
+
+/* Provide information on what is supported by the driver,
+ * what is not supported is optional.
+ */
+int get_global_info(struct stm_global_info *info)
+{
+ int count;
+ int ret = 0;
+
+ /* Using dev.lock to protect attribute_buf and
+ * dev.user_allocated_chn_cnt
+ */
+ if (mutex_lock_interruptible(&dev.lock))
+ return -ERESTARTSYS;
+
+ info->total_chn_cnt = STM_CHANNEL_TOTAL;
+ info->reserved_chn_cnt = STM_CHANNEL_RESERVED;
+ info->user_allocated_chn_cnt = dev.user_allocated_chn_cnt;
+
+ /* If enable can be read then the module is powered and clocked */
+ info->stm_module_enabled = stm_test_enable();
+ if (info->stm_module_enabled)
+ info->stm_module_clock_on = 1;
+ else
+ info->stm_module_clock_on = stm_test_clock();
+
+ info->attribute_list = attribute_buf;
+
+ count = snprintf(attribute_buf, ATTRIBUTE_BUF_SIZE,
+ "printk_logging not supported\n,");
+ count += snprintf(attribute_buf + count, ATTRIBUTE_BUF_SIZE - count,
+ "traceppoint_ftrace logging not supported\n,");
+ count += snprintf(attribute_buf + count, ATTRIBUTE_BUF_SIZE - count,
+ "lttng_kernel transport not supported\n,");
+ count += snprintf(attribute_buf + count, ATTRIBUTE_BUF_SIZE - count,
+ "Port routing not supported\n");
+
+ if (count > ATTRIBUTE_BUF_SIZE)
+ ret = -ENOBUFS;
+
+ mutex_unlock(&dev.lock);
+
+ return ret;
+}
+
+/* Write buf to STM port */
+int stm_write(int chn, char *buf, int cnt, bool uspace, bool timestamp)
+{
+
+ /*
+ * TODO:: If cnt > STM_MAX_XFER (4096) then only transfer a partial
+ * message without a timestamp. Only time stamp message when count is
+ * completly transfered. May need to change stm_write API to include
+ * position to determine first (OST), middle or last(timestamp).
+ */
+ int ret = 0;
+ const char *local_buf = NULL;
+ struct chn_alloc *chn_obj = find_chn_object(chn);
+ int hdr_size = 0;
+ uint32_t ost_header[2] = { 0 };
+
+ if (IS_ERR(chn_obj))
+ return PTR_ERR(chn_obj);
+
+ if (!buf || cnt < 1 || !chn_obj)
+ return -EINVAL;
+
+ /*
+ * Provide protection for chn_obj accesses and keeps all
+ * writes to the same STM channel in order regardless of mode.
+ */
+ if (mutex_lock_interruptible(&chn_obj->chn_lock))
+ return -ERESTARTSYS;
+
+ switch (chn_obj->chn_msg_format) {
+
+ case VENDOR:
+ if (uspace) {
+ if (cnt > STM_MAX_XFER_BYTES) {
+ cnt = STM_MAX_XFER_BYTES;
+ timestamp = false;
+ }
+ local_buf = kmalloc(cnt, GFP_KERNEL);
+ if (!local_buf) {
+ ret = -ENOMEM;
+ goto stm_write_exit;
+ }
+
+ if (copy_from_user((void *)local_buf, buf, cnt)) {
+ ret = -EFAULT;
+ goto stm_write_exit;
+ }
+ }
+
+ /* 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);
+ if (!ret)
+ ret = cnt;
+
+ break;
+
+ case USER:
+ /*
+ * 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 (!ret)
+ ret = cnt;
+
+ break;
+
+ default:
+ ret = -EINVAL;
+ goto stm_write_exit;
+ }
+
+ if (ret > 0)
+ chn_obj->xmit_byte_count += ret;
+
+stm_write_exit:
+
+ mutex_unlock(&chn_obj->chn_lock);
+
+ kfree(local_buf);
+
+ return ret;
+}
+
+enum usecase_id {
+ USECASE_USER,
+ USECASE_PRINTK,
+ USECASE_LAST
+};
+
+static char *usecase_cmds[] = {
+ [USECASE_USER] = "user",
+ [USECASE_PRINTK] = "printk"
+};
+
+int stm_allocate_channel(char *usecase)
+{
+ int chn;
+ int ret = 0;
+ int chn_offset;
+ int chn_num;
+ int chn_last;
+ enum usecase_id uc_id;
+ struct chn_alloc *chn_obj;
+
+ 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:
+ chn_num = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
+ chn_offset = STM_START_ALLOC;
+ chn_last = chn_num;
+ break;
+
+ case USECASE_PRINTK:
+ chn_num = STM_CHANNEL_RESERVED;
+ chn_offset = STM_CHANNEL_TOTAL - STM_CHANNEL_RESERVED;
+ chn_last = STM_CHANNEL_TOTAL;
+ break;
+
+ default:
+ ret = -EINVAL;
+ goto stm_allocate_channel_exit;
+ }
+
+ /* 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);
+ } while ((chn < chn_last) && test_and_set_bit(chn, dev.chn_map));
+
+ if (chn > chn_last) {
+ ret = -EPERM;
+ goto stm_allocate_channel_exit;
+ }
+
+ chn_obj = kmalloc(sizeof(struct chn_alloc), GFP_KERNEL);
+ if (!chn_obj) {
+ ret = -ENOMEM;
+ 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;
+
+stm_allocate_channel_exit:
+
+ mutex_unlock(&dev.lock);
+ return ret;
+
+}
+
+int stm_free_channel(int chn)
+{
+ struct list_head *ptr;
+ struct chn_alloc *chn_obj = NULL;
+
+ 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;
+ }
+ /* Remove the channel from the link list. */
+ list_del(ptr);
+ /* Safe to unlock. */
+ mutex_unlock(&chn_obj->chn_lock);
+
+ clear_bit(chn, dev.chn_map);
+ dev.user_allocated_chn_cnt--;
+ kfree(chn_obj);
+ break;
+ }
+
+ mutex_unlock(&dev.lock);
+
+ return 0;
+}
+
+enum config_id {
+ CFGID_FMT_USER,
+ CFGID_FMT_VENDOR,
+ CFGID_FMT_RAW,
+ 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
+};
+
+static char *config_cmds[] = {
+ [CFGID_FMT_USER] = "fmt_user",
+ [CFGID_FMT_VENDOR] = "fmt_vendor",
+ [CFGID_FMT_RAW] = "fmt_raw",
+ [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 ret = 0;
+ struct chn_alloc *chn_obj;
+ enum config_id cfg_id;
+ void *map;
+ int max;
+ uint32_t master_select;
+ uint32_t master_mask;
+ unsigned int i;
+ const int num_ulongs = 2;
+ const int max_ulong = 255;
+ long data[num_ulongs];
+ 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))
+ return -EINVAL;
+
+ 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++)
+ if (!strncmp(config_buf, config_cmds[cfg_id],
+ strlen(config_cmds[cfg_id])))
+ break;
+
+ /* All cmd_id's less than CFGID_ROUTE_TO_PTI require a vaild chn_obj */
+ if (!chn_obj && cfg_id < CFGID_ROUTE_TO_PTI) {
+ ret = -EINVAL;
+ goto stm_config_write_exit;
+ }
+
+ switch (cfg_id) {
+
+ case CFGID_FMT_USER:
+ chn_obj->chn_msg_format = USER;
+ break;
+
+ case CFGID_FMT_VENDOR:
+ chn_obj->chn_msg_format = VENDOR;
+ break;
+
+ case CFGID_FMT_RAW:
+ chn_obj->chn_msg_format = RAW;
+ ret = -EINVAL;
+ goto stm_config_write_exit;
+
+ case CFGID_ROUTE_TO_ETB:
+ /* Note: call stm_app_ownership first*/
+ /* Note: need to set rate at which masters are generated
+ * for ETB.
+ */
+ break;
+
+ case CFGID_ROUTE_TO_PTI:
+ /* Note: In TI case CCS ssets up the PTI port, so this is
+ * really just a command to disable the ETB routing.
+ * TODO: Think about changing to CFGID_ROUTE_TO_NULL
+ */
+ break;
+
+ case CFGID_SET_MASTER:
+ ret = parse_ulongs_from_string(num_ulongs, max_ulong,
+ data, config_buf, delims);
+ if (ret < 0)
+ goto stm_config_write_exit;
+
+ /* if avaiable set ownership to application (verses debugger) */
+ if (!stm_app_ownership()) {
+ ret = -EACCES;
+ goto stm_config_write_exit;
+ }
+
+ /* Test for an avaiable master select */
+ if (data[0] & HW_MASTER_MASK) {
+ map = dev.hw_master_map;
+ max = STM_MAX_HW_MASTERS;
+ } else {
+ map = dev.sw_master_map;
+ max = STM_MAX_SW_MASTERS;
+ }
+
+ do {
+ i = find_next_zero_bit(map, max, 0);
+ } while ((i < max) && test_and_set_bit(i, map));
+ if (i == STM_MAX_SW_MASTERS) {
+ ret = -EINVAL;
+ goto stm_config_write_exit;
+ }
+
+ if (data[0] & HW_MASTER_MASK) {
+ /* set hw master select value */
+//RMH master_select = ioread32((void *)(stm_cntl_iobase +
+//RMH STM_HWMCTRL_OFFSET));
+ master_select = 0; //RMH
+ master_select |= data[0] << (i * 8);
+//RMH iowrite32(master_select, (void *)(stm_cntl_iobase +
+//RMH STM_HWMCTRL_OFFSET));
+ } else {
+ /* set sw master select value */
+//RMH master_select = ioread32((void *)(stm_cntl_iobase +
+//RMH STM_SWMCTRL1_OFFSET));
+ master_select = 0; //RMH
+ master_select |= data[0] << (i * 8);
+//RMH iowrite32(master_select, (void *)(stm_cntl_iobase +
+//RMH STM_SWMCTRL1_OFFSET));
+ /* set master mask value */
+//RMH master_mask = ioread32((void *)stm_cntl_iobase +
+//RMH STM_SWMCTRL2_OFFSET);
+ master_mask = 0; //RMH
+ master_mask |= data[1] << (i * 8);
+//RMH iowrite32(master_mask, (void *)(stm_cntl_iobase +
+//RMH STM_SWMCTRL2_OFFSET));
+/* TODO:: Add fixed values for other domain master selection registers. */
+/* These may not actually need to be set. */
+
+ }
+ break;
+
+ case CFGID_STM_ENABLE:
+ /*
+ * if avaiable set ownership to application (verses host
+ * debugger)
+ */
+ if (!stm_app_ownership()) {
+ ret = -EACCES;
+ goto stm_config_write_exit;
+ }
+
+//RMH iowrite32(STM_MODULE_ENABLE, (void *)(stm_cntl_iobase
+//RMH + STM_SWMCTRL0_OFFSET));
+
+//RMH control = ioread32((void *)(stm_cntl_iobase
+//RMH + STM_SWMCTRL0_OFFSET));
+ control = 0; //RMH
+
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_ENABLED)
+ return -EFAULT;
+
+ break;
+
+ case CFGID_STM_DISABLE:
+
+ /*
+ * if avaiable set ownership to application (verses host
+ * debugger)
+ */
+ if (!stm_app_ownership()) {
+ ret = -EACCES;
+ goto stm_config_write_exit;
+ }
+
+//RMH iowrite32(STM_MODULE_DISABLE, (void *)(stm_cntl_iobase
+//RMH + STM_SWMCTRL0_OFFSET));
+
+//RMH control = ioread32((void *)(stm_cntl_iobase
+//RMH + STM_SWMCTRL0_OFFSET));
+ control = 0; //RMH
+
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE)
+ return -EFAULT;
+
+ break;
+
+ case CFGID_GUARANTEED_TIMING:
+ /* Only support to prevent error */
+ break;
+ default:
+ /* If the config request not supported */
+ count = -EINVAL;
+ }
+
+ ret = count;
+
+stm_config_write_exit:
+
+ if (chn_obj)
+ mutex_unlock(&chn_obj->chn_lock);
+
+ return ret;
+
+}
+
+/* Provide comma seperated list of configuration and channel state info. */
+int stm_config_read(int chn, char *config_string, int count)
+{
+
+ struct chn_alloc *chn_obj = find_chn_object(chn);
+ 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;
+
+ if (mutex_lock_interruptible(&chn_obj->chn_lock))
+ return -ERESTARTSYS;
+
+ buf_cnt = snprintf(config_string, count, "STM channel %d\n,",
+ chn_obj->chn);
+
+ switch (chn_obj->chn_msg_format) {
+ case VENDOR:
+ chn_format = config_cmds[CFGID_FMT_VENDOR];
+ break;
+ case USER:
+ chn_format = config_cmds[CFGID_FMT_USER];
+ break;
+ case RAW:
+ chn_format = config_cmds[CFGID_FMT_RAW];
+ break;
+ }
+ if (chn_format)
+ buf_cnt += snprintf(config_string+buf_cnt, count-buf_cnt,
+ "Channel format %s\n,", chn_format);
+
+ /* Note: If any other strings are added, this string must be terminated
+ * with a comma.
+ */
+ buf_cnt += snprintf(config_string+buf_cnt, count-buf_cnt,
+ "Transmit Byte Count %d\n", chn_obj->xmit_byte_count);
+
+ mutex_unlock(&chn_obj->chn_lock);
+
+ return buf_cnt;
+}
+
+
+static struct stm_operations stm_dummy_ops = {
+ .name = "stm_dummy",
+ .get_global_info = get_global_info,
+ .write = stm_write,
+ .allocate_channel = stm_allocate_channel,
+ .free_channel = stm_free_channel,
+ .config_write = stm_config_write,
+ .config_read = stm_config_read
+};
+
+
+void stm_dummy_clean(void)
+{
+ struct list_head *ptr;
+ struct chn_alloc *chn_obj = NULL;
+
+ list_for_each(ptr, &dev.chn_list_head) {
+ chn_obj = list_entry(ptr, struct chn_alloc, chn_list_link);
+ kfree(chn_obj);
+ }
+}
+
+
+int __init stm_dummy_init(void)
+{
+
+ int ret = 0;
+//RMH char *mod_name = "STM ARM Module";
+
+//RMH if (!request_mem_region(stm_base_address, STM_ADDRESS_SPACE,
+//RMH mod_name)) {
+//RMH ret = -ENODEV;
+//RMH goto init_err;
+//RMH }
+
+//RMH stm_iobase = (unsigned long)ioremap_nocache(stm_base_address,
+//RMH STM_ADDRESS_SPACE);
+//RMH if (!stm_iobase) {
+//RMH ret = -ENODEV;
+//RMH goto init_err;
+//RMH }
+
+//RMH if (!request_mem_region(stm_control_base, STM_ADDRESS_SPACE,
+//RMH mod_name)) {
+//RMH ret = -ENODEV;
+//RMH goto init_err;
+//RMH }
+
+//RMH stm_cntl_iobase = (unsigned long)ioremap_nocache(stm_control_base,
+//RMH stm_control_size);
+//RMH if (!stm_cntl_iobase) {
+//RMH ret = -ENODEV;
+//RMH goto init_err;
+//RMH }
+
+ /* Register with the STM Framework Drvier */
+ ret = stm_register(&stm_dummy_ops);
+ if (ret < 0)
+ goto init_err;
+
+ mutex_init(&dev.lock);
+ INIT_LIST_HEAD(&dev.chn_list_head);
+ dev.user_allocated_chn_cnt = 0;
+
+ return ret;
+
+init_err:
+ stm_dummy_clean();
+ pr_err("stm_dummy: driver registration error %d\n", ret);
+ return ret;
+
+}
+
+void __exit stm_dummy_exit(void)
+{
+ pr_info("stm_dummy: driver exit\n");
+ stm_dummy_clean();
+}
+
+module_init(stm_dummy_init);
+module_exit(stm_dummy_exit);
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("STM Dummy module");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/*****************************************************************************
+ * Support functions
+ *****************************************************************************/
+static struct chn_alloc *find_chn_object(int chn)
+{
+ struct list_head *ptr;
+ struct chn_alloc *chn_obj = NULL;
+ struct chn_alloc *chn_obj_ret = NULL;
+
+ if (mutex_lock_interruptible(&dev.lock))
+ return ERR_PTR(-ERESTARTSYS);
+
+ 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_unlock(&dev.lock);
+ return chn_obj_ret;
+}
+
+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;
+}
+
+static inline uint32_t compose_address(uint32_t addr_type, int32_t stm_chn)
+{
+ uint32_t offset;
+
+ offset = (addr_type == STM_TIMESTAMP) ? stm_resolution / 2 : 0;
+
+ return (uint32_t)(/*RMH stm_iobase + */
+ (stm_resolution * (uint32_t)stm_chn) +
+ offset);
+}
+
+static void build_ost_header(uint32_t protocol_id, uint32_t size,
+ uint32_t *ret_buf, int32_t *buf_size)
+{
+ if (size >= OST_SHORT_HEADER_LENGTH_LIMIT) {
+ *ret_buf++ = (OST_VERSION | OST_ENTITY_ID | protocol_id |
+ OST_SHORT_HEADER_LENGTH_LIMIT);
+ *ret_buf = size;
+ *buf_size = 8; /* 8 bytes for the extended length header */
+ } else {
+ *ret_buf = (OST_VERSION | OST_ENTITY_ID | protocol_id | size);
+ *buf_size = 4; /* 4 bytes for the normal header */
+ }
+}
+
+
+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)
+{
+ return 0;
+}
+
+static bool stm_app_ownership(void)
+{
+ uint32_t control;
+ uint32_t lock_status;
+ int retry = 100;
+ bool ret = true;
+
+ control = 0; //RMH ioread32((void *)stm_cntl_iobase + STM_SWMCTRL0_OFFSET);
+
+ /* If driver already owns the STM module then exit*/
+ if ((control & STM_CURRENT_OWNER_MASK) == STM_CURRENT_OWNER_APP) {
+ ret = true;
+ goto stm_app_ownership_exit;
+ }
+
+ /* If drvier does not own, and it's not avaiable then exit */
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE) {
+ ret = false;
+ goto stm_app_ownership_exit;
+ }
+
+ /* Since it's avaiable can attempt to claim - so unlock the module*/
+//RMH iowrite32(STM_MODULE_UNLOCK, (void *)stm_cntl_iobase + STM_LOCK_OFFSET);
+
+ /* Test that it unlocked properly */
+//RMH lock_status = ioread32((void *)stm_cntl_iobase +
+//RMH STM_LOCK_STATUS_OFFSET);
+ lock_status = 0;
+
+ /*
+ * If locked set or the implemented bit is not readable (in cases where
+ * the clock is not enabled) then exit, no chance at claiming STM
+ */
+ if ((lock_status & STM_LOCK_IMPLEMENTED) != STM_LOCK_IMPLEMENTED ||
+ (lock_status & STM_LOCK_STATUS_MASK) == STM_LOCK_STATUS_LOCKED) {
+ ret = false;
+ goto stm_app_ownership_exit;
+ }
+
+ /* claim */
+ control = STM_OWNERSHIP_CLAIMED;
+//RMH iowrite32(control, (void *)stm_cntl_iobase + STM_SWMCTRL0_OFFSET);
+
+ /* Test for claim and app owns */
+ do {
+ const uint32_t mask = STM_OWNERSHIP_MASK |
+ STM_CURRENT_OWNER_MASK;
+ const uint32_t claimed = STM_OWNERSHIP_CLAIMED |
+ STM_CURRENT_OWNER_APP;
+ const uint32_t enabled = STM_OWNERSHIP_ENABLED |
+ STM_CURRENT_OWNER_APP;
+
+//RMH control = ioread32((void *)stm_cntl_iobase +
+//RMH STM_SWMCTRL0_OFFSET);
+ control = 0; //RMH
+ if ((control & mask) == claimed || (control & mask) == enabled)
+ break;
+
+ } while (retry--);
+
+ if (retry == -1)
+ ret = false;
+
+stm_app_ownership_exit:
+ return ret;
+}
+
+static bool stm_test_enable()
+{
+ uint32_t control;
+
+//RMH control = ioread32((void *)stm_cntl_iobase + STM_SWMCTRL0_OFFSET);
+ control = 0; // RMH
+
+ if ((control & STM_MODULE_ENABLE) == STM_MODULE_ENABLE)
+ return true;
+
+ return false;
+}
+
+static bool stm_test_clock()
+{
+ bool app_owns = false;
+ uint32_t control;
+
+//RMH control = ioread32((void *)stm_cntl_iobase + STM_SWMCTRL0_OFFSET);
+ control = 0; //RMH
+
+ /* If driver already owns the STM module then it must be
+ * powered up and clock enabled.
+ */
+ if ((control & STM_CURRENT_OWNER_MASK) == STM_CURRENT_OWNER_APP)
+ return true;
+
+ /* If drvier does not own, and ownership state is not available
+ * (claimed or enabled) then must be powered up and clock enabled.
+ */
+ if ((control & STM_OWNERSHIP_MASK) != STM_OWNERSHIP_AVAILABLE)
+ return true;
+
+ /* If ownership is avaialbe test driver (app) can own*/
+ app_owns = stm_app_ownership();
+ if (app_owns) {
+//RMH iowrite32(STM_MODULE_DISABLE, (void *)(stm_cntl_iobase
+//RMH + STM_SWMCTRL0_OFFSET));
+ return true;
+ }
+
+ return false;
+}
+