resource_34xx.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,309 行 · 第 1/3 页
C
1,309 行
} /* Increment the number of users for this domain. */ resp->no_of_users++; return ret;ret: up_srfmutex(&users_list_mutex); return ret;}/* Deletes the request from the list of request for the given resource.*//* Recalulates the target level to be set for the resource and updates it *//* if not same as the current level.Also calls notification functions for *//* registered users to notify the target level change */int resource_release(struct res_handle *res){ struct shared_resource *resp; struct users_list *user, *cur_user = NULL; unsigned short target_level; int ret = 0; if (res == ERR_PTR(-ENOENT)) { DPRINTK("Invalid resource handle passed to reource_release\n"); return ret; } resp = res->res; DPRINTK("resource_request: Clock-name %s\n", res->usr_name); down_srfmutex(&users_list_mutex); if (res->usr_index != -1) cur_user = &usr_list[res->usr_index]; else goto ret; ret = resp->validate(resp, cur_user->level, DEFAULT_LEVEL); if (ret) { DPRINTK("Validation failed\n"); ret = -EINVAL; goto ret; } /* Delete the resource */ DPRINTK("Deleting resource for %s\n", resp->name); list_del(&cur_user->node); usr_flag[cur_user->index] = UNUSED; usr_list[cur_user->index].usr_name = NULL; usr_list[cur_user->index].level = DEFAULT_LEVEL; usr_list[cur_user->index].index = cur_user->index; res->usr_index = -1; /* Regenerate the target_level for the resource */ target_level = DEFAULT_LEVEL; list_for_each_entry(user, &(resp->users_list), node) { if (user->level > target_level) target_level = user->level; } DPRINTK("New Target level is %d\n", target_level); up_srfmutex(&users_list_mutex); if ((target_level == DEFAULT_LEVEL) && (resp->prcm_id == PRCM_VDD1_CONSTRAINT)) target_level = CO_VDD1_OPP1; else if ((target_level == DEFAULT_LEVEL) && (resp->prcm_id == PRCM_VDD2_CONSTRAINT)) target_level = CO_VDD2_OPP2; else if ((target_level == DEFAULT_LEVEL) && (resp->prcm_id == PRCM_ARMFREQ_CONSTRAINT)) target_level = min_arm_freq; else if ((target_level == DEFAULT_LEVEL) && (resp->prcm_id == PRCM_DSPFREQ_CONSTRAINT)) target_level = min_dsp_freq; if (target_level != resp->curr_level) { DPRINTK("Changing Level for resource %s to %d\n", resp->name, target_level); if ((resp->res_type != RES_FREQ_CO) &&\ (target_level < MAX_LEVEL)) atomic_notifier_call_chain( &resp->pre_notifier_list[target_level], target_level, NULL); down_srfmutex(&resp->res_action_sem); ret = resp->action(resp, resp->curr_level, target_level); up_srfmutex(&resp->res_action_sem); if (ret) printk(KERN_ERR "FATAL ERROR: Unable to Change " "level for resource %s to %d\n", resp->name, target_level); else /* If successful, change the resource curr_level */ resp->curr_level = target_level; if ((resp->res_type != RES_FREQ_CO) && (target_level < MAX_LEVEL)) atomic_notifier_call_chain( &resp->post_notifier_list[target_level], target_level, NULL); } /* Decrement the number of users for this domain. */ resp->no_of_users--; return ret;ret: up_srfmutex(&users_list_mutex); return ret;}/* Frees the res_handle structure from the pool */void resource_put(struct res_handle *res){ if (res == ERR_PTR(-ENOENT)) { DPRINTK("Invalid resource handle passed to resource_put\n"); return; } if (res->usr_index != -1) { printk(KERN_ERR "resource_put called before " "resource_release\n"); return; } down_srfmutex(&res_handle_mutex); DPRINTK("resource_put for %s, index = %d\n", res->res->name, res->res_index); handle_flag[res->res_index] = UNUSED; handle_list[res->res_index].res = NULL; handle_list[res->res_index].usr_name = NULL; handle_list[res->res_index].res_index = res->res_index; handle_list[res->res_index].usr_index = -1; up_srfmutex(&res_handle_mutex);}/* Registers a notification function from a resource user for a specific *//* target level. The function is called before a level change for the *//* resource to the target level. */void resource_register_pre_notification(struct res_handle *res, struct notifier_block *nb, unsigned short target_level){ struct shared_resource *resp; int ind; resp = res->res; DPRINTK("Notification registered for %s, level %d\n", resp->name, target_level); if (target_level == resp->max_levels) { for (ind = DEFAULT_LEVEL; ind < resp->max_levels; ind++) { res->nb_internal_pre[ind] = (struct notifier_block *)kmalloc(sizeof(struct notifier_block), GFP_KERNEL); *(res->nb_internal_pre[ind]) = *nb; atomic_notifier_chain_register( &resp->pre_notifier_list[ind], res->nb_internal_pre[ind]); } } else { res->nb_internal_pre[target_level] = (struct notifier_block *) kmalloc(sizeof(struct notifier_block), GFP_KERNEL); *(res->nb_internal_pre[target_level]) = *nb; atomic_notifier_chain_register( &resp->pre_notifier_list[target_level], res->nb_internal_pre[target_level]); }}/* Registers a notification function from a resource user for a specific *//* target level. The function is called before a level change for the *//* resource to the target level. */void resource_register_post_notification(struct res_handle *res, struct notifier_block *nb, unsigned short target_level){ struct shared_resource *resp; int ind; resp = res->res; DPRINTK("Notification registered for %s, level %d\n", resp->name, target_level); if (target_level == resp->max_levels) { for (ind = DEFAULT_LEVEL; ind < resp->max_levels; ind++) { res->nb_internal_post[ind] = (struct notifier_block *) kmalloc(sizeof(struct notifier_block), GFP_KERNEL); *(res->nb_internal_post[ind]) = *nb; atomic_notifier_chain_register( &resp->post_notifier_list[ind], res->nb_internal_post[ind]); } } else { res->nb_internal_post[target_level] = (struct notifier_block *) kmalloc(sizeof(struct notifier_block), GFP_KERNEL); *(res->nb_internal_post[target_level]) = *nb; atomic_notifier_chain_register( &resp->post_notifier_list[target_level], res->nb_internal_post[target_level]); }}/* Unregisters the notification function from a resource user for a specific *//* target level. */void resource_unregister_pre_notification(struct res_handle *res, struct notifier_block *nb, unsigned short target_level){ struct shared_resource *resp; int ind, ret; resp = res->res; DPRINTK("Notification unregistered for %s, level %d\n", resp->name, target_level); if (target_level == resp->max_levels) { for (ind = DEFAULT_LEVEL; ind < resp->max_levels; ind++) { ret = atomic_notifier_chain_unregister( &resp->pre_notifier_list[ind], res->nb_internal_pre[ind]); if (ret != -ENOENT) kfree(res->nb_internal_pre[ind]); } } else { ret = atomic_notifier_chain_unregister( &resp->pre_notifier_list[target_level], res->nb_internal_pre[target_level]); if (ret != -ENOENT) kfree(res->nb_internal_pre[target_level]); }}/* Unregisters the notification function from a resource user for a specific *//* target level. */void resource_unregister_post_notification(struct res_handle *res, struct notifier_block *nb, unsigned short target_level){ struct shared_resource *resp; int ind, ret; resp = res->res; DPRINTK("Notification unregistered for %s, level %d\n", resp->name, target_level); if (target_level == resp->max_levels) { for (ind = DEFAULT_LEVEL; ind < resp->max_levels; ind++) { ret = atomic_notifier_chain_unregister( &resp->post_notifier_list[ind], res->nb_internal_post[ind]); if (ret != -ENOENT) kfree(res->nb_internal_post[ind]); } } else { ret = atomic_notifier_chain_unregister( &resp->post_notifier_list[target_level], res->nb_internal_post[target_level]); if (ret != -ENOENT) kfree(res->nb_internal_post[target_level]); }}/* Returns the current level for a resource */int resource_get_level(struct res_handle *res){ struct shared_resource *resp; int ret; resp = res->res; down_srfmutex(&res_handle_mutex); ret = resp->curr_level; up_srfmutex(&res_handle_mutex); return ret;}/* Activation function to change target level for a Power Domain resource *//* Transtitions from RET to OFF and OFF to RET are not allowed */int activate_power_res(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ int ret = 0; unsigned long prcm_id = resp->prcm_id; /* Common code for transitioning to RET/OFF. */ switch (target_level) { case POWER_DOMAIN_RET: case POWER_DOMAIN_OFF: if (current_level != POWER_DOMAIN_ON) { ret = prcm_set_power_domain_state(prcm_id, POWER_DOMAIN_ON, PRCM_FORCE); if (ret != PRCM_PASS) return ret; } break; } switch (target_level) { case POWER_DOMAIN_ON: ret = prcm_set_power_domain_state(prcm_id, POWER_DOMAIN_ON, PRCM_FORCE); break; case POWER_DOMAIN_RET: case POWER_DOMAIN_OFF: ret = prcm_set_power_domain_state(prcm_id, POWER_DOMAIN_RET, PRCM_FORCE); break; default: ret = PRCM_FAIL; } return ret;}/* Activation function to change target level for a Logical resource */int activate_logical_res(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ unsigned long prcm_id = resp->prcm_id; switch (prcm_id) { case DOM_CORE1: core_active = (target_level)?LOGICAL_USED:LOGICAL_UNUSED; break; default: return -1; } return 0;}/* Function to change target level for Memory or Logic resource */int activate_memory_logic(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ unsigned long domain_id; unsigned long prcm_id = resp->prcm_id; domain_id = DOMAIN_ID(prcm_id); switch (prcm_id) { case PRCM_CORE_MEM1ON: prcm_set_memory_resource_on_state(target_level); break; case PRCM_CORE_MEM2ON: prcm_set_memory_resource_on_state(target_level); break; case PRCM_CORE_MEM1RET: break; case PRCM_CORE_MEM2RET: break; case PRCM_CORE_LOGICRET: break; default : DPRINTK("Unsupported resourse\n"); return -1; } return 0;}/* Functio to validate the memory or logic resource transition */int validate_memory_logic(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ if (target_level >= resp->max_levels) return -1; return 0;}int activate_autoidle_resource(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ unsigned long prcm_id = resp->prcm_id; int ret; ret = prcm_dpll_clock_auto_control(prcm_id, target_level); if (ret == PRCM_FAIL) { DPRINTK("Invalid DPLL Autoidle resource state\n"); return -1; } return 0;}int validate_autoidle_resource(struct shared_resource *resp, unsigned short current_level, unsigned short target_level){ int invalidlevelmin = 2, invalidlevelmax = 4; if (target_level >= resp->max_levels) { printk(KERN_ERR"Invalid Target Level\n"); return -1; } if (resp->name == "core_autoidle_res") if (target_level >= invalidlevelmin && target_level <= invalidlevelmax) { printk(KERN_ERR"Invalid Target Level\n"); return -1; } return 0;}int activate_constraint(struct shared_resource *resp, unsigned short current_value, unsigned short target_value){ int ind; unsigned long type = resp->prcm_id; DPRINTK("CUR_VAL = %d, TAR_VAL = %d\n", current_value, target_value); if (type == RES_LATENCY_CO) { switch (target_value) { case CO_LATENCY_WFI: /* Allows only wfi + tick suppression. State C1*/ set_acceptable_latency("omap_lt_co", 99); break; case CO_LATENCY_MPURET_COREON: /* Allows upto MPU RET. State C2*/ set_acceptable_latency("omap_lt_co", 3299); break; case CO_LATENCY_MPUOFF_COREON: /* Allows upto MPU OFF. State C3*/ set_acceptable_latency("omap_lt_co", 4999); break; case CO_LATENCY_MPUOFF_CORERET: /* Allows upto CORE RET. State C4*/ set_acceptable_latency("omap_lt_co", 39999); break; case CO_UNUSED: /* Removing the constraints */ remove_acceptable_latency("omap_lt_co"); break; default: set_acceptable_latency("omap_lt_co", target_value); break; } } else if ((type == PRCM_ARMFREQ_CONSTRAINT)) { for (ind = 0; ind < max_vdd1_opp; ind++) { if (vdd1_arm_dsp_freq[ind][0] >= target_value) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?