From 8f54b9374e56fd08f990fe2fe4dc8b3bde1c00d2 Mon Sep 17 00:00:00 2001 From: Neela Chithirala Date: Mon, 14 Mar 2022 05:24:14 +0000 Subject: Merge branch 'gs201-release' to android13-gs-pixel-5.10 * gs201-release: gxp: ignore AUR_OFF in power voting Bug: 223286553 gxp: change memory power state asynchronously Bug: 221187219 gxp: cancel the vote when the client is destroyed Bug: 201600514 gxp: refactor pm interface Bug: 201600514 gxp: Make a power state vote for debugfs wakelocks Bug: 223286553 gxp: Return error if gxp_vd_allocate() fails Signed-off-by: Neela Chithirala Change-Id: Ibb879ffffa83e787409debec4e5e55bfe8858808 --- gxp-client.c | 8 +++++++- gxp-debugfs.c | 29 ++++++++++++++++++++------- gxp-platform.c | 5 +++-- gxp-pm.c | 62 +++++++++++++++++++++++++++++++++++----------------------- gxp-pm.h | 10 +++++++++- 5 files changed, 78 insertions(+), 36 deletions(-) diff --git a/gxp-client.c b/gxp-client.c index 2ff0a7c..73aafc1 100644 --- a/gxp-client.c +++ b/gxp-client.c @@ -52,8 +52,14 @@ void gxp_client_destroy(struct gxp_client *client) up_write(&gxp->vd_semaphore); - if (client->has_block_wakelock) + if (client->has_block_wakelock) { gxp_wakelock_release(client->gxp); + gxp_pm_update_requested_power_state( + gxp, client->requested_power_state, AUR_OFF); + gxp_pm_update_requested_memory_power_state( + gxp, client->requested_memory_power_state, + AUR_MEM_UNDEFINED); + } gxp_vd_release(client->vd); diff --git a/gxp-debugfs.c b/gxp-debugfs.c index 0576c9a..480dca2 100644 --- a/gxp-debugfs.c +++ b/gxp-debugfs.c @@ -148,15 +148,16 @@ static int gxp_firmware_run_set(void *data, u64 val) if (IS_ERR(gxp->debugfs_client->vd)) { dev_err(gxp->dev, "Failed to allocate VD\n"); ret = PTR_ERR(gxp->debugfs_client->vd); - goto err_start; + goto err_wakelock; } ret = gxp_wakelock_acquire(gxp); if (ret) { dev_err(gxp->dev, "Failed to acquire BLOCK wakelock\n"); - goto err_start; + goto err_wakelock; } gxp->debugfs_client->has_block_wakelock = true; + gxp_pm_update_requested_power_state(gxp, AUR_OFF, AUR_UUD); down_write(&gxp->vd_semaphore); ret = gxp_vd_start(gxp->debugfs_client->vd); @@ -179,6 +180,7 @@ static int gxp_firmware_run_set(void *data, u64 val) */ gxp_client_destroy(gxp->debugfs_client); gxp->debugfs_client = NULL; + gxp_pm_update_requested_power_state(gxp, AUR_UUD, AUR_OFF); } out: @@ -187,6 +189,9 @@ out: return ret; err_start: + gxp_wakelock_release(gxp); + gxp_pm_update_requested_power_state(gxp, AUR_UUD, AUR_OFF); +err_wakelock: /* Destroying a client cleans up any VDss or wakelocks it held. */ gxp_client_destroy(gxp->debugfs_client); gxp->debugfs_client = NULL; @@ -210,32 +215,42 @@ static int gxp_wakelock_set(void *data, u64 val) struct gxp_dev *gxp = (struct gxp_dev *)data; int ret = 0; + mutex_lock(&gxp->debugfs_client_lock); + if (val > 0) { /* Wakelock Acquire */ if (gxp->debugfs_wakelock_held) { dev_warn(gxp->dev, "Debugfs wakelock is already held.\n"); - return -EBUSY; + ret = -EBUSY; + goto out; } ret = gxp_wakelock_acquire(gxp); - if (ret) + if (ret) { dev_err(gxp->dev, "Failed to acquire debugfs wakelock ret=%d\n", ret); - else - gxp->debugfs_wakelock_held = true; + goto out; + } + gxp->debugfs_wakelock_held = true; + gxp_pm_update_requested_power_state(gxp, AUR_OFF, AUR_UUD); } else { /* Wakelock Release */ if (!gxp->debugfs_wakelock_held) { dev_warn(gxp->dev, "Debugfs wakelock not held.\n"); - return -EIO; + ret = -EIO; + goto out; } gxp_wakelock_release(gxp); gxp->debugfs_wakelock_held = false; + gxp_pm_update_requested_power_state(gxp, AUR_UUD, AUR_OFF); } +out: + mutex_unlock(&gxp->debugfs_client_lock); + return ret; } diff --git a/gxp-platform.c b/gxp-platform.c index 3061935..ba2093e 100644 --- a/gxp-platform.c +++ b/gxp-platform.c @@ -536,9 +536,10 @@ static int gxp_allocate_vd(struct gxp_client *client, vd = gxp_vd_allocate(gxp, ibuf.core_count); if (IS_ERR(vd)) { + ret = PTR_ERR(vd); dev_err(gxp->dev, - "Failed to allocate virtual device for client (%ld)\n", - PTR_ERR(vd)); + "Failed to allocate virtual device for client (%d)\n", + ret); goto out; } diff --git a/gxp-pm.c b/gxp-pm.c index 87da768..7ca23a5 100644 --- a/gxp-pm.c +++ b/gxp-pm.c @@ -242,7 +242,7 @@ static int gxp_pm_req_state_locked(struct gxp_dev *gxp, enum aur_power_state sta if (state != gxp->power_mgr->curr_state) { gxp->power_mgr->curr_state = state; if (state == AUR_OFF) { - gxp_pm_blk_off(gxp); + dev_warn(gxp->dev, "It is not supported to request AUR_OFF\n"); } else { gxp->power_mgr->set_acpm_rate_work.gxp = gxp; gxp->power_mgr->set_acpm_rate_work.state = state; @@ -265,24 +265,23 @@ int gxp_pm_req_state(struct gxp_dev *gxp, enum aur_power_state state) } /* Caller must hold pm_lock */ -static int gxp_pm_revoke_power_state_vote(struct gxp_dev *gxp, - enum aur_power_state revoked_state) +static void gxp_pm_revoke_power_state_vote(struct gxp_dev *gxp, + enum aur_power_state revoked_state) { unsigned int i; if (revoked_state == AUR_OFF) - return 0; + return; for (i = 0; i < AUR_NUM_POWER_STATE; i++) { if (aur_state_array[i] == revoked_state) { - if (gxp->power_mgr->pwr_state_req_count[i] <= 0) { + if (gxp->power_mgr->pwr_state_req_count[i] == 0) dev_err(gxp->dev, "Invalid state %d\n", revoked_state); - return -EINVAL; - } - gxp->power_mgr->pwr_state_req_count[i]--; + else + gxp->power_mgr->pwr_state_req_count[i]--; + return; } } - return 0; } /* Caller must hold pm_lock */ @@ -293,9 +292,12 @@ static void gxp_pm_vote_power_state(struct gxp_dev *gxp, if (state == AUR_OFF) return; - for (i = 0; i < AUR_NUM_POWER_STATE; i++) - if (aur_state_array[i] == state) + for (i = 0; i < AUR_NUM_POWER_STATE; i++) { + if (aur_state_array[i] == state) { gxp->power_mgr->pwr_state_req_count[i]++; + return; + } + } } /* Caller must hold pm_lock */ @@ -321,13 +323,10 @@ int gxp_pm_update_requested_power_state(struct gxp_dev *gxp, unsigned long max_state; mutex_lock(&gxp->power_mgr->pm_lock); - ret = gxp_pm_revoke_power_state_vote(gxp, origin_state); - if (ret < 0) - goto out; + gxp_pm_revoke_power_state_vote(gxp, origin_state); gxp_pm_vote_power_state(gxp, requested_state); max_state = gxp_pm_get_max_voted_power_state(gxp); ret = gxp_pm_req_state_locked(gxp, max_state); -out: mutex_unlock(&gxp->power_mgr->pm_lock); return ret; } @@ -339,6 +338,17 @@ static int gxp_pm_req_pm_qos(struct gxp_dev *gxp, s32 int_val, s32 mif_val) return 0; } +static void gxp_pm_req_pm_qos_async(struct work_struct *work) +{ + struct gxp_req_pm_qos_work *req_pm_qos_work = + container_of(work, struct gxp_req_pm_qos_work, work); + + mutex_lock(&req_pm_qos_work->gxp->power_mgr->pm_lock); + gxp_pm_req_pm_qos(req_pm_qos_work->gxp, req_pm_qos_work->int_val, + req_pm_qos_work->mif_val); + mutex_unlock(&req_pm_qos_work->gxp->power_mgr->pm_lock); +} + static int gxp_pm_req_memory_state_locked(struct gxp_dev *gxp, enum aur_memory_power_state state) { s32 int_val = 0, mif_val = 0; @@ -351,20 +361,25 @@ static int gxp_pm_req_memory_state_locked(struct gxp_dev *gxp, enum aur_memory_p gxp->power_mgr->curr_memory_state = state; int_val = aur_memory_state2int_table[state]; mif_val = aur_memory_state2mif_table[state]; - gxp_pm_req_pm_qos(gxp, int_val, mif_val); + gxp->power_mgr->req_pm_qos_work.gxp = gxp; + gxp->power_mgr->req_pm_qos_work.int_val = int_val; + gxp->power_mgr->req_pm_qos_work.mif_val = mif_val; + queue_work(gxp->power_mgr->wq, + &gxp->power_mgr->req_pm_qos_work.work); } return 0; } /* Caller must hold pm_lock */ -static int gxp_pm_revoke_memory_power_state_vote(struct gxp_dev *gxp, - enum aur_memory_power_state revoked_state) +static void +gxp_pm_revoke_memory_power_state_vote(struct gxp_dev *gxp, + enum aur_memory_power_state revoked_state) { unsigned int i; if (revoked_state == AUR_MEM_UNDEFINED) - return 0; + return; for (i = 0; i < AUR_NUM_MEMORY_POWER_STATE; i++) { if (aur_memory_state_array[i] == revoked_state) { if (gxp->power_mgr->mem_pwr_state_req_count[i] == 0) @@ -374,10 +389,9 @@ static int gxp_pm_revoke_memory_power_state_vote(struct gxp_dev *gxp, revoked_state); else gxp->power_mgr->mem_pwr_state_req_count[i]--; - return 0; + return; } } - return 0; } /* Caller must hold pm_lock */ @@ -419,13 +433,10 @@ int gxp_pm_update_requested_memory_power_state( unsigned long max_state; mutex_lock(&gxp->power_mgr->pm_lock); - ret = gxp_pm_revoke_memory_power_state_vote(gxp, origin_state); - if (ret < 0) - goto out; + gxp_pm_revoke_memory_power_state_vote(gxp, origin_state); gxp_pm_vote_memory_power_state(gxp, requested_state); max_state = gxp_pm_get_max_voted_memory_power_state(gxp); ret = gxp_pm_req_memory_state_locked(gxp, max_state); -out: mutex_unlock(&gxp->power_mgr->pm_lock); return ret; } @@ -471,6 +482,7 @@ int gxp_pm_init(struct gxp_dev *gxp) mgr->ops = &gxp_aur_ops; gxp->power_mgr = mgr; INIT_WORK(&mgr->set_acpm_rate_work.work, gxp_pm_blk_set_state_acpm_async); + INIT_WORK(&mgr->req_pm_qos_work.work, gxp_pm_req_pm_qos_async); gxp->power_mgr->wq = create_singlethread_workqueue("gxp_power_work_queue"); diff --git a/gxp-pm.h b/gxp-pm.h index 73273f7..e5bbdad 100644 --- a/gxp-pm.h +++ b/gxp-pm.h @@ -52,16 +52,24 @@ struct gxp_set_acpm_state_work { unsigned long state; }; +struct gxp_req_pm_qos_work { + struct work_struct work; + struct gxp_dev *gxp; + s32 int_val; + s32 mif_val; +}; + struct gxp_power_manager { struct gxp_dev *gxp; struct mutex pm_lock; - int pwr_state_req_count[AUR_NUM_POWER_STATE]; + uint pwr_state_req_count[AUR_NUM_POWER_STATE]; uint mem_pwr_state_req_count[AUR_NUM_MEMORY_POWER_STATE]; int curr_state; int curr_memory_state; refcount_t blk_wake_ref; struct gxp_pm_device_ops *ops; struct gxp_set_acpm_state_work set_acpm_rate_work; + struct gxp_req_pm_qos_work req_pm_qos_work; struct workqueue_struct *wq; /* INT/MIF requests for memory bandwidth */ struct exynos_pm_qos_request int_min; -- cgit v1.2.3