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;
}
} 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)) {
_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;
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",
_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",
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.
*
* - 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;