OSDN Git Service

arm64: Add support for app specific settings
authorSarangdhar Joshi <spjoshi@codeaurora.org>
Fri, 12 Feb 2016 00:39:46 +0000 (16:39 -0800)
committerKyle Yan <kyan@codeaurora.org>
Tue, 7 Jun 2016 18:53:27 +0000 (11:53 -0700)
Add support to provide an interface that can be used from
userspace to decide whether app specific settings need to
be applied / cleared when particular processes are running.

CRs-Fixed: 981519 997757
Change-Id: Id81f8b70de64f291a8586150f4d2c7c8f8b4420f
Signed-off-by: Sarangdhar Joshi <spjoshi@codeaurora.org>
[satyap@codeaurora.org: trivial merge conflict resolution and pull
fixes for CR: 997757]
Signed-off-by: Satya Durga Srinivasu Prabhala <satyap@codeaurora.org>
arch/arm64/Kconfig
arch/arm64/include/asm/app_api.h [new file with mode: 0644]
arch/arm64/include/asm/fpsimd.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/app_api.c [new file with mode: 0644]
arch/arm64/kernel/app_setting.c [new file with mode: 0644]
arch/arm64/kernel/entry-fpsimd.S
arch/arm64/kernel/fpsimd.c
include/linux/mm_types.h
kernel/sched/core.c
mm/mmap.c

index 706129c..69c9b84 100644 (file)
@@ -513,9 +513,20 @@ config ARM64_64K_PAGES
 
 endchoice
 
+config MSM_APP_API
+       bool "API support to enable / disable app settings for MSM8996"
+       depends on ARCH_MSM8996 && (ENABLE_FP_SIMD_SETTINGS || MSM_APP_SETTINGS)
+       help
+         Add API support to enable / disable the app settings to be used
+         at runtime. These APIs are used to enable / disable app setting
+         when specific aarch32 or aarch64 processes are running.
+
+         If you are not sure what to do, select 'N' here.
+
 config ENABLE_FP_SIMD_SETTINGS
        bool "Enable FP(Floating Point) Settings for Qualcomm MSM8996"
        depends on ARCH_MSM8996
+       select MSM_APP_API
        help
          Enable FP(Floating Point) and SIMD settings for the MSM8996 during
          the execution of the aarch32 processes and disable these settings
@@ -523,6 +534,16 @@ config ENABLE_FP_SIMD_SETTINGS
 
          If you are not sure what to do, select 'N' here.
 
+config MSM_APP_SETTINGS
+       bool "Support to enable / disable app settings for MSM8996"
+       depends on ARCH_MSM8996
+       select MSM_APP_API
+       help
+         Expose an interface used by the userspace at runtime to
+         enable / disable the app specific settings.
+
+         If you are not sure what to do, select 'N' here.
+
 choice
        prompt "Virtual address space size"
        default ARM64_VA_BITS_39 if ARM64_4K_PAGES
diff --git a/arch/arm64/include/asm/app_api.h b/arch/arm64/include/asm/app_api.h
new file mode 100644 (file)
index 0000000..2162400
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (c) 2016, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_APP_API_H
+#define __ASM_APP_API_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+#define APP_SETTING_BIT                30
+#define MAX_ENTRIES            10
+
+/*
+ * APIs to set / clear the app setting bits
+ * in the register.
+ */
+#ifdef CONFIG_MSM_APP_API
+extern void set_app_setting_bit(uint32_t bit);
+extern void clear_app_setting_bit(uint32_t bit);
+#else
+static inline void set_app_setting_bit(uint32_t bit) {}
+static inline void clear_app_setting_bit(uint32_t bit) {}
+#endif
+
+#ifdef CONFIG_MSM_APP_SETTINGS
+extern void switch_app_setting_bit(struct task_struct *prev,
+                                  struct task_struct *next);
+extern void apply_app_setting_bit(struct file *file);
+extern bool use_app_setting;
+#endif
+
+#endif
index 355871b..3efaa5c 100644 (file)
@@ -84,13 +84,9 @@ extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
 #ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS
 extern void fpsimd_disable_trap(void);
 extern void fpsimd_enable_trap(void);
-extern void fpsimd_settings_disable(void);
-extern void fpsimd_settings_enable(void);
 #else
 static inline void fpsimd_disable_trap(void) {}
 static inline void fpsimd_enable_trap(void) {}
-static inline void fpsimd_settings_disable(void) {}
-static inline void fpsimd_settings_enable(void) {}
 #endif
 
 #endif
