pass: Add new fault_around_bytes feature for memory h/w device 47/146347/4
authorChanwoo Choi <cw00.choi@samsung.com>
Mon, 28 Aug 2017 03:02:59 +0000 (12:02 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Thu, 7 Sep 2017 04:57:19 +0000 (13:57 +0900)
This patch adds the new 'fault_around_bytes'[1] feature
of the memory h/w device. When the page fault happens,
'fault_around_bytes' is used.

The 'fault_around_bytes' indicates the number of bytes to be mapped
around the fault. If the value is low, it is able to increase
the amount of empty memory on normal case. On the other hand,
if the value is high, it is able to improve the performance
by mapping the huge pages such as the app launching.

It can be adjusted on the fly according to the user requirements.

[1] https://lkml.org/lkml/2016/4/18/612

Change-Id: Ib33e071ac6f46dd746c00dd473bd48dfe48e1aea
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
src/pass/pass-hal.c
src/pass/pass-hal.h
src/pass/pass-parser.c
src/pass/pass-rescon.c
src/pass/pass.h

index 6d1976d9a00797d1386d54a55477ca8f72985ba7..ffcfbdb966105e0bccd1b6666e670a64f1f6f3b4 100644 (file)
@@ -521,6 +521,59 @@ int pass_get_tmu_policy(struct pass_resource *res, char *policy)
        return tmu->get_policy(res_thermal_name, policy);
 }
 
+int pass_set_fault_around_bytes(struct pass_resource *res,
+                               int fault_around_bytes)
+{
+       struct pass_resource_memory *memory;
+       char *res_name;
+       int res_type;
+
+       if (!res)
+               return -EINVAL;
+
+       res_name = res->cdata.res_name;
+       res_type = res->cdata.res_type;
+
+       switch (res_type) {
+       case PASS_RESOURCE_MEMORY_ID:
+               memory = res->hal.memory;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!memory->set_fault_around_bytes)
+               return -EINVAL;
+
+       return memory->set_fault_around_bytes(res_name, fault_around_bytes);
+}
+
+int pass_get_fault_around_bytes(struct pass_resource *res)
+{
+       struct pass_resource_memory *memory;
+       char *res_name;
+       int res_type;
+
+       if (!res)
+               return -EINVAL;
+
+       res_name = res->cdata.res_name;
+       res_type = res->cdata.res_type;
+
+       switch (res_type) {
+       case PASS_RESOURCE_MEMORY_ID:
+               memory = res->hal.memory;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!memory->get_fault_around_bytes)
+               return -EINVAL;
+
+       return memory->get_fault_around_bytes(res_name);
+}
+
 int pass_set_pmqos_data(struct pass_resource *res, void *data)
 {
        struct pass_resource_nonstandard *nonstandard = NULL;
@@ -602,6 +655,15 @@ static int pass_save_hotplug_initdata(struct pass_resource *res)
        return 0;
 }
 
+static int pass_save_memory_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+
+       initdata->memory.fault_around_bytes = pass_get_fault_around_bytes(res);
+
+       return 0;
+}
+
 static int pass_restore_dvfs_initdata(struct pass_resource *res)
 {
        struct pass_resource_initdata *initdata = &res->initdata;
@@ -673,6 +735,21 @@ static int pass_restore_hotplug_initdata(struct pass_resource *res)
        return 0;
 }
 
+static int pass_restore_memory_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+       int fault_around_bytes = initdata->memory.fault_around_bytes;
+       int ret;
+
+       if (fault_around_bytes >= 0) {
+               ret = pass_set_fault_around_bytes(res, fault_around_bytes);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 int pass_save_initdata(struct pass_resource *res)
 {
        struct pass_conf_data *cdata;
@@ -706,6 +783,12 @@ int pass_save_initdata(struct pass_resource *res)
                }
                break;
        case PASS_RESOURCE_MEMORY_ID:
+               ret = pass_save_memory_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to save memory initdata for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
                break;
        case PASS_RESOURCE_NONSTANDARD_ID:
                break;
@@ -750,6 +833,12 @@ int pass_restore_initdata(struct pass_resource *res)
                }
                break;
        case PASS_RESOURCE_MEMORY_ID:
+               ret = pass_restore_memory_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to restore memory data for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
                break;
        case PASS_RESOURCE_NONSTANDARD_ID:
                break;
index 3b45c84e17480c238cd6272a9a5c554869e79cb7..c5c0da0f4266d4d60f6fbf5dfa61607544637c25 100644 (file)
@@ -81,6 +81,14 @@ int pass_set_online_max_num(struct pass_resource *res, int num);
  */
 int pass_get_cpu_stats(struct pass_policy *policy);
 
+/***
+ * Functions for Memory h/w resource
+ */
+/* Get and set the /sys/kernel/debug/fault_around_bytes */
+int pass_get_fault_around_bytes(struct pass_resource *res);
+int pass_set_fault_around_bytes(struct pass_resource *res,
+                               int fault_around_bytes);
+
 /***
  * Functions for Nonstandard H/W resources
  */
