arm64: Add support for app specific settings

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>
This commit is contained in:
Sarangdhar Joshi 2016-02-11 16:39:46 -08:00 committed by Kyle Yan
parent e3ab187d0b
commit 7ab05c20ad
11 changed files with 294 additions and 20 deletions

View 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

View file

@ -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

View 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

View 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)

View file

@ -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);

View file

@ -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);

View 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

View 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.
*/

View 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)

View 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
}
/**

View file

@ -48,6 +48,10 @@
#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?
*