Loading drivers/platform/msm/ipa/ipa.c +7 −0 Original line number Diff line number Diff line Loading @@ -1604,6 +1604,13 @@ fail: return retval; } int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage, u32 bandwidth_mbps) { IPADBG("Not Implemented yet"); return 0; } static int ipa_init_flt_block(void) { int result = 0; Loading drivers/platform/msm/ipa/ipa_i.h +3 −0 Original line number Diff line number Diff line Loading @@ -907,6 +907,9 @@ int ipa_id_alloc(void *ptr); void *ipa_id_find(u32 id); void ipa_id_remove(u32 id); int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage, u32 bandwidth_mbps); int ipa_cfg_ep_status(u32 clnt_hdl, const struct ipa_ep_cfg_status *ipa_ep_cfg); Loading drivers/platform/msm/ipa/ipa_rm.c +200 −3 Original line number Diff line number Diff line Loading @@ -37,13 +37,28 @@ static const char *resource_name_to_str[IPA_RM_RESOURCE_MAX] = { __stringify(IPA_RM_RESOURCE_HSIC_CONS), }; struct ipa_rm_profile_vote_type { enum ipa_voltage_level volt[IPA_RM_RESOURCE_MAX]; enum ipa_voltage_level curr_volt; u32 bw_prods[IPA_RM_RESOURCE_PROD_MAX]; u32 bw_cons[IPA_RM_RESOURCE_CONS_MAX]; u32 curr_bw; }; struct ipa_rm_context_type { struct ipa_rm_dep_graph *dep_graph; struct workqueue_struct *ipa_rm_wq; spinlock_t ipa_rm_lock; struct ipa_rm_profile_vote_type prof_vote; }; static struct ipa_rm_context_type *ipa_rm_ctx; struct ipa_rm_notify_ipa_work_type { struct work_struct work; enum ipa_voltage_level volt; u32 bandwidth_mbps; }; /** * ipa_rm_create_resource() - create resource * @create_params: [in] parameters needed Loading @@ -67,6 +82,13 @@ int ipa_rm_create_resource(struct ipa_rm_create_params *create_params) } IPA_RM_DBG("%s\n", ipa_rm_resource_str(create_params->name)); if (create_params->floor_voltage < 0 || create_params->floor_voltage >= IPA_VOLTAGE_MAX) { IPA_RM_ERR("invalid voltage %d\n", create_params->floor_voltage); return -EINVAL; } spin_lock(&ipa_rm_ctx->ipa_rm_lock); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, create_params->name, Loading Loading @@ -353,6 +375,48 @@ bail: } EXPORT_SYMBOL(ipa_rm_deregister); /** * ipa_rm_set_perf_profile() - set performance profile * @resource_name: resource name * @profile: [in] profile information. * * Returns: 0 on success, negative on failure * * Set resource performance profile. * Updates IPA driver if performance level changed. */ int ipa_rm_set_perf_profile(enum ipa_rm_resource_name resource_name, struct ipa_rm_perf_profile *profile) { int result; struct ipa_rm_resource *resource; IPA_RM_DBG("%s\n", ipa_rm_resource_str(resource_name)); spin_lock(&ipa_rm_ctx->ipa_rm_lock); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, resource_name, &resource) != 0) { IPA_RM_ERR("resource does not exists\n"); result = -EPERM; goto bail; } result = ipa_rm_resource_set_perf_profile(resource, profile); if (result) { IPA_RM_ERR("ipa_rm_resource_set_perf_profile failed %d\n", result); goto bail; } result = 0; bail: spin_unlock(&ipa_rm_ctx->ipa_rm_lock); IPA_RM_DBG("EXIT with %d\n", result); return result; } EXPORT_SYMBOL(ipa_rm_set_perf_profile); /** * ipa_rm_notify_completion() - * consumer driver notification for Loading Loading @@ -563,6 +627,139 @@ const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name) return resource_name_to_str[resource_name]; }; static void ipa_rm_perf_profile_notify_to_ipa_work(struct work_struct *work) { struct ipa_rm_notify_ipa_work_type *notify_work = container_of(work, struct ipa_rm_notify_ipa_work_type, work); int res; IPA_RM_DBG("calling to IPA driver. voltage %d bandwidth %d\n", notify_work->volt, notify_work->bandwidth_mbps); res = ipa_set_required_perf_profile(notify_work->volt, notify_work->bandwidth_mbps); if (res) { IPA_RM_ERR("ipa_set_required_perf_profile failed %d\n", res); goto bail; } IPA_RM_DBG("IPA driver notified\n"); bail: kfree(notify_work); } static void ipa_rm_perf_profile_notify_to_ipa(enum ipa_voltage_level volt, u32 bandwidth) { struct ipa_rm_notify_ipa_work_type *work; work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) { IPA_RM_ERR("no mem\n"); return; } INIT_WORK(&work->work, ipa_rm_perf_profile_notify_to_ipa_work); work->volt = volt; work->bandwidth_mbps = bandwidth; queue_work(ipa_rm_ctx->ipa_rm_wq, &work->work); } /** * ipa_rm_perf_profile_change() - change performance profile vote for resource * @resource_name: [in] resource name * * change bandwidth and voltage vote based on resource state. */ void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name) { enum ipa_voltage_level old_volt; u32 *bw_ptr; u32 old_bw; struct ipa_rm_resource *resource; int i; u32 sum_bw_prod = 0; u32 sum_bw_cons = 0; IPA_RM_DBG("%s\n", ipa_rm_resource_str(resource_name)); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, resource_name, &resource) != 0) { IPA_RM_ERR("resource does not exists\n"); WARN_ON(1); return; } old_volt = ipa_rm_ctx->prof_vote.curr_volt; old_bw = ipa_rm_ctx->prof_vote.curr_bw; if (IPA_RM_RESORCE_IS_PROD(resource_name)) bw_ptr = &ipa_rm_ctx->prof_vote.bw_prods[resource_name]; else bw_ptr = &ipa_rm_ctx->prof_vote.bw_cons[ resource_name - IPA_RM_RESOURCE_PROD_MAX]; switch (resource->state) { case IPA_RM_GRANTED: case IPA_RM_REQUEST_IN_PROGRESS: IPA_RM_DBG("max_bw = %d, needed_bw = %d\n", resource->max_bw, resource->needed_bw); *bw_ptr = min(resource->max_bw, resource->needed_bw); ipa_rm_ctx->prof_vote.volt[resource_name] = resource->floor_voltage; break; case IPA_RM_RELEASE_IN_PROGRESS: case IPA_RM_RELEASED: *bw_ptr = 0; ipa_rm_ctx->prof_vote.volt[resource_name] = 0; break; default: IPA_RM_ERR("unknown state %d\n", resource->state); WARN_ON(1); return; } IPA_RM_DBG("resource bandwidth: %d voltage: %d\n", *bw_ptr, resource->floor_voltage); ipa_rm_ctx->prof_vote.curr_volt = IPA_VOLTAGE_UNSPECIFIED; for (i = 0; i < IPA_RM_RESOURCE_MAX; i++) { if (ipa_rm_ctx->prof_vote.volt[i] > ipa_rm_ctx->prof_vote.curr_volt) { ipa_rm_ctx->prof_vote.curr_volt = ipa_rm_ctx->prof_vote.volt[i]; } } for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++) sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i]; for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++) sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i]; IPA_RM_DBG("all prod bandwidth: %d all cons bandwidth: %d\n", sum_bw_prod, sum_bw_cons); ipa_rm_ctx->prof_vote.curr_bw = min(sum_bw_prod, sum_bw_cons); if (ipa_rm_ctx->prof_vote.curr_volt == old_volt && ipa_rm_ctx->prof_vote.curr_bw == old_bw) { IPA_RM_DBG("same voting\n"); return; } IPA_RM_DBG("new voting: voltage %d bandwidth %d\n", ipa_rm_ctx->prof_vote.curr_volt, ipa_rm_ctx->prof_vote.curr_bw); ipa_rm_perf_profile_notify_to_ipa(ipa_rm_ctx->prof_vote.curr_volt, ipa_rm_ctx->prof_vote.curr_bw); return; }; /** * ipa_rm_exit() - free all IPA RM resources */ Loading drivers/platform/msm/ipa/ipa_rm_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ int ipa_rm_stat(char *buf, int size); const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name); void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name); void ipa_rm_exit(void); #endif /* _IPA_RM_I_H_ */ drivers/platform/msm/ipa/ipa_rm_resource.c +109 −40 Original line number Diff line number Diff line Loading @@ -76,7 +76,8 @@ int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name) } static int ipa_rm_resource_consumer_request( struct ipa_rm_resource_cons *consumer) struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { int result = 0; int driver_result; Loading @@ -85,6 +86,7 @@ static int ipa_rm_resource_consumer_request( ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); consumer->resource.needed_bw += prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -95,10 +97,12 @@ static int ipa_rm_resource_consumer_request( IPA_RM_DBG("calling driver CB\n"); driver_result = consumer->request_resource(); IPA_RM_DBG("driver CB returned with %d\n", driver_result); if (driver_result == 0) if (driver_result == 0) { consumer->resource.state = IPA_RM_GRANTED; else if (driver_result != -EINPROGRESS) { ipa_rm_perf_profile_change(consumer->resource.name); } else if (driver_result != -EINPROGRESS) { consumer->resource.state = prev_state; consumer->resource.needed_bw -= prod_needed_bw; result = driver_result; goto bail; } Loading @@ -106,11 +110,13 @@ static int ipa_rm_resource_consumer_request( break; } case IPA_RM_GRANTED: ipa_rm_perf_profile_change(consumer->resource.name); break; case IPA_RM_REQUEST_IN_PROGRESS: result = -EINPROGRESS; break; default: consumer->resource.needed_bw -= prod_needed_bw; result = -EPERM; goto bail; } Loading @@ -125,34 +131,46 @@ bail: } static int ipa_rm_resource_consumer_release( struct ipa_rm_resource_cons *consumer) struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { int result = 0; int driver_result; enum ipa_rm_resource_state save_state; IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); consumer->resource.needed_bw -= prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: break; case IPA_RM_GRANTED: case IPA_RM_REQUEST_IN_PROGRESS: if (consumer->usage_count > 0) if (consumer->usage_count == 0) { IPA_RM_ERR("consumer not used\n"); result = -EPERM; break; } consumer->usage_count--; if (consumer->usage_count == 0) { save_state = consumer->resource.state; consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS; IPA_RM_DBG("calling driver CB\n"); driver_result = consumer->release_resource(); result = consumer->release_resource(); IPA_RM_DBG("driver CB returned with %d\n", driver_result); if (driver_result == 0) consumer->resource.state = IPA_RM_RELEASED; else if (driver_result != -EINPROGRESS) result); if (result != 0 && result != -EINPROGRESS) { IPA_RM_ERR("driver CB returned error %d\n", result); consumer->resource.state = save_state; result = driver_result; goto bail; } if (result == 0) consumer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change(consumer->resource.name); } else if (consumer->resource.state == IPA_RM_GRANTED) { ipa_rm_perf_profile_change(consumer->resource.name); } break; case IPA_RM_RELEASE_IN_PROGRESS: Loading Loading @@ -247,6 +265,7 @@ static void ipa_rm_resource_producer_delete( struct ipa_rm_notification_info *reg_info; struct list_head *pos, *q; ipa_rm_resource_producer_release(producer); list_for_each_safe(pos, q, &(producer->event_listeners)) { reg_info = list_entry(pos, struct ipa_rm_notification_info, Loading Loading @@ -332,6 +351,7 @@ int ipa_rm_resource_create( goto peers_alloc_fail; } (*resource)->name = create_params->name; (*resource)->floor_voltage = create_params->floor_voltage; (*resource)->state = IPA_RM_RELEASED; goto bail; Loading Loading @@ -532,6 +552,7 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); resource->needed_bw += depends_on->max_bw; switch (resource->state) { case IPA_RM_RELEASED: case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -544,11 +565,13 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, ((struct ipa_rm_resource_prod *) resource)->pending_request++; consumer_result = ipa_rm_resource_consumer_request( (struct ipa_rm_resource_cons *)depends_on); (struct ipa_rm_resource_cons *)depends_on, resource->max_bw); if (consumer_result != -EINPROGRESS) { resource->state = prev_state; ((struct ipa_rm_resource_prod *) resource)->pending_request--; ipa_rm_perf_profile_change(resource->name); } result = consumer_result; break; Loading Loading @@ -599,10 +622,12 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); resource->needed_bw -= depends_on->max_bw; switch (resource->state) { case IPA_RM_RELEASED: break; case IPA_RM_GRANTED: ipa_rm_perf_profile_change(resource->name); release_consumer = true; break; case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -616,6 +641,7 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->state = IPA_RM_RELEASED; state_changed = true; evt = IPA_RM_RESOURCE_RELEASED; ipa_rm_perf_profile_change(resource->name); } break; case IPA_RM_REQUEST_IN_PROGRESS: Loading @@ -630,6 +656,7 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->state = IPA_RM_GRANTED; state_changed = true; evt = IPA_RM_RESOURCE_GRANTED; ipa_rm_perf_profile_change(resource->name); } break; default: Loading @@ -652,7 +679,8 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->name); if (release_consumer) (void) ipa_rm_resource_consumer_release( (struct ipa_rm_resource_cons *)depends_on); (struct ipa_rm_resource_cons *)depends_on, resource->max_bw); bail: IPA_RM_DBG("EXIT with %d\n", result); Loading @@ -673,17 +701,6 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) int consumer_result; enum ipa_rm_resource_state state; if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) { state = producer->resource.state; producer->resource.state = IPA_RM_GRANTED; (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_GRANTED, true); result = 0; goto unlock_and_bail; } state = producer->resource.state; switch (producer->resource.state) { case IPA_RM_RELEASED: Loading @@ -710,7 +727,8 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) if (consumer) { producer->pending_request++; consumer_result = ipa_rm_resource_consumer_request( (struct ipa_rm_resource_cons *)consumer); (struct ipa_rm_resource_cons *)consumer, producer->resource.max_bw); if (consumer_result == -EINPROGRESS) { result = -EINPROGRESS; } else { Loading @@ -725,6 +743,7 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) if (producer->pending_request == 0) { producer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change(producer->resource.name); (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_GRANTED, Loading Loading @@ -756,16 +775,6 @@ int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer) int consumer_result; enum ipa_rm_resource_state state; if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) { state = producer->resource.state; producer->resource.state = IPA_RM_RELEASED; (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_RELEASED, true); goto bail; } state = producer->resource.state; switch (producer->resource.state) { case IPA_RM_RELEASED: Loading @@ -792,13 +801,15 @@ int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer) if (consumer) { producer->pending_release++; consumer_result = ipa_rm_resource_consumer_release( (struct ipa_rm_resource_cons *)consumer); (struct ipa_rm_resource_cons *)consumer, producer->resource.max_bw); producer->pending_release--; } } if (producer->pending_release == 0) { producer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change(producer->resource.name); (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_RELEASED, Loading Loading @@ -833,6 +844,8 @@ static void ipa_rm_resource_producer_handle_cb( if (producer->pending_request == 0) { producer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change( producer->resource.name); ipa_rm_resource_producer_notify_clients( producer, IPA_RM_RESOURCE_GRANTED, Loading @@ -849,6 +862,8 @@ static void ipa_rm_resource_producer_handle_cb( if (producer->pending_release == 0) { producer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change( producer->resource.name); ipa_rm_resource_producer_notify_clients( producer, IPA_RM_RESOURCE_RELEASED, Loading Loading @@ -896,6 +911,7 @@ void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer, if (event == IPA_RM_RESOURCE_RELEASED) goto bail; consumer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change(consumer->resource.name); break; case IPA_RM_RELEASE_IN_PROGRESS: if (event == IPA_RM_RESOURCE_GRANTED) Loading Loading @@ -930,6 +946,60 @@ bail: return; } /* * ipa_rm_resource_set_perf_profile() - sets the performance profile to * resource. * * @resource: [in] resource * @profile: [in] profile to be set * * sets the profile to the given resource, In case the resource is * granted, update bandwidth vote of the resource */ int ipa_rm_resource_set_perf_profile(struct ipa_rm_resource *resource, struct ipa_rm_perf_profile *profile) { int peers_index; struct ipa_rm_resource *peer; if (!resource || !profile) { IPA_RM_ERR("invalid params\n"); return -EINVAL; } if (profile->max_supported_bandwidth_mbps == resource->max_bw) { IPA_RM_DBG("same profile\n"); return 0; } if ((resource->type == IPA_RM_PRODUCER && (resource->state == IPA_RM_GRANTED || resource->state == IPA_RM_REQUEST_IN_PROGRESS)) || resource->type == IPA_RM_CONSUMER) { for (peers_index = 0; peers_index < ipa_rm_peers_list_get_size( resource->peers_list); peers_index++) { peer = ipa_rm_peers_list_get_resource(peers_index, resource->peers_list); if (!peer) continue; peer->needed_bw -= resource->max_bw; peer->needed_bw += profile->max_supported_bandwidth_mbps; if (peer->state == IPA_RM_GRANTED) ipa_rm_perf_profile_change(peer->name); } } resource->max_bw = profile->max_supported_bandwidth_mbps; if (resource->state == IPA_RM_GRANTED) ipa_rm_perf_profile_change(resource->name); return 0; } /* * ipa_rm_resource_producer_print_stat() - print the * resource status and all his dependencies Loading @@ -940,7 +1010,6 @@ bail: * * Returns: number of bytes used on success, negative on failure */ int ipa_rm_resource_producer_print_stat( struct ipa_rm_resource *resource, char *buf, Loading Loading @@ -992,7 +1061,7 @@ int ipa_rm_resource_producer_print_stat( resource->peers_list); if (consumer) { nbytes = scnprintf(buf + cnt, size - cnt, ipa_rm_resource_str(resource->name)); ipa_rm_resource_str(consumer->name)); cnt += nbytes; nbytes = scnprintf(buf + cnt, size - cnt, "["); cnt += nbytes; Loading Loading
drivers/platform/msm/ipa/ipa.c +7 −0 Original line number Diff line number Diff line Loading @@ -1604,6 +1604,13 @@ fail: return retval; } int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage, u32 bandwidth_mbps) { IPADBG("Not Implemented yet"); return 0; } static int ipa_init_flt_block(void) { int result = 0; Loading
drivers/platform/msm/ipa/ipa_i.h +3 −0 Original line number Diff line number Diff line Loading @@ -907,6 +907,9 @@ int ipa_id_alloc(void *ptr); void *ipa_id_find(u32 id); void ipa_id_remove(u32 id); int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage, u32 bandwidth_mbps); int ipa_cfg_ep_status(u32 clnt_hdl, const struct ipa_ep_cfg_status *ipa_ep_cfg); Loading
drivers/platform/msm/ipa/ipa_rm.c +200 −3 Original line number Diff line number Diff line Loading @@ -37,13 +37,28 @@ static const char *resource_name_to_str[IPA_RM_RESOURCE_MAX] = { __stringify(IPA_RM_RESOURCE_HSIC_CONS), }; struct ipa_rm_profile_vote_type { enum ipa_voltage_level volt[IPA_RM_RESOURCE_MAX]; enum ipa_voltage_level curr_volt; u32 bw_prods[IPA_RM_RESOURCE_PROD_MAX]; u32 bw_cons[IPA_RM_RESOURCE_CONS_MAX]; u32 curr_bw; }; struct ipa_rm_context_type { struct ipa_rm_dep_graph *dep_graph; struct workqueue_struct *ipa_rm_wq; spinlock_t ipa_rm_lock; struct ipa_rm_profile_vote_type prof_vote; }; static struct ipa_rm_context_type *ipa_rm_ctx; struct ipa_rm_notify_ipa_work_type { struct work_struct work; enum ipa_voltage_level volt; u32 bandwidth_mbps; }; /** * ipa_rm_create_resource() - create resource * @create_params: [in] parameters needed Loading @@ -67,6 +82,13 @@ int ipa_rm_create_resource(struct ipa_rm_create_params *create_params) } IPA_RM_DBG("%s\n", ipa_rm_resource_str(create_params->name)); if (create_params->floor_voltage < 0 || create_params->floor_voltage >= IPA_VOLTAGE_MAX) { IPA_RM_ERR("invalid voltage %d\n", create_params->floor_voltage); return -EINVAL; } spin_lock(&ipa_rm_ctx->ipa_rm_lock); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, create_params->name, Loading Loading @@ -353,6 +375,48 @@ bail: } EXPORT_SYMBOL(ipa_rm_deregister); /** * ipa_rm_set_perf_profile() - set performance profile * @resource_name: resource name * @profile: [in] profile information. * * Returns: 0 on success, negative on failure * * Set resource performance profile. * Updates IPA driver if performance level changed. */ int ipa_rm_set_perf_profile(enum ipa_rm_resource_name resource_name, struct ipa_rm_perf_profile *profile) { int result; struct ipa_rm_resource *resource; IPA_RM_DBG("%s\n", ipa_rm_resource_str(resource_name)); spin_lock(&ipa_rm_ctx->ipa_rm_lock); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, resource_name, &resource) != 0) { IPA_RM_ERR("resource does not exists\n"); result = -EPERM; goto bail; } result = ipa_rm_resource_set_perf_profile(resource, profile); if (result) { IPA_RM_ERR("ipa_rm_resource_set_perf_profile failed %d\n", result); goto bail; } result = 0; bail: spin_unlock(&ipa_rm_ctx->ipa_rm_lock); IPA_RM_DBG("EXIT with %d\n", result); return result; } EXPORT_SYMBOL(ipa_rm_set_perf_profile); /** * ipa_rm_notify_completion() - * consumer driver notification for Loading Loading @@ -563,6 +627,139 @@ const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name) return resource_name_to_str[resource_name]; }; static void ipa_rm_perf_profile_notify_to_ipa_work(struct work_struct *work) { struct ipa_rm_notify_ipa_work_type *notify_work = container_of(work, struct ipa_rm_notify_ipa_work_type, work); int res; IPA_RM_DBG("calling to IPA driver. voltage %d bandwidth %d\n", notify_work->volt, notify_work->bandwidth_mbps); res = ipa_set_required_perf_profile(notify_work->volt, notify_work->bandwidth_mbps); if (res) { IPA_RM_ERR("ipa_set_required_perf_profile failed %d\n", res); goto bail; } IPA_RM_DBG("IPA driver notified\n"); bail: kfree(notify_work); } static void ipa_rm_perf_profile_notify_to_ipa(enum ipa_voltage_level volt, u32 bandwidth) { struct ipa_rm_notify_ipa_work_type *work; work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) { IPA_RM_ERR("no mem\n"); return; } INIT_WORK(&work->work, ipa_rm_perf_profile_notify_to_ipa_work); work->volt = volt; work->bandwidth_mbps = bandwidth; queue_work(ipa_rm_ctx->ipa_rm_wq, &work->work); } /** * ipa_rm_perf_profile_change() - change performance profile vote for resource * @resource_name: [in] resource name * * change bandwidth and voltage vote based on resource state. */ void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name) { enum ipa_voltage_level old_volt; u32 *bw_ptr; u32 old_bw; struct ipa_rm_resource *resource; int i; u32 sum_bw_prod = 0; u32 sum_bw_cons = 0; IPA_RM_DBG("%s\n", ipa_rm_resource_str(resource_name)); if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, resource_name, &resource) != 0) { IPA_RM_ERR("resource does not exists\n"); WARN_ON(1); return; } old_volt = ipa_rm_ctx->prof_vote.curr_volt; old_bw = ipa_rm_ctx->prof_vote.curr_bw; if (IPA_RM_RESORCE_IS_PROD(resource_name)) bw_ptr = &ipa_rm_ctx->prof_vote.bw_prods[resource_name]; else bw_ptr = &ipa_rm_ctx->prof_vote.bw_cons[ resource_name - IPA_RM_RESOURCE_PROD_MAX]; switch (resource->state) { case IPA_RM_GRANTED: case IPA_RM_REQUEST_IN_PROGRESS: IPA_RM_DBG("max_bw = %d, needed_bw = %d\n", resource->max_bw, resource->needed_bw); *bw_ptr = min(resource->max_bw, resource->needed_bw); ipa_rm_ctx->prof_vote.volt[resource_name] = resource->floor_voltage; break; case IPA_RM_RELEASE_IN_PROGRESS: case IPA_RM_RELEASED: *bw_ptr = 0; ipa_rm_ctx->prof_vote.volt[resource_name] = 0; break; default: IPA_RM_ERR("unknown state %d\n", resource->state); WARN_ON(1); return; } IPA_RM_DBG("resource bandwidth: %d voltage: %d\n", *bw_ptr, resource->floor_voltage); ipa_rm_ctx->prof_vote.curr_volt = IPA_VOLTAGE_UNSPECIFIED; for (i = 0; i < IPA_RM_RESOURCE_MAX; i++) { if (ipa_rm_ctx->prof_vote.volt[i] > ipa_rm_ctx->prof_vote.curr_volt) { ipa_rm_ctx->prof_vote.curr_volt = ipa_rm_ctx->prof_vote.volt[i]; } } for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++) sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i]; for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++) sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i]; IPA_RM_DBG("all prod bandwidth: %d all cons bandwidth: %d\n", sum_bw_prod, sum_bw_cons); ipa_rm_ctx->prof_vote.curr_bw = min(sum_bw_prod, sum_bw_cons); if (ipa_rm_ctx->prof_vote.curr_volt == old_volt && ipa_rm_ctx->prof_vote.curr_bw == old_bw) { IPA_RM_DBG("same voting\n"); return; } IPA_RM_DBG("new voting: voltage %d bandwidth %d\n", ipa_rm_ctx->prof_vote.curr_volt, ipa_rm_ctx->prof_vote.curr_bw); ipa_rm_perf_profile_notify_to_ipa(ipa_rm_ctx->prof_vote.curr_volt, ipa_rm_ctx->prof_vote.curr_bw); return; }; /** * ipa_rm_exit() - free all IPA RM resources */ Loading
drivers/platform/msm/ipa/ipa_rm_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ int ipa_rm_stat(char *buf, int size); const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name); void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name); void ipa_rm_exit(void); #endif /* _IPA_RM_I_H_ */
drivers/platform/msm/ipa/ipa_rm_resource.c +109 −40 Original line number Diff line number Diff line Loading @@ -76,7 +76,8 @@ int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name) } static int ipa_rm_resource_consumer_request( struct ipa_rm_resource_cons *consumer) struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { int result = 0; int driver_result; Loading @@ -85,6 +86,7 @@ static int ipa_rm_resource_consumer_request( ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); consumer->resource.needed_bw += prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -95,10 +97,12 @@ static int ipa_rm_resource_consumer_request( IPA_RM_DBG("calling driver CB\n"); driver_result = consumer->request_resource(); IPA_RM_DBG("driver CB returned with %d\n", driver_result); if (driver_result == 0) if (driver_result == 0) { consumer->resource.state = IPA_RM_GRANTED; else if (driver_result != -EINPROGRESS) { ipa_rm_perf_profile_change(consumer->resource.name); } else if (driver_result != -EINPROGRESS) { consumer->resource.state = prev_state; consumer->resource.needed_bw -= prod_needed_bw; result = driver_result; goto bail; } Loading @@ -106,11 +110,13 @@ static int ipa_rm_resource_consumer_request( break; } case IPA_RM_GRANTED: ipa_rm_perf_profile_change(consumer->resource.name); break; case IPA_RM_REQUEST_IN_PROGRESS: result = -EINPROGRESS; break; default: consumer->resource.needed_bw -= prod_needed_bw; result = -EPERM; goto bail; } Loading @@ -125,34 +131,46 @@ bail: } static int ipa_rm_resource_consumer_release( struct ipa_rm_resource_cons *consumer) struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { int result = 0; int driver_result; enum ipa_rm_resource_state save_state; IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); consumer->resource.needed_bw -= prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: break; case IPA_RM_GRANTED: case IPA_RM_REQUEST_IN_PROGRESS: if (consumer->usage_count > 0) if (consumer->usage_count == 0) { IPA_RM_ERR("consumer not used\n"); result = -EPERM; break; } consumer->usage_count--; if (consumer->usage_count == 0) { save_state = consumer->resource.state; consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS; IPA_RM_DBG("calling driver CB\n"); driver_result = consumer->release_resource(); result = consumer->release_resource(); IPA_RM_DBG("driver CB returned with %d\n", driver_result); if (driver_result == 0) consumer->resource.state = IPA_RM_RELEASED; else if (driver_result != -EINPROGRESS) result); if (result != 0 && result != -EINPROGRESS) { IPA_RM_ERR("driver CB returned error %d\n", result); consumer->resource.state = save_state; result = driver_result; goto bail; } if (result == 0) consumer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change(consumer->resource.name); } else if (consumer->resource.state == IPA_RM_GRANTED) { ipa_rm_perf_profile_change(consumer->resource.name); } break; case IPA_RM_RELEASE_IN_PROGRESS: Loading Loading @@ -247,6 +265,7 @@ static void ipa_rm_resource_producer_delete( struct ipa_rm_notification_info *reg_info; struct list_head *pos, *q; ipa_rm_resource_producer_release(producer); list_for_each_safe(pos, q, &(producer->event_listeners)) { reg_info = list_entry(pos, struct ipa_rm_notification_info, Loading Loading @@ -332,6 +351,7 @@ int ipa_rm_resource_create( goto peers_alloc_fail; } (*resource)->name = create_params->name; (*resource)->floor_voltage = create_params->floor_voltage; (*resource)->state = IPA_RM_RELEASED; goto bail; Loading Loading @@ -532,6 +552,7 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); resource->needed_bw += depends_on->max_bw; switch (resource->state) { case IPA_RM_RELEASED: case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -544,11 +565,13 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, ((struct ipa_rm_resource_prod *) resource)->pending_request++; consumer_result = ipa_rm_resource_consumer_request( (struct ipa_rm_resource_cons *)depends_on); (struct ipa_rm_resource_cons *)depends_on, resource->max_bw); if (consumer_result != -EINPROGRESS) { resource->state = prev_state; ((struct ipa_rm_resource_prod *) resource)->pending_request--; ipa_rm_perf_profile_change(resource->name); } result = consumer_result; break; Loading Loading @@ -599,10 +622,12 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); resource->needed_bw -= depends_on->max_bw; switch (resource->state) { case IPA_RM_RELEASED: break; case IPA_RM_GRANTED: ipa_rm_perf_profile_change(resource->name); release_consumer = true; break; case IPA_RM_RELEASE_IN_PROGRESS: Loading @@ -616,6 +641,7 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->state = IPA_RM_RELEASED; state_changed = true; evt = IPA_RM_RESOURCE_RELEASED; ipa_rm_perf_profile_change(resource->name); } break; case IPA_RM_REQUEST_IN_PROGRESS: Loading @@ -630,6 +656,7 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->state = IPA_RM_GRANTED; state_changed = true; evt = IPA_RM_RESOURCE_GRANTED; ipa_rm_perf_profile_change(resource->name); } break; default: Loading @@ -652,7 +679,8 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, resource->name); if (release_consumer) (void) ipa_rm_resource_consumer_release( (struct ipa_rm_resource_cons *)depends_on); (struct ipa_rm_resource_cons *)depends_on, resource->max_bw); bail: IPA_RM_DBG("EXIT with %d\n", result); Loading @@ -673,17 +701,6 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) int consumer_result; enum ipa_rm_resource_state state; if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) { state = producer->resource.state; producer->resource.state = IPA_RM_GRANTED; (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_GRANTED, true); result = 0; goto unlock_and_bail; } state = producer->resource.state; switch (producer->resource.state) { case IPA_RM_RELEASED: Loading @@ -710,7 +727,8 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) if (consumer) { producer->pending_request++; consumer_result = ipa_rm_resource_consumer_request( (struct ipa_rm_resource_cons *)consumer); (struct ipa_rm_resource_cons *)consumer, producer->resource.max_bw); if (consumer_result == -EINPROGRESS) { result = -EINPROGRESS; } else { Loading @@ -725,6 +743,7 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer) if (producer->pending_request == 0) { producer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change(producer->resource.name); (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_GRANTED, Loading Loading @@ -756,16 +775,6 @@ int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer) int consumer_result; enum ipa_rm_resource_state state; if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) { state = producer->resource.state; producer->resource.state = IPA_RM_RELEASED; (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_RELEASED, true); goto bail; } state = producer->resource.state; switch (producer->resource.state) { case IPA_RM_RELEASED: Loading @@ -792,13 +801,15 @@ int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer) if (consumer) { producer->pending_release++; consumer_result = ipa_rm_resource_consumer_release( (struct ipa_rm_resource_cons *)consumer); (struct ipa_rm_resource_cons *)consumer, producer->resource.max_bw); producer->pending_release--; } } if (producer->pending_release == 0) { producer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change(producer->resource.name); (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD, producer->resource.name, IPA_RM_RESOURCE_RELEASED, Loading Loading @@ -833,6 +844,8 @@ static void ipa_rm_resource_producer_handle_cb( if (producer->pending_request == 0) { producer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change( producer->resource.name); ipa_rm_resource_producer_notify_clients( producer, IPA_RM_RESOURCE_GRANTED, Loading @@ -849,6 +862,8 @@ static void ipa_rm_resource_producer_handle_cb( if (producer->pending_release == 0) { producer->resource.state = IPA_RM_RELEASED; ipa_rm_perf_profile_change( producer->resource.name); ipa_rm_resource_producer_notify_clients( producer, IPA_RM_RESOURCE_RELEASED, Loading Loading @@ -896,6 +911,7 @@ void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer, if (event == IPA_RM_RESOURCE_RELEASED) goto bail; consumer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change(consumer->resource.name); break; case IPA_RM_RELEASE_IN_PROGRESS: if (event == IPA_RM_RESOURCE_GRANTED) Loading Loading @@ -930,6 +946,60 @@ bail: return; } /* * ipa_rm_resource_set_perf_profile() - sets the performance profile to * resource. * * @resource: [in] resource * @profile: [in] profile to be set * * sets the profile to the given resource, In case the resource is * granted, update bandwidth vote of the resource */ int ipa_rm_resource_set_perf_profile(struct ipa_rm_resource *resource, struct ipa_rm_perf_profile *profile) { int peers_index; struct ipa_rm_resource *peer; if (!resource || !profile) { IPA_RM_ERR("invalid params\n"); return -EINVAL; } if (profile->max_supported_bandwidth_mbps == resource->max_bw) { IPA_RM_DBG("same profile\n"); return 0; } if ((resource->type == IPA_RM_PRODUCER && (resource->state == IPA_RM_GRANTED || resource->state == IPA_RM_REQUEST_IN_PROGRESS)) || resource->type == IPA_RM_CONSUMER) { for (peers_index = 0; peers_index < ipa_rm_peers_list_get_size( resource->peers_list); peers_index++) { peer = ipa_rm_peers_list_get_resource(peers_index, resource->peers_list); if (!peer) continue; peer->needed_bw -= resource->max_bw; peer->needed_bw += profile->max_supported_bandwidth_mbps; if (peer->state == IPA_RM_GRANTED) ipa_rm_perf_profile_change(peer->name); } } resource->max_bw = profile->max_supported_bandwidth_mbps; if (resource->state == IPA_RM_GRANTED) ipa_rm_perf_profile_change(resource->name); return 0; } /* * ipa_rm_resource_producer_print_stat() - print the * resource status and all his dependencies Loading @@ -940,7 +1010,6 @@ bail: * * Returns: number of bytes used on success, negative on failure */ int ipa_rm_resource_producer_print_stat( struct ipa_rm_resource *resource, char *buf, Loading Loading @@ -992,7 +1061,7 @@ int ipa_rm_resource_producer_print_stat( resource->peers_list); if (consumer) { nbytes = scnprintf(buf + cnt, size - cnt, ipa_rm_resource_str(resource->name)); ipa_rm_resource_str(consumer->name)); cnt += nbytes; nbytes = scnprintf(buf + cnt, size - cnt, "["); cnt += nbytes; Loading