arm: common: Add indirect L2 rw support for cpaccess
Added indirect L2 rw support to cpaccess kernel module. Input format
change to include a parameter to specify register access type. Validation
if register type is one of supported types.
Change-Id: I5bd52c89d87a4fb4da4248526e56079bb604f910
Signed-off-by: Suren Eda Naarayana Kulothungan <sedanaar@codeaurora.org>
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index 241e339..d3d0537 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,11 +28,19 @@
#include <linux/string.h>
#include <linux/smp.h>
#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+
+#ifdef CONFIG_ARCH_MSM_KRAIT
+#include <mach/msm-krait-l2-accessors.h>
+#endif
+
+#define TYPE_MAX_CHARACTERS 10
/*
* CP parameters
*/
struct cp_params {
+ unsigned long il2index;
unsigned long cp;
unsigned long op1;
unsigned long op2;
@@ -43,15 +51,86 @@
};
static struct semaphore cp_sem;
+static unsigned long il2_output;
static int cpu;
+char type[TYPE_MAX_CHARACTERS] = "C";
static DEFINE_PER_CPU(struct cp_params, cp_param)
- = { 15, 0, 0, 0, 0, 0, 'r' };
+ = { 0, 15, 0, 0, 0, 0, 0, 'r' };
static struct sysdev_class cpaccess_sysclass = {
.name = "cpaccess",
};
+#ifdef CONFIG_ARCH_MSM_KRAIT
+/*
+ * do_read_il2 - Read indirect L2 registers
+ * @ret: Pointer to return value
+ *
+ */
+static void do_read_il2(void *ret)
+{
+ *(unsigned long *)ret =
+ get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu));
+}
+
+/*
+ * do_write_il2 - Write indirect L2 registers
+ * @ret: Pointer to return value
+ *
+ */
+static void do_write_il2(void *ret)
+{
+ *(unsigned long *)ret =
+ set_get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu),
+ per_cpu(cp_param.write_value, cpu));
+}
+
+/*
+ * do_il2_rw - Call Read/Write indirect L2 register functions
+ * @ret: Pointer to return value in case of CP register
+ *
+ */
+static int do_il2_rw(char *str_tmp)
+{
+ unsigned long write_value, il2index;
+ char rw;
+ int ret = 0;
+
+ il2index = 0;
+ sscanf(str_tmp, "%lx:%c:%lx:%d", &il2index, &rw, &write_value,
+ &cpu);
+ per_cpu(cp_param.il2index, cpu) = il2index;
+ per_cpu(cp_param.rw, cpu) = rw;
+ per_cpu(cp_param.write_value, cpu) = write_value;
+
+ if (per_cpu(cp_param.rw, cpu) == 'r') {
+ if (is_smp()) {
+ if (smp_call_function_single(cpu, do_read_il2,
+ &il2_output, 1))
+ pr_err("Error cpaccess smp call single\n");
+ } else
+ do_read_il2(&il2_output);
+ } else if (per_cpu(cp_param.rw, cpu) == 'w') {
+ if (is_smp()) {
+ if (smp_call_function_single(cpu, do_write_il2,
+ &il2_output, 1))
+ pr_err("Error cpaccess smp call single\n");
+ } else
+ do_write_il2(&il2_output);
+ } else {
+ pr_err("cpaccess: Wrong Entry for 'r' or 'w'.\n");
+ return -EINVAL;
+ }
+ return ret;
+}
+#else
+static void do_il2_rw(char *str_tmp)
+{
+ il2_output = 0;
+}
+#endif
+
/*
* get_asm_value - Dummy fuction
* @write_val: Write value incase of a CP register write operation.
@@ -137,6 +216,45 @@
return ret;
}
+static int get_register_params(char *str_tmp)
+{
+ unsigned long op1, op2, crn, crm, cp = 15, write_value, il2index;
+ char rw;
+ int cnt = 0;
+
+ il2index = 0;
+ strncpy(type, strsep(&str_tmp, ":"), TYPE_MAX_CHARACTERS);
+
+ if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0) {
+
+ sscanf(str_tmp, "%lu:%lu:%lu:%lu:%lu:%c:%lx:%d",
+ &cp, &op1, &crn, &crm, &op2, &rw, &write_value, &cpu);
+ per_cpu(cp_param.cp, cpu) = cp;
+ per_cpu(cp_param.op1, cpu) = op1;
+ per_cpu(cp_param.crn, cpu) = crn;
+ per_cpu(cp_param.crm, cpu) = crm;
+ per_cpu(cp_param.op2, cpu) = op2;
+ per_cpu(cp_param.rw, cpu) = rw;
+ per_cpu(cp_param.write_value, cpu) = write_value;
+
+ if ((per_cpu(cp_param.rw, cpu) != 'w') &&
+ (per_cpu(cp_param.rw, cpu) != 'r')) {
+ pr_err("cpaccess: Wrong entry for 'r' or 'w'.\n");
+ return -EINVAL;
+ }
+
+ if (per_cpu(cp_param.rw, cpu) == 'w')
+ do_cpregister_rw(1);
+ } else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
+ do_il2_rw(str_tmp);
+ else {
+ pr_err("cpaccess: Not a valid type. Entered: %s\n", type);
+ return -EINVAL;
+ }
+
+ return cnt;
+}
+
/*
* cp_register_write_sysfs - sysfs interface for writing to
* CP register
@@ -147,34 +265,14 @@
*
*/
static ssize_t cp_register_write_sysfs(struct sys_device *dev,
- struct sysdev_attribute *attr, const char *buf, size_t cnt)
+ struct sysdev_attribute *attr, const char *buf, size_t cnt)
{
- unsigned long op1, op2, crn, crm, cp = 15, write_value, ret;
- char rw;
+ char *str_tmp = (char *)buf;
+
if (down_timeout(&cp_sem, 6000))
return -ERESTARTSYS;
- sscanf(buf, "%lu:%lu:%lu:%lu:%lu:%c:%lx:%d", &cp, &op1, &crn,
- &crm, &op2, &rw, &write_value, &cpu);
- per_cpu(cp_param.cp, cpu) = cp;
- per_cpu(cp_param.op1, cpu) = op1;
- per_cpu(cp_param.crn, cpu) = crn;
- per_cpu(cp_param.crm, cpu) = crm;
- per_cpu(cp_param.op2, cpu) = op2;
- per_cpu(cp_param.rw, cpu) = rw;
- per_cpu(cp_param.write_value, cpu) = write_value;
-
- if (per_cpu(cp_param.rw, cpu) == 'w') {
- do_cpregister_rw(1);
- ret = cnt;
- }
-
- if ((per_cpu(cp_param.rw, cpu) != 'w') &&
- (per_cpu(cp_param.rw, cpu) != 'r')) {
- ret = -1;
- printk(KERN_INFO "Wrong Entry for 'r' or 'w'. \
- Use cp:op1:crn:crm:op2:r/w:write_value.\n");
- }
+ get_register_params(str_tmp);
return cnt;
}
@@ -191,10 +289,17 @@
* result to the caller.
*/
static ssize_t cp_register_read_sysfs(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
+ struct sysdev_attribute *attr, char *buf)
{
int ret;
- ret = sprintf(buf, "%lx\n", do_cpregister_rw(0));
+
+ if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0)
+ ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n",
+ do_cpregister_rw(0));
+ else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
+ ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n", il2_output);
+ else
+ ret = -EINVAL;
if (cp_sem.count <= 0)
up(&cp_sem);
@@ -205,8 +310,7 @@
/*
* Setup sysfs files
*/
-SYSDEV_ATTR(cp_rw, 0644, cp_register_read_sysfs,
- cp_register_write_sysfs);
+SYSDEV_ATTR(cp_rw, 0644, cp_register_read_sysfs, cp_register_write_sysfs);
static struct sys_device device_cpaccess = {
.id = 0,
@@ -223,15 +327,13 @@
if (!error)
error = sysdev_register(&device_cpaccess);
else
- printk(KERN_ERR "Error initializing cpaccess \
- interface\n");
+ pr_err("Error initializing cpaccess interface\n");
if (!error)
error = sysdev_create_file(&device_cpaccess,
&attr_cp_rw);
else {
- printk(KERN_ERR "Error initializing cpaccess \
- interface\n");
+ pr_err("Error initializing cpaccess interface\n");
sysdev_unregister(&device_cpaccess);
sysdev_class_unregister(&cpaccess_sysclass);
}