diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c index 5c185c8d181d3f7b228d9c53f982c463a3d97738..784ffc10a7a15d926b03a1530737c760a73e9919 100644 --- a/drivers/platform/msm/ipa/ipa.c +++ b/drivers/platform/msm/ipa/ipa.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/rbtree.h> #include <linux/uaccess.h> +#include <linux/interrupt.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> #include "ipa_i.h" @@ -1800,6 +1801,65 @@ static int ipa_init_flt_block(void) return result; } +/** +* ipa_suspend_handler() - Handles the suspend interrupt: +* wakes up the suspended peripheral by requesting its consumer +* @interrupt: Interrupt type +* @private_data: The client's private data +* @interrupt_data: Interrupt specific information data +*/ +void ipa_suspend_handler(enum ipa_irq_type interrupt, + void *private_data, + void *interrupt_data) +{ + enum ipa_rm_resource_name resource; + u32 suspend_data = + ((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints; + u32 bmsk = 1; + u32 i = 0; + + IPADBG("interrupt=%d, interrupt_data=%u\n", interrupt, suspend_data); + for (i = 0; i < IPA_NUM_PIPES; i++) { + if ((suspend_data & bmsk) && (ipa_ctx->ep[i].valid)) { + resource = ipa_get_rm_resource_from_ep(i); + ipa_rm_request_resource_with_timer(resource); + } + bmsk = bmsk << 1; + } +} + +static int apps_cons_release_resource(void) +{ + return 0; +} + +static int apps_cons_request_resource(void) +{ + return 0; +} + +static int ipa_create_apps_resource(void) +{ + struct ipa_rm_create_params apps_cons_create_params; + struct ipa_rm_perf_profile profile; + int result = 0; + + memset(&apps_cons_create_params, 0, + sizeof(apps_cons_create_params)); + apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS; + apps_cons_create_params.request_resource = apps_cons_request_resource; + apps_cons_create_params.release_resource = apps_cons_release_resource; + result = ipa_rm_create_resource(&apps_cons_create_params); + if (result) { + IPAERR("ipa_rm_create_resource failed\n"); + return result; + } + + profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS; + ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile); + + return result; +} /** * ipa_init() - Initialize the IPA Driver * @resource_p: contain platform specific values from DST file @@ -2074,7 +2134,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, spin_lock_init(&ipa_ctx->idr_lock); mutex_init(&ipa_ctx->ipa_active_clients_lock); - ipa_ctx->ipa_active_clients = 0; + ipa_ctx->ipa_active_clients = 1; /* wlan related member */ spin_lock_init(&ipa_ctx->wlan_spinlock); @@ -2082,9 +2142,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, ipa_ctx->wlan_comm_cnt = 0; INIT_LIST_HEAD(&ipa_ctx->wlan_comm_desc_list); memset(&ipa_ctx->wstats, 0, sizeof(struct ipa_wlan_stats)); - /* enable IPA clocks until the end of the initialization */ - ipa_inc_client_enable_clks(); - /* * setup an empty routing table in system memory, this will be used * to delete a routing table cleanly and safely @@ -2166,13 +2223,29 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, } IPADBG("IPA resource manager initialized"); + result = ipa_create_apps_resource(); + if (result) { + IPAERR("Failed to create APPS_CONS resource\n"); + result = -ENODEV; + goto fail_create_apps_resource; + } + /*register IPA IRQ handler*/ - result = ipa_interrupts_init(resource_p->ipa_irq, resource_p->ee, + result = ipa_interrupts_init(resource_p->ipa_irq, 0, ipa_dev); if (result) { IPAERR("ipa interrupts initialization failed\n"); result = -ENODEV; - goto fail_ipa_rm_init; + goto fail_ipa_interrupts_init; + } + + /*add handler for suspend interrupt*/ + result = ipa_add_interrupt_handler(IPA_TX_SUSPEND_IRQ, + ipa_suspend_handler, true, NULL); + if (result) { + IPAERR("register handler for suspend interrupt failed\n"); + result = -ENODEV; + goto fail_add_interrupt_handler; } if (ipa_ctx->use_ipa_teth_bridge) { @@ -2181,7 +2254,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, if (result) { IPAERR(":teth_bridge init failed (%d)\n", -result); result = -ENODEV; - goto fail_teth_bridge_init; + goto fail_add_interrupt_handler; } IPADBG("teth_bridge initialized"); } @@ -2193,7 +2266,11 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, return 0; -fail_teth_bridge_init: +fail_add_interrupt_handler: + free_irq(resource_p->ipa_irq, ipa_dev); +fail_ipa_interrupts_init: + ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS); +fail_create_apps_resource: ipa_rm_exit(); fail_ipa_rm_init: cdev_del(&ipa_ctx->cdev); diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c index 37aa781568984e40359ae5ae7dca207f954e2db9..bc318587faa07a6d2ac13db6e75145c59a924bbe 100644 --- a/drivers/platform/msm/ipa/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_debugfs.c @@ -720,6 +720,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, "stat_compl=%u\n" "lan_aggr_close=%u\n" "wan_aggr_close=%u\n" + "act_clnt=%u\n" "con_clnt_bmap=0x%x\n", ipa_ctx->stats.tx_sw_pkts, ipa_ctx->stats.tx_hw_pkts, @@ -728,6 +729,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, ipa_ctx->stats.stat_compl, ipa_ctx->stats.aggr_close, ipa_ctx->stats.wan_aggr_close, + ipa_ctx->ipa_active_clients, connect); cnt += nbytes; diff --git a/drivers/platform/msm/ipa/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_interrupts.c index 3e9f4766d48fb921beb59e32544a03d5ef200578..dbc45d58f50e9d31766854fe8e0e34d8a67d79aa 100644 --- a/drivers/platform/msm/ipa/ipa_interrupts.c +++ b/drivers/platform/msm/ipa/ipa_interrupts.c @@ -38,7 +38,7 @@ static void deferred_interrupt_work(struct work_struct *work) container_of(work, struct ipa_interrupt_work_wrap, interrupt_work); - IPAERR("call handler from workq...\n"); + IPADBG("call handler from workq...\n"); work_data->handler(work_data->interrupt, work_data->private_data, work_data->interrupt_data); kfree(work_data->interrupt_data); @@ -127,10 +127,12 @@ static irqreturn_t ipa_isr(int irq, void *ctxt) u32 reg; u32 bmsk = 1; u32 i = 0; + u32 en; + en = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee)); reg = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee)); for (i = 0; i < IPA_IRQ_MAX; i++) { - if (reg & bmsk) + if (en & reg & bmsk) handle_interrupt(i); bmsk = bmsk << 1; } @@ -138,7 +140,6 @@ static irqreturn_t ipa_isr(int irq, void *ctxt) return IRQ_HANDLED; } - /** * ipa_add_interrupt_handler() - Adds handler to an interrupt type * @interrupt: Interrupt type diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c index d65e282e3308b19d54c983445c0bbeebeb5cd644..95851ad04600a10805e086caa1875d4cdbc85cfc 100644 --- a/drivers/platform/msm/ipa/ipa_rm.c +++ b/drivers/platform/msm/ipa/ipa_rm.c @@ -16,7 +16,6 @@ #include "ipa_i.h" #include "ipa_rm_dependency_graph.h" #include "ipa_rm_i.h" -#include "ipa_rm_resource.h" static const char *resource_name_to_str[IPA_RM_RESOURCE_MAX] = { __stringify(IPA_RM_RESOURCE_Q6_PROD), @@ -254,6 +253,82 @@ bail: } EXPORT_SYMBOL(ipa_rm_request_resource); +void delayed_release_work_func(struct work_struct *work) +{ + struct ipa_rm_resource *resource; + struct ipa_rm_delayed_release_work_type *rwork = container_of( + to_delayed_work(work), + struct ipa_rm_delayed_release_work_type, + work); + + if (!IPA_RM_RESORCE_IS_CONS(rwork->resource_name)) { + IPA_RM_ERR("can be called on CONS only\n"); + kfree(rwork); + return; + } + spin_lock(&ipa_rm_ctx->ipa_rm_lock); + if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, + rwork->resource_name, + &resource) != 0) { + IPA_RM_ERR("resource does not exists\n"); + goto bail; + } + + ipa_rm_resource_consumer_release( + (struct ipa_rm_resource_cons *)resource, rwork->needed_bw); + +bail: + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); + kfree(rwork); + +} + +/** + * ipa_rm_request_resource_with_timer() - requests the specified consumer + * resource and releases it after 1 second + * @resource_name: name of the requested resource + * + * Returns: 0 on success, negative on failure + */ +int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name) +{ + struct ipa_rm_resource *resource; + struct ipa_rm_delayed_release_work_type *release_work; + int result; + + if (!IPA_RM_RESORCE_IS_CONS(resource_name)) { + IPA_RM_ERR("can be called on CONS only\n"); + return -EINVAL; + } + + 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_consumer_request( + (struct ipa_rm_resource_cons *)resource, 0); + if (result != 0 && result != -EINPROGRESS) { + IPA_RM_ERR("consumer request returned error %d\n", result); + result = -EPERM; + goto bail; + } + + release_work = kzalloc(sizeof(*release_work), GFP_ATOMIC); + release_work->resource_name = resource->name; + release_work->needed_bw = 0; + INIT_DELAYED_WORK(&release_work->work, delayed_release_work_func); + schedule_delayed_work(&release_work->work, + msecs_to_jiffies(IPA_RM_RELEASE_DELAY_IN_MSEC)); + result = 0; +bail: + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); + + return result; +} /** * ipa_rm_release_resource() - release resource * @resource_name: [in] name of the requested resource @@ -504,6 +579,71 @@ static void ipa_rm_wq_handler(struct work_struct *work) kfree((void *) work); } +static void ipa_rm_wq_resume_handler(struct work_struct *work) +{ + struct ipa_rm_resource *resource; + struct ipa_rm_wq_suspend_resume_work_type *ipa_rm_work = + container_of(work, + struct ipa_rm_wq_suspend_resume_work_type, + work); + IPA_RM_DBG("resume work handler: %s", + ipa_rm_resource_str(ipa_rm_work->resource_name)); + + if (!IPA_RM_RESORCE_IS_CONS(ipa_rm_work->resource_name)) { + IPA_RM_ERR("resource is not CONS\n"); + return; + } + ipa_inc_client_enable_clks(); + spin_lock(&ipa_rm_ctx->ipa_rm_lock); + if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, + ipa_rm_work->resource_name, + &resource) != 0){ + IPA_RM_ERR("resource does not exists\n"); + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); + ipa_dec_client_disable_clks(); + goto bail; + } + ipa_rm_resource_consumer_request_work( + (struct ipa_rm_resource_cons *)resource, + ipa_rm_work->prev_state, ipa_rm_work->needed_bw, true); + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); +bail: + kfree(ipa_rm_work); +} + + +static void ipa_rm_wq_suspend_handler(struct work_struct *work) +{ + struct ipa_rm_resource *resource; + struct ipa_rm_wq_suspend_resume_work_type *ipa_rm_work = + container_of(work, + struct ipa_rm_wq_suspend_resume_work_type, + work); + IPA_RM_DBG("suspend work handler: %s", + ipa_rm_resource_str(ipa_rm_work->resource_name)); + + if (!IPA_RM_RESORCE_IS_CONS(ipa_rm_work->resource_name)) { + IPA_RM_ERR("resource is not CONS\n"); + return; + } + ipa_suspend_resource_sync(ipa_rm_work->resource_name); + spin_lock(&ipa_rm_ctx->ipa_rm_lock); + if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, + ipa_rm_work->resource_name, + &resource) != 0){ + IPA_RM_ERR("resource does not exists\n"); + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); + return; + } + ipa_rm_resource_consumer_release_work( + (struct ipa_rm_resource_cons *)resource, + ipa_rm_work->prev_state, + true); + spin_unlock(&ipa_rm_ctx->ipa_rm_lock); + + kfree(ipa_rm_work); +} + /** * ipa_rm_wq_send_cmd() - send a command for deferred work * @wq_cmd: command that should be executed @@ -535,6 +675,48 @@ int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd, return result; } +int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_state prev_state, + u32 needed_bw) +{ + int result = -ENOMEM; + struct ipa_rm_wq_suspend_resume_work_type *work = kzalloc(sizeof(*work), + GFP_ATOMIC); + if (work) { + INIT_WORK((struct work_struct *)work, + ipa_rm_wq_suspend_handler); + work->resource_name = resource_name; + work->prev_state = prev_state; + work->needed_bw = needed_bw; + result = queue_work(ipa_rm_ctx->ipa_rm_wq, + (struct work_struct *)work); + } else { + IPA_RM_ERR("no mem\n"); + } + + return result; +} + +int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_state prev_state, + u32 needed_bw) +{ + int result = -ENOMEM; + struct ipa_rm_wq_suspend_resume_work_type *work = kzalloc(sizeof(*work), + GFP_ATOMIC); + if (work) { + INIT_WORK((struct work_struct *)work, ipa_rm_wq_resume_handler); + work->resource_name = resource_name; + work->prev_state = prev_state; + work->needed_bw = needed_bw; + result = queue_work(ipa_rm_ctx->ipa_rm_wq, + (struct work_struct *)work); + } else { + IPA_RM_ERR("no mem\n"); + } + + return result; +} /** * ipa_rm_initialize() - initialize IPA RM component * diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h index 2882ffbe1c6d017f54fb378b591be609490dafa4..488dcf74b9519ee3fdc07c231477a835acebce1c 100644 --- a/drivers/platform/msm/ipa/ipa_rm_i.h +++ b/drivers/platform/msm/ipa/ipa_rm_i.h @@ -15,6 +15,7 @@ #include <linux/workqueue.h> #include <linux/ipa.h> +#include "ipa_rm_resource.h" #define IPA_RM_DRV_NAME "ipa_rm" @@ -30,10 +31,25 @@ #define IPA_RM_RESORCE_IS_CONS(x) \ (x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX) #define IPA_RM_INDEX_INVALID (-1) +#define IPA_RM_RELEASE_DELAY_IN_MSEC 1000 int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name); int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name); +/** + * struct ipa_rm_delayed_release_work_type - IPA RM delayed resource release + * work type + * @delayed_work: work struct + * @ipa_rm_resource_name: name of the resource on which this work should be done + * @needed_bw: bandwidth required for resource in Mbps + */ +struct ipa_rm_delayed_release_work_type { + struct delayed_work work; + enum ipa_rm_resource_name resource_name; + u32 needed_bw; + +}; + /** * enum ipa_rm_wq_cmd - workqueue commands */ @@ -63,11 +79,36 @@ struct ipa_rm_wq_work_type { bool notify_registered_only; }; +/** + * struct ipa_rm_wq_suspend_resume_work_type - IPA RM worqueue resume or + * suspend work type + * @work: work struct + * @resource_name: name of the resource on which this work + * should be done + * @prev_state: + * @needed_bw: + */ +struct ipa_rm_wq_suspend_resume_work_type { + struct work_struct work; + enum ipa_rm_resource_name resource_name; + enum ipa_rm_resource_state prev_state; + u32 needed_bw; + +}; + int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd, enum ipa_rm_resource_name resource_name, enum ipa_rm_event event, bool notify_registered_only); +int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_state prev_state, + u32 needed_bw); + +int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_state prev_state, + u32 needed_bw); + int ipa_rm_initialize(void); int ipa_rm_stat(char *buf, int size); @@ -76,6 +117,10 @@ 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); +int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name); + +void delayed_release_work_func(struct work_struct *work); + void ipa_rm_exit(void); #endif /* _IPA_RM_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c index 073f21b131a64606b98b5427052a0aea9ed4baca..41ae20466d16551487160a5d2c599fc81e8bd97d 100644 --- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c +++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include "ipa_i.h" #include "ipa_rm_i.h" -#include "ipa_rm_resource.h" /** * ipa_rm_peers_list_get_resource_index() - resource name to index diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c index 9dd7f11aa67306a73e940ced1cbdffc043c36a5b..d3d965e9d62a4af65b21168ff83a7d508c6d80f1 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.c +++ b/drivers/platform/msm/ipa/ipa_rm_resource.c @@ -75,40 +75,94 @@ int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name) return result; } -static int ipa_rm_resource_consumer_request( +int ipa_rm_resource_consumer_release_work( + struct ipa_rm_resource_cons *consumer, + enum ipa_rm_resource_state prev_state, + bool notify_completion) +{ + int driver_result; + + IPA_RM_DBG("calling driver CB\n"); + driver_result = consumer->release_resource(); + IPA_RM_DBG("driver CB returned with %d\n", driver_result); + if (driver_result != 0 && driver_result != -EINPROGRESS) { + IPA_RM_ERR("driver CB returned error %d\n", driver_result); + consumer->resource.state = prev_state; + goto bail; + } + if (driver_result == 0) { + if (notify_completion) + ipa_rm_resource_consumer_handle_cb(consumer, + IPA_RM_RESOURCE_RELEASED); + else + consumer->resource.state = IPA_RM_RELEASED; + } + + ipa_rm_perf_profile_change(consumer->resource.name); +bail: + return driver_result; +} + +int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer, + enum ipa_rm_resource_state prev_state, + u32 prod_needed_bw, + bool notify_completion) +{ + int driver_result; + + 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 (notify_completion) { + ipa_rm_resource_consumer_handle_cb(consumer, + IPA_RM_RESOURCE_GRANTED); + } else { + consumer->resource.state = IPA_RM_GRANTED; + ipa_rm_perf_profile_change(consumer->resource.name); + ipa_resume_resource(consumer->resource.name); + } + } else if (driver_result != -EINPROGRESS) { + consumer->resource.state = prev_state; + consumer->resource.needed_bw -= prod_needed_bw; + consumer->usage_count--; + } + + return driver_result; +} + +int ipa_rm_resource_consumer_request( struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { int result = 0; - int driver_result; + enum ipa_rm_resource_state prev_state; IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); + prev_state = consumer->resource.state; consumer->resource.needed_bw += prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: case IPA_RM_RELEASE_IN_PROGRESS: - { - enum ipa_rm_resource_state prev_state = - consumer->resource.state; consumer->resource.state = IPA_RM_REQUEST_IN_PROGRESS; - 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) { - consumer->resource.state = IPA_RM_GRANTED; - 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; + if (prev_state == IPA_RM_RELEASE_IN_PROGRESS || + ipa_inc_client_enable_clks_no_block() != 0) { + IPA_RM_DBG("async resume work for %s\n", + ipa_rm_resource_str(consumer->resource.name)); + ipa_rm_wq_send_resume_cmd(consumer->resource.name, + prev_state, + prod_needed_bw); + result = -EINPROGRESS; + break; } - result = driver_result; + result = ipa_rm_resource_consumer_request_work(consumer, + prev_state, + prod_needed_bw, + false); break; - } case IPA_RM_GRANTED: ipa_rm_perf_profile_change(consumer->resource.name); break; @@ -130,7 +184,7 @@ bail: return result; } -static int ipa_rm_resource_consumer_release( +int ipa_rm_resource_consumer_release( struct ipa_rm_resource_cons *consumer, u32 prod_needed_bw) { @@ -140,6 +194,7 @@ static int ipa_rm_resource_consumer_release( IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(consumer->resource.name), consumer->resource.state); + save_state = consumer->resource.state; consumer->resource.needed_bw -= prod_needed_bw; switch (consumer->resource.state) { case IPA_RM_RELEASED: @@ -153,22 +208,20 @@ static int ipa_rm_resource_consumer_release( } 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"); - result = consumer->release_resource(); - IPA_RM_DBG("driver CB returned with %d\n", - result); - if (result != 0 && result != -EINPROGRESS) { - IPA_RM_ERR("driver CB returned error %d\n", - result); - consumer->resource.state = save_state; + if (save_state == IPA_RM_REQUEST_IN_PROGRESS || + ipa_suspend_resource_no_block( + consumer->resource.name) != 0) { + ipa_rm_wq_send_suspend_cmd( + consumer->resource.name, + save_state, + prod_needed_bw); + result = -EINPROGRESS; goto bail; } - if (result == 0) - consumer->resource.state = IPA_RM_RELEASED; - ipa_rm_perf_profile_change(consumer->resource.name); - + result = ipa_rm_resource_consumer_release_work(consumer, + save_state, false); + goto bail; } else if (consumer->resource.state == IPA_RM_GRANTED) { ipa_rm_perf_profile_change(consumer->resource.name); } @@ -912,6 +965,7 @@ void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer, goto bail; consumer->resource.state = IPA_RM_GRANTED; ipa_rm_perf_profile_change(consumer->resource.name); + ipa_resume_resource(consumer->resource.name); break; case IPA_RM_RELEASE_IN_PROGRESS: if (event == IPA_RM_RESOURCE_GRANTED) diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h index c1b73746cf39295b56a732455f5d74d6d918cdbc..4a66ca48d09783e858420eb22c5d1cef8aff66bd 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.h +++ b/drivers/platform/msm/ipa/ipa_rm_resource.h @@ -122,6 +122,12 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer); int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer); +int ipa_rm_resource_consumer_request(struct ipa_rm_resource_cons *consumer, + u32 needed_bw); + +int ipa_rm_resource_consumer_release(struct ipa_rm_resource_cons *consumer, + u32 needed_bw); + int ipa_rm_resource_set_perf_profile(struct ipa_rm_resource *resource, struct ipa_rm_perf_profile *profile); @@ -138,4 +144,14 @@ int ipa_rm_resource_producer_print_stat( char *buf, int size); +int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer, + enum ipa_rm_resource_state prev_state, + u32 needed_bw, + bool notify_completion); + +int ipa_rm_resource_consumer_release_work( + struct ipa_rm_resource_cons *consumer, + enum ipa_rm_resource_state prev_state, + bool notify_completion); + #endif /* _IPA_RM_RESOURCE_H_ */ diff --git a/include/linux/ipa.h b/include/linux/ipa.h index 2a06f46cb5f55da4fbb0c8f0c8da14fe45a88adb..96278509076c0e882722fd9dc318e974e94c4056 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -18,6 +18,8 @@ #include <linux/types.h> #include <linux/msm-sps.h> +#define IPA_APPS_MAX_BW_IN_MBPS 200 + /** * enum ipa_nat_en_type - NAT setting type in IPA end-point */