pass: Restore resource state after PASS service is stopped 93/138593/12
authorDongwoo Lee <dwoo08.lee@samsung.com>
Tue, 11 Jul 2017 08:00:44 +0000 (17:00 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Thu, 20 Jul 2017 00:19:44 +0000 (09:19 +0900)
The resource state can be changed during PASS operation, but it
should be restored to default state after PASS is over. To do this,
PASS saves initdata of each resource during initalization process
and restores it before putting resources.

Change-Id: If9f3d712cd3288d508187295c5b3def88043c509
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Wook Song <wook16.song@samsung.com>
src/pass/pass-gov.c
src/pass/pass-hal.c
src/pass/pass-hal.h
src/pass/pass-parser.c
src/pass/pass.c
src/pass/pass.h

index c02e959bf30c32b402e123c740ef8fb5f59056ef..b4d0de58ba29298885dbc9b571684cf86cae3aab 100644 (file)
@@ -480,9 +480,6 @@ static void __pass_governor_stop(struct pass_policy *policy)
                return;
        }
 
-       /* Restore the frequency and the number of online resources */
-       pass_governor_change_level(policy, policy->num_levels - 1);
-
        pass_hotplug_stop(policy);
 
        if (policy->gov_timer_id) {
index 23090f5c31643587ebaed6998c64086fb768497a..3c0458c93828bbab10cce10cba620a7e1210f437 100644 (file)
@@ -501,6 +501,207 @@ int pass_set_pmqos_data(struct pass_resource *res, void *data)
        return nonstandard->set_pmqos_data(res_name, data);
 }
 