index 9f7794c..57e55e4 100644 (file)
@@ -43,6 +43,8 @@ arm64-obj-$(CONFIG_EFI)                       += efi.o efi-entry.stub.o
 arm64-obj-$(CONFIG_PCI)                        += pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)   += armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)               += acpi.o
+arm64-obj-$(CONFIG_MSM_APP_API)                += app_api.o
+arm64-obj-$(CONFIG_MSM_APP_SETTINGS)   += app_setting.o
 
 obj-y                                  += $(arm64-obj-y) vdso/
 obj-m                                  += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/app_api.c b/arch/arm64/kernel/app_api.c
new file mode 100644 (file)
index 0000000..39eeee1
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (c) 2016, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/export.h>
+
+#include <asm/app_api.h>
+
+static spinlock_t spinlock;
+static DEFINE_PER_CPU(int, app_config_applied);
+static unsigned long app_config_set[NR_CPUS];
+static unsigned long app_config_clear[NR_CPUS];
+
+void set_app_setting_bit(uint32_t bit)
+{
+       unsigned long flags;
+       uint64_t reg;
+       int cpu;
+
+       spin_lock_irqsave(&spinlock, flags);
+       asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg));
+       reg = reg | BIT(bit);
+       isb();
+       asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg));
+       isb();
+       if (bit == APP_SETTING_BIT) {
+               cpu = raw_smp_processor_id();
+               app_config_set[cpu]++;
+
+               this_cpu_write(app_config_applied, 1);
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+
+}
+EXPORT_SYMBOL(set_app_setting_bit);
+
+void clear_app_setting_bit(uint32_t bit)
+{
+       unsigned long flags;
+       uint64_t reg;
+       int cpu;
+
+       spin_lock_irqsave(&spinlock, flags);
+       asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg));
+       reg = reg & ~BIT(bit);
+       isb();
+       asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg));
+       isb();
+       if (bit == APP_SETTING_BIT) {
+               cpu = raw_smp_processor_id();
+               app_config_clear[cpu]++;
+
+               this_cpu_write(app_config_applied, 0);
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+EXPORT_SYMBOL(clear_app_setting_bit);
+
+static int __init init_app_api(void)
+{
+       spin_lock_init(&spinlock);
+       return 0;
+}
+early_initcall(init_app_api);
diff --git a/arch/arm64/kernel/app_setting.c b/arch/arm64/kernel/app_setting.c
new file mode 100644 (file)
index 0000000..6b4eb28
--- /dev/null
@@ -0,0 +1,120 @@
+/* Copyright (c) 2016, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+
+#include <asm/app_api.h>
+
+#define MAX_LEN                100
+
+static char *lib_names[MAX_ENTRIES];
+static unsigned int count;
+static struct mutex mutex;
+
+static char lib_str[MAX_LEN] = "";
+static struct kparam_string kps = {
+       .string                 = lib_str,
+       .maxlen                 = MAX_LEN,
+};
+static int set_name(const char *str, struct kernel_param *kp);
+module_param_call(lib_name, set_name, param_get_string, &kps, S_IWUSR);
+
+bool use_app_setting = true;
+module_param(use_app_setting, bool, 0644);
+MODULE_PARM_DESC(use_app_setting, "control use of app specific settings");
+
+static int set_name(const char *str, struct kernel_param *kp)
+{
+       int len = strlen(str);
+       char *name;
+
+       if (len >= MAX_LEN) {
+               pr_err("app_setting: name string too long\n");
+               return -ENOSPC;
+       }
+
+       /*
+        * echo adds '\n' which we need to chop off later
+        */
+       name = kzalloc(len + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       strlcpy(name, str, len + 1);
+
+       if (name[len - 1] == '\n')
+               name[len - 1] = '\0';
+
+       mutex_lock(&mutex);
+       if (count < MAX_ENTRIES) {
+               lib_names[count] = name;
+               /*
+                * mb to ensure that the new lib_names entry is present
+                * before updating the view presented by get_lib_names
+                */
+               mb();
+               count++;
+       } else {
+               pr_err("app_setting: set name failed. Max entries reached\n");
+               kfree(name);
+               mutex_unlock(&mutex);
+               return -EPERM;
+       }
+       mutex_unlock(&mutex);
+
+       return 0;
+}
+
+void switch_app_setting_bit(struct task_struct *prev, struct task_struct *next)
+{
+       if (prev->mm && unlikely(prev->mm->app_setting))
+               clear_app_setting_bit(APP_SETTING_BIT);
+
+       if (next->mm && unlikely(next->mm->app_setting))
+               set_app_setting_bit(APP_SETTING_BIT);
+}
+EXPORT_SYMBOL(switch_app_setting_bit);
+
+void apply_app_setting_bit(struct file *file)
+{
+       bool found = false;
+       int i;
+
+       if (file && file->f_path.dentry) {
+               const char *name = file->f_path.dentry->d_name.name;
+
+               for (i = 0; i < count; i++) {
+                       if (unlikely(!strcmp(name, lib_names[i]))) {
+                               found = true;
+                               break;
+                       }
+               }
+               if (found) {
+                       preempt_disable();
+                       set_app_setting_bit(APP_SETTING_BIT);
+                       /* This will take care of child processes as well */
+                       current->mm->app_setting = 1;
+                       preempt_enable();
+               }
+       }
+}
+EXPORT_SYMBOL(apply_app_setting_bit);
+
+static int __init app_setting_init(void)
+{
+       mutex_init(&mutex);
+       return 0;
+}
+module_init(app_setting_init);
index d90efa4..1ffe154 100644 (file)
@@ -78,22 +78,6 @@ ENTRY(fpsimd_disable_trap)
        msr cpacr_el1, x0
        ret
 ENDPROC(fpsimd_disable_trap)
-ENTRY(fpsimd_settings_enable)
-       mrs x0, s3_1_c15_c15_0
-       orr x0, x0, #(1 << 31)
-       isb
-       msr s3_1_c15_c15_0, x0
-       isb
-       ret
-ENDPROC(fpsimd_settings_enable)
-ENTRY(fpsimd_settings_disable)
-       mrs x0, s3_1_c15_c15_0
-       bic x0, x0, #(1 << 31)
-       isb
-       msr s3_1_c15_c15_0, x0
-       isb
-       ret
-ENDPROC(fpsimd_settings_disable)
 #endif
 
 #endif
index 74bc79e..2ed553f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <asm/fpsimd.h>
 #include <asm/cputype.h>
+#include <asm/app_api.h>
 
 #define FPEXC_IOF      (1 << 0)
 #define FPEXC_DZF      (1 << 1)
@@ -36,6 +37,8 @@
 #define FPEXC_IXF      (1 << 4)
 #define FPEXC_IDF      (1 << 7)
 
+#define FP_SIMD_BIT    31
+
 /*
  * In order to reduce the number of times the FPSIMD state is needlessly saved
  * and restored, we need to keep track of two things:
@@ -94,6 +97,16 @@ static DEFINE_PER_CPU(int, fpsimd_stg_enable);
 static int fpsimd_settings = 0x1; /* default = 0x1 */
 module_param(fpsimd_settings, int, 0644);
 
+void fpsimd_settings_enable(void)
+{
+       set_app_setting_bit(FP_SIMD_BIT);
+}
+
+void fpsimd_settings_disable(void)
+{
+       clear_app_setting_bit(FP_SIMD_BIT);
+}
+
 /*
  * Trapped FP/ASIMD access.
  */
index ea00090..9f9e607 100644 (file)
@@ -522,6 +522,10 @@ struct mm_struct {
 #ifdef CONFIG_HUGETLB_PAGE
        atomic_long_t hugetlb_usage;
 #endif
+#ifdef CONFIG_MSM_APP_SETTINGS
+       int app_setting;
+#endif
+
 };
 
 static inline void mm_init_cpumask(struct mm_struct *mm)
index 0a7db8a..e145b56 100644 (file)
@@ -85,6 +85,9 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #endif
+#ifdef CONFIG_MSM_APP_SETTINGS
+#include <asm/app_api.h>
+#endif
 
 #include "sched.h"
 #include "../workqueue_internal.h"
@@ -5874,6 +5877,11 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
+
+#ifdef CONFIG_MSM_APP_SETTINGS
+       if (use_app_setting)
+               switch_app_setting_bit(prev, next);
+#endif
 }
 
 /**
index 6c561ac..8b0a0ed 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
 #include <asm/tlb.h>
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_MSM_APP_SETTINGS
+#include <asm/app_api.h>
+#endif
+
 #include "internal.h"
 
 #ifndef arch_mmap_check
@@ -1297,6 +1301,11 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
        if (!len)
                return -EINVAL;
 
+#ifdef CONFIG_MSM_APP_SETTINGS
+       if (use_app_setting)
+               apply_app_setting_bit(file);
+#endif
+
        /*
         * Does the application expect PROT_READ to imply PROT_EXEC?
         *