index 2fcbd47180924df69234956f6412392e21578f2f..6e8a0722948d6242e04abfb4087b12e379a13251 100644 (file)
@@ -126,6 +126,12 @@ static int pass_parse_level(struct parse_result *result,
        if (!result->section || !result->name || !result->value)
                return 0;
 
+       /*
+        * Properties for the following h/w resources:
+        * - PASS_RESOURCE_CPU_ID
+        * - PASS_RESOURCE_BUS_ID
+        * - PASS_RESOURCE_GPU_ID
+        */
        if (MATCH(result->name, "limit_max_freq"))
                policy->pass_table[level].limit_max_freq = atoi(result->value);
        else if (MATCH(result->name, "limit_min_freq"))
@@ -133,6 +139,10 @@ static int pass_parse_level(struct parse_result *result,
        else if (MATCH(result->name, "limit_min_cpu"))
                policy->pass_table[level].limit_min_cpu = atoi(result->value);
 
+       /*
+        * Properties for the following h/w resources:
+        * - PASS_RESOURCE_CPU_ID
+        */
        else if (MATCH(result->name, "num_down_cond"))
                policy->pass_table[level].num_down_cond = atoi(result->value);
        else if (MATCH(result->name, "num_down_cond_freq"))
@@ -177,6 +187,13 @@ static int pass_parse_level(struct parse_result *result,
                policy->pass_table[level].gov_timeout = gov_timeout;
        }
 
+       /*
+        * Properties for the following h/w resources:
+        * - PASS_RESOURCE_MEMORY_ID
+        */
+       else if (MATCH(result->name, "fault_around_bytes"))
+               policy->pass_table[level].fault_around_bytes = atoi(result->value);
+
        return 0;
 }
 
@@ -635,6 +652,8 @@ static int pass_resource_config(struct parse_result *result, void *user_data)
                                cur->initdata.hotplug.online_state = NULL;
                                cur->initdata.hotplug.online_min_num = -1;
                                cur->initdata.hotplug.online_max_num = -1;
+
+                               cur->initdata.memory.fault_around_bytes = -1;
                        }
                } else {
                        _E("cannot parse the number of resource\n");
index f025d759200d6c9551e39e89886490a451f2d044..f1938d2d608ede3eff9a8cd07520d5c6b0b34a81 100644 (file)
@@ -79,6 +79,7 @@ int pass_rescon_set_level(struct pass_policy *policy, int new_level)
        int limit_max_freq;
        int limit_min_freq;
        int limit_min_cpu;
+       int fault_around_bytes;
        int ret;
 
        if (new_level > policy->max_level)
@@ -90,12 +91,10 @@ int pass_rescon_set_level(struct pass_policy *policy, int new_level)
        if (new_level == curr_level)
                return 0;
 
-       /*
-        * Get the max/min frequency and the number of max online
-        * according to PASS level.
-        */
+       /* Get the detailed resource value according to PASS level */
        limit_max_freq = table[new_level].limit_max_freq;
        limit_min_freq = table[new_level].limit_min_freq;
+       fault_around_bytes = table[new_level].fault_around_bytes;
 
        policy->prev_level = curr_level;
        policy->curr_level = new_level;
@@ -130,6 +129,16 @@ int pass_rescon_set_level(struct pass_policy *policy, int new_level)
                }
        }
 
+       /* Set fault_around_bytes for the memory h/w */
+       if (fault_around_bytes) {
+               ret = pass_set_fault_around_bytes(res, fault_around_bytes);
+               if (ret < 0) {
+                       _E("cannot set the fault_around_bytes of %s",
+                                               cdata->res_name);
+                       return -EINVAL;
+               }
+       }
+
        /*
        _I("[PASS %s] Level %4s '%d->%d' : 'max %d | min %d'Hz/'%d'Core\n",
                res->cdata.res_name,
index f7ae3756452df9e5cb60566c6d9401acc8330091..060e94b9f1124cc8fcc7256303ebb7cd6e6c4ce1 100644 (file)
@@ -166,6 +166,9 @@ struct pass_level_condition {
  *     - PASS_RESOURCE_CPU_ID
  *     - PASS_RESOURCE_BUS_ID
  *     - PASS_RESOURCE_GPU_ID
+ * @fault_around_bytes: the number of bytes to be mapped around the fault
+ *     this property is used for the following resoures:
+ *     - PASS_RESOURCE_MEMORY_ID
  *
  * @gov_timeout: the period of timer for each PASS's level
  *     this property is used for the following resoures:
@@ -186,6 +189,8 @@ struct pass_table {
        int limit_min_freq;
        int limit_min_cpu;
 
+       int fault_around_bytes;
+
        /* Properties for the timer */
        double gov_timeout;
 
@@ -337,6 +342,8 @@ struct pass_conf_data {
  * - online_min_num: the initial minimum number of online resources
  * - online_max_num: the initial maximum number of online resources
  * @tmu: the initial value of tmu configuration
+ * @memory: the initial value of memory configuration
+ * - fault_around_bytes: the number of bytes to be mapped around the fault
  */
 struct pass_resource_initdata {
        struct {
@@ -355,6 +362,10 @@ struct pass_resource_initdata {
        struct {
                /* NOTE: tmu has no writable data yet. */
        } tmu;
+
+       struct {
+               int fault_around_bytes;
+       } memory;
 };
 
 /*