+static int pass_save_dvfs_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+       int ret;
+
+       ret = pass_get_curr_governor(res, initdata->dvfs.governor);
+       if (ret < 0)
+               initdata->dvfs.governor = NULL;
+
+       initdata->dvfs.min_freq = pass_get_min_freq(res);
+       initdata->dvfs.max_freq = pass_get_max_freq(res);
+       initdata->dvfs.up_threshold = pass_get_up_threshold(res);
+
+       return 0;
+}
+
+static int pass_save_hotplug_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+       struct pass_conf_data *cdata = &res->cdata;
+       int *online_state;
+       int first_cpu = cdata->cpu;
+       int num_cpus = cdata->num_cpus;
+       int i;
+       int ret;
+
+       initdata->hotplug.online_min_num = pass_get_online_min_num(res);
+       initdata->hotplug.online_max_num = pass_get_online_max_num(res);
+
+       online_state = (int *)calloc(num_cpus, sizeof(int));
+       if (!online_state)
+               return -ENOMEM;
+
+       for (i = 0; i < num_cpus; i++) {
+               ret = pass_get_online_state(res, first_cpu + i);
+               if (ret < 0) {
+                       free(online_state);
+                       return 0;
+               }
+               online_state[i] = ret;
+       }
+       initdata->hotplug.online_state = online_state;
+
+       return 0;
+}
+
+static int pass_restore_dvfs_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+       int ret;
+
+       if (initdata->dvfs.governor) {
+               ret = pass_set_curr_governor(res, initdata->dvfs.governor);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (initdata->dvfs.min_freq >= 0) {
+               ret = pass_set_min_freq(res, initdata->dvfs.min_freq);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (initdata->dvfs.max_freq >= 0) {
+               ret = pass_set_max_freq(res, initdata->dvfs.max_freq);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (initdata->dvfs.up_threshold >= 0) {
+               ret = pass_set_up_threshold(res, initdata->dvfs.up_threshold);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int pass_restore_hotplug_initdata(struct pass_resource *res)
+{
+       struct pass_resource_initdata *initdata = &res->initdata;
+       struct pass_conf_data *cdata = &res->cdata;
+       int *online_state = initdata->hotplug.online_state;
+       int first_cpu = cdata->cpu;
+       int num_cpus = cdata->num_cpus;
+       int online_min_num = initdata->hotplug.online_min_num;
+       int online_max_num = initdata->hotplug.online_max_num;
+       int i;
+       int ret;
+
+       if (online_state) {
+               for (i = 0; i < num_cpus; i++) {
+                       ret = pass_set_online_state(res, first_cpu + i,
+                                                       online_state[i]);
+                       if (ret < 0) {
+                               free(online_state);
+                               return ret;
+                       }
+               }
+               free(online_state);
+       }
+
+       if (online_min_num >= 0) {
+               ret = pass_set_online_min_num(res, online_min_num);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (online_max_num >= 0) {
+               ret = pass_set_online_max_num(res, online_max_num);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int pass_save_initdata(struct pass_resource *res)
+{
+       struct pass_conf_data *cdata;
+       char *res_name;
+       int res_type;
+       int ret;
+
+       if (!res)
+               return -EINVAL;
+
+       cdata = &res->cdata;
+       res_name = cdata->res_name;
+       res_type = cdata->res_type;
+
+       switch (res_type) {
+       case PASS_RESOURCE_CPU_ID:
+               ret = pass_save_hotplug_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to save hp initdata for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
+               /* fall through */
+       case PASS_RESOURCE_BUS_ID:
+       case PASS_RESOURCE_GPU_ID:
+               ret = pass_save_dvfs_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to save dvfs initdata for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
+               break;
+       case PASS_RESOURCE_NONSTANDARD_ID:
+               break;
+       default:
+               _E("Unsupported resource type (type: %d)\n", res_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int pass_restore_initdata(struct pass_resource *res)
+{
+       struct pass_conf_data *cdata;
+       char *res_name;
+       int res_type;
+       int ret;
+
+       if (!res)
+               return -EINVAL;
+
+       cdata = &res->cdata;
+       res_name = cdata->res_name;
+       res_type = cdata->res_type;
+
+       switch (res_type) {
+       case PASS_RESOURCE_CPU_ID:
+               ret = pass_restore_hotplug_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to restore hp initdata for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
+               /* fall through */
+       case PASS_RESOURCE_BUS_ID:
+       case PASS_RESOURCE_GPU_ID:
+               ret = pass_restore_dvfs_initdata(res);
+               if (ret < 0) {
+                       _E("Failed to restore dvfs initdata for '%s' resource",
+                                                               res_name);
+                       return ret;
+               }
+               break;
+       case PASS_RESOURCE_NONSTANDARD_ID:
+               break;
+       default:
+               _E("Unsupported resource type (type: %d)\n", res_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int pass_get_resource(struct pass_resource *res)
 {
        struct pass_conf_data *cdata;
index 53667384c610f5d1e2fa198331e2aedc948db4bf..80a75a8217983843025254e94bda8bea3be59bda 100644 (file)
 int pass_get_resource(struct pass_resource *res);
 int pass_put_resource(struct pass_resource *res);
 
+/* Save and restore the initial data of the h/w resource. */
+int pass_save_initdata(struct pass_resource *pass_res);
+int pass_restore_initdata(struct pass_resource *pass_res);
+
 /***
  * Functions for CPU/BUS/GPU H/W resources
  */
index 0be37d967db44714a141302864795c9907d7382b..9e6d3be84c1aa87de892fdfba26b76ff2b2b6400 100644 (file)
@@ -603,6 +603,7 @@ static int pass_resource_config(struct parse_result *result, void *user_data)
                        }
                } else if (MATCH(result->name, "pass_num_resources")) {
                        unsigned int num_resources = atoi(result->value);
+                       int i;
 
                        if ((num_resources > MAX_NUM) ||
                                        (num_resources < 1)) {
@@ -617,6 +618,22 @@ static int pass_resource_config(struct parse_result *result, void *user_data)
                                _E("cannot allocate the memory for resource");
                                return -ENOMEM;
                        }
+
+                       /* Set init. value of initdata for each h/w resource */
+                       for (i = 0; i < num_resources ; i++) {
+                               struct pass_resource *cur;
+
+                               cur = &pass->res[i];
+
+                               cur->initdata.dvfs.governor = NULL;
+                               cur->initdata.dvfs.min_freq = -1;
+                               cur->initdata.dvfs.max_freq = -1;
+                               cur->initdata.dvfs.up_threshold = -1;
+
+                               cur->initdata.hotplug.online_state = NULL;
+                               cur->initdata.hotplug.online_min_num = -1;
+                               cur->initdata.hotplug.online_max_num = -1;
+                       }
                } else {
                        _E("cannot parse the number of resource\n");
                        return -ENOENT;
index eb23b451d34818c691f3457e0a37d0983089ee8d..408120f6b30653a2ef405da51cee960297a470b8 100644 (file)
@@ -247,11 +247,28 @@ static int pass_init_done(void *data, void *user_data)
                        continue;
                }
 
+               ret = pass_save_initdata(res);
+               if (ret < 0) {
+                       _E("Cannot save initdata of '%s' resource (%d)\n",
+                                       cdata->res_name, ret);
+
+                       ret = pass_put_resource(res);
+                       if (ret < 0)
+                               _E("Cannot put the pass '%s' resource (%d)\n",
+                                       cdata->res_name, ret);
+                       continue;
+               }
+
                ret = pass_init_resource(res);
                if (ret < 0) {
                        _E("Cannot initialize the pass '%s' resource (%d)\n",
                                        cdata->res_name, ret);
 
+                       ret = pass_restore_initdata(res);
+                       if (ret < 0)
+                               _E("Cannot restore the initdata of '%s' "
+                                  "resource (%d)\n", cdata->res_name, ret);
+
                        ret = pass_put_resource(res);
                        if (ret < 0)
                                _E("Cannot put the pass '%s' resource (%d)\n",
@@ -275,6 +292,11 @@ static int pass_exit_done(void)
                        _E("Cannot exit the pass '%s' resource (%d)\n",
                                        cdata->res_name, ret);
 
+               ret = pass_restore_initdata(res);
+               if (ret < 0)
+                       _E("Cannot restore initdata of '%s' resource (%d)\n",
+                                       cdata->res_name, ret);
+
                ret = pass_put_resource(res);
                if (ret < 0) {
                        _E("Cannot put the pass '%s' resource (%d)\n",
index 956eada4df7dbd517215a5804836244c8306c4bd..85d177112fbcc5a920e6836e757788d97885c53d 100644 (file)
@@ -290,6 +290,39 @@ struct pass_conf_data {
        unsigned int cpu;
 };
 
+/*
+ * struct pass_resource_initdata - Represent initial data of each h/w resource.
+ *
+ * @dvfs: the initial value of dvfs configuration
+ * - governor: the initial type of current governor
+ * - min_freq: the initial value of minimum frequency
+ * - max_freq: the initial value of maximum frequency
+ * - up_threshold: the initial threshold of boosting frequency
+ * @hotplug: the initial value of hotplug configuration
+ * - online_state: the array of resource's online state
+ * - 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
+ */
+struct pass_resource_initdata {
+       struct {
+               char *governor;
+               int min_freq;
+               int max_freq;
+               int up_threshold;
+       } dvfs;
+
+       struct {
+               int *online_state;
+               int online_min_num;
+               int online_max_num;
+       } hotplug;
+
+       struct {
+               /* NOTE: tmu has no writable data yet. */
+       } tmu;
+};
+
 /*
  * struct pass_resource - Represent the each h/w resource.
  *
@@ -301,10 +334,12 @@ struct pass_conf_data {
  * - If res_type of cdata is PASS_RESOURCE_NONSTANDARD_ID,
  *   hal.nonstandard will be used.
  * @policy: the policy data to handle the h/w resource
+ * @initdata: the initial data to restore when pass service is stopped
  */
 struct pass_resource {
        struct pass_conf_data cdata;
        struct pass_policy policy;
+       struct pass_resource_initdata initdata;
 
        union {
                struct pass_resource_cpu *cpu;