Loading drivers/gpu/msm/adreno.c +13 −11 Original line number Diff line number Diff line Loading @@ -122,9 +122,10 @@ static unsigned int _wake_timeout = 100; /* * A workqueue callback responsible for actually turning on the GPU after a * touch event. kgsl_pwrctrl_wake() is used without any active_count protection * to avoid the need to maintain state. Either somebody will start using the * GPU or the idle timer will fire and put the GPU back into slumber * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any * active_count protection to avoid the need to maintain state. Either * somebody will start using the GPU or the idle timer will fire and put the * GPU back into slumber. */ static void adreno_input_work(struct work_struct *work) { Loading @@ -140,7 +141,7 @@ static void adreno_input_work(struct work_struct *work) * Don't schedule adreno_start in a high priority workqueue, we are * already in a workqueue which should be sufficient */ kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); /* * When waking up from a touch event we want to stay active long enough Loading Loading @@ -1700,7 +1701,7 @@ static int adreno_init(struct kgsl_device *device) /* Make a high priority workqueue for starting the GPU */ adreno_wq = alloc_workqueue("adreno", 0, 1); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); /* * initialization only needs to be done once initially until * device is shutdown Loading Loading @@ -1736,7 +1737,7 @@ static int adreno_init(struct kgsl_device *device) BUG_ON(1); } kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); /* * Check if firmware supports the sync lock PM4 packets needed * for IOMMUv1 Loading Loading @@ -1814,7 +1815,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) kgsl_cffdump_open(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) || (device->pwrctrl.gpu_cx && Loading Loading @@ -1887,7 +1888,7 @@ error_mmu_off: error_clk_off: kgsl_pwrctrl_disable(device); /* set the state back to original state */ kgsl_pwrctrl_set_state(device, state); kgsl_pwrctrl_change_state(device, state); return status; } Loading Loading @@ -2043,7 +2044,7 @@ int adreno_reset(struct kgsl_device *device) */ if (atomic_read(&device->active_cnt)) kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); /* Set the page table back to the default page table */ kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable, Loading Loading @@ -2328,7 +2329,7 @@ static ssize_t _ft_hang_intr_status_store(struct device *dev, switch (device->state) { case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); case KGSL_STATE_ACTIVE: adreno_dev->gpudev->irq_control(adreno_dev, 1); /* Loading Loading @@ -2611,7 +2612,8 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv, kgsl_pwrscale_enable(device); } else { kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); device->pwrctrl.ctrl_flags = KGSL_PWR_ON; adreno_dev->fast_hang_detect = 0; if (adreno_dev->gpudev->fault_detect_stop) Loading drivers/gpu/msm/kgsl.c +7 −66 Original line number Diff line number Diff line Loading @@ -611,61 +611,9 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) KGSL_PWR_WARN(device, "suspend start\n"); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND); /* Tell the device to drain the submission queue */ device->ftbl->drain(device); /* Wait for the active count to hit zero */ status = kgsl_active_count_wait(device, 0); if (status) goto end; /* * An interrupt could have snuck in and requested NAP in * the meantime, make sure we're on the SUSPEND path. */ kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND); /* Don't let the timer wake us during suspended sleep. */ del_timer_sync(&device->idle_timer); switch (device->state) { case KGSL_STATE_INIT: break; case KGSL_STATE_ACTIVE: case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: /* make sure power is on to stop the device */ kgsl_pwrctrl_enable(device); /* Get the completion ready to be waited upon. */ INIT_COMPLETION(device->hwaccess_gate); device->ftbl->suspend_context(device); device->ftbl->stop(device); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); break; case KGSL_STATE_SLUMBER: INIT_COMPLETION(device->hwaccess_gate); kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); break; default: KGSL_PWR_ERR(device, "suspend fail, device %d\n", device->id); goto end; } kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); kgsl_pwrscale_sleep(device); status = 0; end: if (status) { /* On failure, re-resume normal activity */ if (device->ftbl->resume) device->ftbl->resume(device); } status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); KGSL_PWR_WARN(device, "suspend end\n"); return status; } Loading @@ -678,8 +626,7 @@ static int kgsl_resume_device(struct kgsl_device *device) KGSL_PWR_WARN(device, "resume start\n"); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); if (device->state == KGSL_STATE_SUSPEND) { kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); complete_all(&device->hwaccess_gate); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); } else if (device->state != KGSL_STATE_INIT) { /* * This is an error situation,so wait for the device Loading @@ -689,16 +636,10 @@ static int kgsl_resume_device(struct kgsl_device *device) */ if (device->state == KGSL_STATE_ACTIVE) device->ftbl->idle(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); KGSL_PWR_ERR(device, "resume invoked without a suspend\n"); } kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); /* Call the GPU specific resume function */ if (device->ftbl->resume) device->ftbl->resume(device); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); KGSL_PWR_WARN(device, "resume end\n"); Loading Loading @@ -915,7 +856,7 @@ static int kgsl_close_device(struct kgsl_device *device) /* Force power on to do the stop */ kgsl_pwrctrl_enable(device); result = device->ftbl->stop(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); } return result; Loading Loading @@ -1017,7 +958,7 @@ static int kgsl_open_device(struct kgsl_device *device) * we start suspend or FT. */ complete_all(&device->hwaccess_gate); kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); kgsl_active_count_put(device); } device->open_count++; Loading Loading @@ -1089,7 +1030,7 @@ err_stop: /* make sure power is on to stop the device */ kgsl_pwrctrl_enable(device); device->ftbl->stop(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); atomic_dec(&device->active_cnt); } err_freedevpriv: Loading drivers/gpu/msm/kgsl_cffdump.c +5 −2 Original line number Diff line number Diff line Loading @@ -628,11 +628,14 @@ int kgsl_cff_dump_enable_set(void *data, u64 val) if (!device->cff_dump_enable) { device->cff_dump_enable = 1; /* * put device to slumber so that we ensure that the * force device to slumber so that we ensure that the * start opcode in CFF is present */ kgsl_mutex_lock(&device->mutex, &device->mutex_owner); ret = kgsl_pwrctrl_slumber(device); ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); ret |= kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); if (ret) device->cff_dump_enable = 0; kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); Loading drivers/gpu/msm/kgsl_pwrctrl.c +136 −91 Original line number Diff line number Diff line Loading @@ -82,6 +82,10 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state); static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state); static void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state); static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /* * Given a requested power level do bounds checking on the constraints and Loading Loading @@ -1151,7 +1155,8 @@ void kgsl_idle_check(struct work_struct *work) || device->state == KGSL_STATE_NAP) { if (!atomic_read(&device->active_cnt)) kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_change_state(device, device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); if (device->state == KGSL_STATE_ACTIVE) Loading Loading @@ -1206,6 +1211,73 @@ void kgsl_pre_hwaccess(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_pre_hwaccess); /** * _init() - Get the GPU ready to start, but don't turn anything on * @device - Pointer to the kgsl_device struct */ static int _init(struct kgsl_device *device) { kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); return 0; } /** * _wake() - Power up the GPU from a slumber/sleep state * @device - Pointer to the kgsl_device struct * * Resume the GPU from a lower power state to ACTIVE. */ static int _wake(struct kgsl_device *device) { int status = 0; switch (device->state) { case KGSL_STATE_SUSPEND: complete_all(&device->hwaccess_gate); /* Call the GPU specific resume function */ device->ftbl->resume(device); case KGSL_STATE_SLUMBER: status = device->ftbl->start(device, device->pwrctrl.superfast); device->pwrctrl.superfast = false; if (status) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); KGSL_DRV_ERR(device, "start failed %d\n", status); break; } /* fall through */ case KGSL_STATE_SLEEP: kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); kgsl_pwrscale_wake(device); /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE); /* Enable state before turning on irq */ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, device->pwrctrl.pm_qos_latency); case KGSL_STATE_ACTIVE: kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); break; case KGSL_STATE_INIT: kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } static int _nap(struct kgsl_device *device) { Loading Loading @@ -1294,6 +1366,11 @@ _slumber(struct kgsl_device *device) break; case KGSL_STATE_SLUMBER: break; case KGSL_STATE_SUSPEND: complete_all(&device->hwaccess_gate); device->ftbl->resume(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); Loading @@ -1302,123 +1379,91 @@ _slumber(struct kgsl_device *device) return 0; } /******************************************************************/ /* Caller must hold the device mutex. */ int kgsl_pwrctrl_sleep(struct kgsl_device *device) { int status = 0; KGSL_PWR_INFO(device, "sleep device %d\n", device->id); /* Work through the legal state transitions */ switch (device->requested_state) { case KGSL_STATE_NAP: status = _nap(device); break; case KGSL_STATE_SLEEP: status = _sleep(device); break; case KGSL_STATE_SLUMBER: status = _slumber(device); break; default: KGSL_PWR_INFO(device, "bad state request 0x%x\n", device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_sleep); /* * kgsl_pwrctrl_slumber() - Put device into slumber if it is not in suspend * _suspend() - Put device into suspend * @device: Device pointer * * Return 0 on success else error code */ int kgsl_pwrctrl_slumber(struct kgsl_device *device) int _suspend(struct kgsl_device *device) { int ret = 0; if (KGSL_STATE_SLUMBER == device->state || KGSL_STATE_SUSPEND == device->state) return ret; if (KGSL_STATE_SUSPEND == device->requested_state) if (KGSL_STATE_SUSPEND == device->state) return ret; /* drain to prevent from more commands being submitted */ device->ftbl->drain(device); /* wait for active count so device can be put in slumber */ ret = kgsl_active_count_wait(device, 0); if (ret) { device->ftbl->resume(device); return ret; } if (ret) goto err; ret = device->ftbl->idle(device); if (ret) { device->ftbl->resume(device); if (ret) goto err; ret = _slumber(device); if (ret) goto err; kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); return ret; } /* resume since we drained earlier */ err: device->ftbl->resume(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); ret = kgsl_pwrctrl_sleep(device); KGSL_PWR_ERR(device, "device failed to SUSPEND %d\n", ret); return ret; } EXPORT_SYMBOL(kgsl_pwrctrl_slumber); /** * kgsl_pwrctrl_wake() - Power up the GPU from a slumber/sleep state * @device - Pointer to the kgsl_device struct * @priority - Boolean flag to indicate that the GPU start should be run in the * higher priority thread /* * kgsl_pwrctrl_change_state() changes the GPU state to the input * @device: Pointer to a KGSL device * @state: desired KGSL state * * Resume the GPU from a lower power state to ACTIVE. The caller to this * fucntion must host the kgsl_device mutex. * Caller must hold the device mutex. If the requested state change * is valid, execute it. Otherwise return an error code explaining * why the change has not taken place. Also print an error if an * unexpected state change failure occurs. For example, a change to * NAP may be rejected because the GPU is busy, this is not an error. * A change to SUSPEND should go through no matter what, so if it * fails an additional error message will be printed to dmesg. */ int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority) int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state) { int status = 0; kgsl_pwrctrl_request_state(device, state); kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE); switch (device->state) { case KGSL_STATE_SLUMBER: status = device->ftbl->start(device, priority); if (status) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); KGSL_DRV_ERR(device, "start failed %d\n", status); /* Work through the legal state transitions */ switch (device->requested_state) { case KGSL_STATE_INIT: status = _init(device); break; } /* fall through */ case KGSL_STATE_SLEEP: kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); kgsl_pwrscale_wake(device); /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE); /* Enable state before turning on irq */ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, device->pwrctrl.pm_qos_latency); case KGSL_STATE_ACTIVE: kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = _wake(device); break; case KGSL_STATE_NAP: status = _nap(device); break; case KGSL_STATE_SLEEP: status = _sleep(device); break; case KGSL_STATE_SLUMBER: status = _slumber(device); break; case KGSL_STATE_SUSPEND: status = _suspend(device); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); KGSL_PWR_INFO(device, "bad state request 0x%x\n", device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_wake); EXPORT_SYMBOL(kgsl_pwrctrl_change_state); void kgsl_pwrctrl_enable(struct kgsl_device *device) { Loading Loading @@ -1450,21 +1495,21 @@ void kgsl_pwrctrl_disable(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_pwrctrl_disable); void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state) static void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state) { trace_kgsl_pwr_set_state(device, state); device->state = state; device->requested_state = KGSL_STATE_NONE; } EXPORT_SYMBOL(kgsl_pwrctrl_set_state); void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state) static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state) { if (state != KGSL_STATE_NONE && state != device->requested_state) trace_kgsl_pwr_request_state(device, state); device->requested_state = state; } EXPORT_SYMBOL(kgsl_pwrctrl_request_state); const char *kgsl_pwrstate_to_str(unsigned int state) { Loading Loading @@ -1513,8 +1558,8 @@ int kgsl_active_count_get(struct kgsl_device *device) kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); wait_for_completion(&device->hwaccess_gate); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); ret = kgsl_pwrctrl_wake(device, 1); device->pwrctrl.superfast = true; ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); } if (ret == 0) atomic_inc(&device->active_cnt); Loading drivers/gpu/msm/kgsl_pwrctrl.h +4 −7 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ struct kgsl_pwr_constraint { * @bus_index - default bus index into the bus_ib table * @bus_ib - the set of unique ib requests needed for the bus calculation * @constraint - currently active power constraint * @superfast - Boolean flag to indicate that the GPU start should be run in the * higher priority thread */ struct kgsl_pwrctrl { Loading Loading @@ -109,6 +111,7 @@ struct kgsl_pwrctrl { unsigned int bus_index[KGSL_MAX_PWRLEVELS]; uint64_t bus_ib[KGSL_MAX_PWRLEVELS]; struct kgsl_pwr_constraint constraint; bool superfast; }; void kgsl_pwrctrl_irq(struct kgsl_device *device, int state); Loading @@ -117,8 +120,6 @@ void kgsl_pwrctrl_close(struct kgsl_device *device); void kgsl_timer(unsigned long data); void kgsl_idle_check(struct work_struct *work); void kgsl_pre_hwaccess(struct kgsl_device *device); int kgsl_pwrctrl_sleep(struct kgsl_device *device); int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority); void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int level); void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, Loading @@ -128,6 +129,7 @@ void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device); void kgsl_pwrctrl_enable(struct kgsl_device *device); void kgsl_pwrctrl_disable(struct kgsl_device *device); bool kgsl_pwrctrl_isenabled(struct kgsl_device *device); int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state); static inline unsigned long kgsl_get_clkrate(struct clk *clk) { Loading @@ -146,13 +148,8 @@ kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr) return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq; } void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state); void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); int __must_check kgsl_active_count_get(struct kgsl_device *device); void kgsl_active_count_put(struct kgsl_device *device); int kgsl_active_count_wait(struct kgsl_device *device, int count); int kgsl_pwrctrl_slumber(struct kgsl_device *device); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); #endif /* __KGSL_PWRCTRL_H */ Loading
drivers/gpu/msm/adreno.c +13 −11 Original line number Diff line number Diff line Loading @@ -122,9 +122,10 @@ static unsigned int _wake_timeout = 100; /* * A workqueue callback responsible for actually turning on the GPU after a * touch event. kgsl_pwrctrl_wake() is used without any active_count protection * to avoid the need to maintain state. Either somebody will start using the * GPU or the idle timer will fire and put the GPU back into slumber * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any * active_count protection to avoid the need to maintain state. Either * somebody will start using the GPU or the idle timer will fire and put the * GPU back into slumber. */ static void adreno_input_work(struct work_struct *work) { Loading @@ -140,7 +141,7 @@ static void adreno_input_work(struct work_struct *work) * Don't schedule adreno_start in a high priority workqueue, we are * already in a workqueue which should be sufficient */ kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); /* * When waking up from a touch event we want to stay active long enough Loading Loading @@ -1700,7 +1701,7 @@ static int adreno_init(struct kgsl_device *device) /* Make a high priority workqueue for starting the GPU */ adreno_wq = alloc_workqueue("adreno", 0, 1); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); /* * initialization only needs to be done once initially until * device is shutdown Loading Loading @@ -1736,7 +1737,7 @@ static int adreno_init(struct kgsl_device *device) BUG_ON(1); } kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); /* * Check if firmware supports the sync lock PM4 packets needed * for IOMMUv1 Loading Loading @@ -1814,7 +1815,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) kgsl_cffdump_open(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) || (device->pwrctrl.gpu_cx && Loading Loading @@ -1887,7 +1888,7 @@ error_mmu_off: error_clk_off: kgsl_pwrctrl_disable(device); /* set the state back to original state */ kgsl_pwrctrl_set_state(device, state); kgsl_pwrctrl_change_state(device, state); return status; } Loading Loading @@ -2043,7 +2044,7 @@ int adreno_reset(struct kgsl_device *device) */ if (atomic_read(&device->active_cnt)) kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); /* Set the page table back to the default page table */ kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable, Loading Loading @@ -2328,7 +2329,7 @@ static ssize_t _ft_hang_intr_status_store(struct device *dev, switch (device->state) { case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); case KGSL_STATE_ACTIVE: adreno_dev->gpudev->irq_control(adreno_dev, 1); /* Loading Loading @@ -2611,7 +2612,8 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv, kgsl_pwrscale_enable(device); } else { kgsl_pwrctrl_wake(device, 0); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); device->pwrctrl.ctrl_flags = KGSL_PWR_ON; adreno_dev->fast_hang_detect = 0; if (adreno_dev->gpudev->fault_detect_stop) Loading
drivers/gpu/msm/kgsl.c +7 −66 Original line number Diff line number Diff line Loading @@ -611,61 +611,9 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) KGSL_PWR_WARN(device, "suspend start\n"); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND); /* Tell the device to drain the submission queue */ device->ftbl->drain(device); /* Wait for the active count to hit zero */ status = kgsl_active_count_wait(device, 0); if (status) goto end; /* * An interrupt could have snuck in and requested NAP in * the meantime, make sure we're on the SUSPEND path. */ kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND); /* Don't let the timer wake us during suspended sleep. */ del_timer_sync(&device->idle_timer); switch (device->state) { case KGSL_STATE_INIT: break; case KGSL_STATE_ACTIVE: case KGSL_STATE_NAP: case KGSL_STATE_SLEEP: /* make sure power is on to stop the device */ kgsl_pwrctrl_enable(device); /* Get the completion ready to be waited upon. */ INIT_COMPLETION(device->hwaccess_gate); device->ftbl->suspend_context(device); device->ftbl->stop(device); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); break; case KGSL_STATE_SLUMBER: INIT_COMPLETION(device->hwaccess_gate); kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); break; default: KGSL_PWR_ERR(device, "suspend fail, device %d\n", device->id); goto end; } kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); kgsl_pwrscale_sleep(device); status = 0; end: if (status) { /* On failure, re-resume normal activity */ if (device->ftbl->resume) device->ftbl->resume(device); } status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); KGSL_PWR_WARN(device, "suspend end\n"); return status; } Loading @@ -678,8 +626,7 @@ static int kgsl_resume_device(struct kgsl_device *device) KGSL_PWR_WARN(device, "resume start\n"); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); if (device->state == KGSL_STATE_SUSPEND) { kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); complete_all(&device->hwaccess_gate); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); } else if (device->state != KGSL_STATE_INIT) { /* * This is an error situation,so wait for the device Loading @@ -689,16 +636,10 @@ static int kgsl_resume_device(struct kgsl_device *device) */ if (device->state == KGSL_STATE_ACTIVE) device->ftbl->idle(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); KGSL_PWR_ERR(device, "resume invoked without a suspend\n"); } kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); /* Call the GPU specific resume function */ if (device->ftbl->resume) device->ftbl->resume(device); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); KGSL_PWR_WARN(device, "resume end\n"); Loading Loading @@ -915,7 +856,7 @@ static int kgsl_close_device(struct kgsl_device *device) /* Force power on to do the stop */ kgsl_pwrctrl_enable(device); result = device->ftbl->stop(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); } return result; Loading Loading @@ -1017,7 +958,7 @@ static int kgsl_open_device(struct kgsl_device *device) * we start suspend or FT. */ complete_all(&device->hwaccess_gate); kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); kgsl_active_count_put(device); } device->open_count++; Loading Loading @@ -1089,7 +1030,7 @@ err_stop: /* make sure power is on to stop the device */ kgsl_pwrctrl_enable(device); device->ftbl->stop(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); atomic_dec(&device->active_cnt); } err_freedevpriv: Loading
drivers/gpu/msm/kgsl_cffdump.c +5 −2 Original line number Diff line number Diff line Loading @@ -628,11 +628,14 @@ int kgsl_cff_dump_enable_set(void *data, u64 val) if (!device->cff_dump_enable) { device->cff_dump_enable = 1; /* * put device to slumber so that we ensure that the * force device to slumber so that we ensure that the * start opcode in CFF is present */ kgsl_mutex_lock(&device->mutex, &device->mutex_owner); ret = kgsl_pwrctrl_slumber(device); ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); ret |= kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); if (ret) device->cff_dump_enable = 0; kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); Loading
drivers/gpu/msm/kgsl_pwrctrl.c +136 −91 Original line number Diff line number Diff line Loading @@ -82,6 +82,10 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state); static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state); static void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state); static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); /* * Given a requested power level do bounds checking on the constraints and Loading Loading @@ -1151,7 +1155,8 @@ void kgsl_idle_check(struct work_struct *work) || device->state == KGSL_STATE_NAP) { if (!atomic_read(&device->active_cnt)) kgsl_pwrctrl_sleep(device); kgsl_pwrctrl_change_state(device, device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); if (device->state == KGSL_STATE_ACTIVE) Loading Loading @@ -1206,6 +1211,73 @@ void kgsl_pre_hwaccess(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_pre_hwaccess); /** * _init() - Get the GPU ready to start, but don't turn anything on * @device - Pointer to the kgsl_device struct */ static int _init(struct kgsl_device *device) { kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT); return 0; } /** * _wake() - Power up the GPU from a slumber/sleep state * @device - Pointer to the kgsl_device struct * * Resume the GPU from a lower power state to ACTIVE. */ static int _wake(struct kgsl_device *device) { int status = 0; switch (device->state) { case KGSL_STATE_SUSPEND: complete_all(&device->hwaccess_gate); /* Call the GPU specific resume function */ device->ftbl->resume(device); case KGSL_STATE_SLUMBER: status = device->ftbl->start(device, device->pwrctrl.superfast); device->pwrctrl.superfast = false; if (status) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); KGSL_DRV_ERR(device, "start failed %d\n", status); break; } /* fall through */ case KGSL_STATE_SLEEP: kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); kgsl_pwrscale_wake(device); /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE); /* Enable state before turning on irq */ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, device->pwrctrl.pm_qos_latency); case KGSL_STATE_ACTIVE: kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); break; case KGSL_STATE_INIT: kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } static int _nap(struct kgsl_device *device) { Loading Loading @@ -1294,6 +1366,11 @@ _slumber(struct kgsl_device *device) break; case KGSL_STATE_SLUMBER: break; case KGSL_STATE_SUSPEND: complete_all(&device->hwaccess_gate); device->ftbl->resume(device); kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); Loading @@ -1302,123 +1379,91 @@ _slumber(struct kgsl_device *device) return 0; } /******************************************************************/ /* Caller must hold the device mutex. */ int kgsl_pwrctrl_sleep(struct kgsl_device *device) { int status = 0; KGSL_PWR_INFO(device, "sleep device %d\n", device->id); /* Work through the legal state transitions */ switch (device->requested_state) { case KGSL_STATE_NAP: status = _nap(device); break; case KGSL_STATE_SLEEP: status = _sleep(device); break; case KGSL_STATE_SLUMBER: status = _slumber(device); break; default: KGSL_PWR_INFO(device, "bad state request 0x%x\n", device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_sleep); /* * kgsl_pwrctrl_slumber() - Put device into slumber if it is not in suspend * _suspend() - Put device into suspend * @device: Device pointer * * Return 0 on success else error code */ int kgsl_pwrctrl_slumber(struct kgsl_device *device) int _suspend(struct kgsl_device *device) { int ret = 0; if (KGSL_STATE_SLUMBER == device->state || KGSL_STATE_SUSPEND == device->state) return ret; if (KGSL_STATE_SUSPEND == device->requested_state) if (KGSL_STATE_SUSPEND == device->state) return ret; /* drain to prevent from more commands being submitted */ device->ftbl->drain(device); /* wait for active count so device can be put in slumber */ ret = kgsl_active_count_wait(device, 0); if (ret) { device->ftbl->resume(device); return ret; } if (ret) goto err; ret = device->ftbl->idle(device); if (ret) { device->ftbl->resume(device); if (ret) goto err; ret = _slumber(device); if (ret) goto err; kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND); return ret; } /* resume since we drained earlier */ err: device->ftbl->resume(device); kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); ret = kgsl_pwrctrl_sleep(device); KGSL_PWR_ERR(device, "device failed to SUSPEND %d\n", ret); return ret; } EXPORT_SYMBOL(kgsl_pwrctrl_slumber); /** * kgsl_pwrctrl_wake() - Power up the GPU from a slumber/sleep state * @device - Pointer to the kgsl_device struct * @priority - Boolean flag to indicate that the GPU start should be run in the * higher priority thread /* * kgsl_pwrctrl_change_state() changes the GPU state to the input * @device: Pointer to a KGSL device * @state: desired KGSL state * * Resume the GPU from a lower power state to ACTIVE. The caller to this * fucntion must host the kgsl_device mutex. * Caller must hold the device mutex. If the requested state change * is valid, execute it. Otherwise return an error code explaining * why the change has not taken place. Also print an error if an * unexpected state change failure occurs. For example, a change to * NAP may be rejected because the GPU is busy, this is not an error. * A change to SUSPEND should go through no matter what, so if it * fails an additional error message will be printed to dmesg. */ int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority) int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state) { int status = 0; kgsl_pwrctrl_request_state(device, state); kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE); switch (device->state) { case KGSL_STATE_SLUMBER: status = device->ftbl->start(device, priority); if (status) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); KGSL_DRV_ERR(device, "start failed %d\n", status); /* Work through the legal state transitions */ switch (device->requested_state) { case KGSL_STATE_INIT: status = _init(device); break; } /* fall through */ case KGSL_STATE_SLEEP: kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); kgsl_pwrscale_wake(device); /* fall through */ case KGSL_STATE_NAP: /* Turn on the core clocks */ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE); /* Enable state before turning on irq */ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma, device->pwrctrl.pm_qos_latency); case KGSL_STATE_ACTIVE: kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = _wake(device); break; case KGSL_STATE_NAP: status = _nap(device); break; case KGSL_STATE_SLEEP: status = _sleep(device); break; case KGSL_STATE_SLUMBER: status = _slumber(device); break; case KGSL_STATE_SUSPEND: status = _suspend(device); break; default: KGSL_PWR_WARN(device, "unhandled state %s\n", kgsl_pwrstate_to_str(device->state)); KGSL_PWR_INFO(device, "bad state request 0x%x\n", device->requested_state); kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE); status = -EINVAL; break; } return status; } EXPORT_SYMBOL(kgsl_pwrctrl_wake); EXPORT_SYMBOL(kgsl_pwrctrl_change_state); void kgsl_pwrctrl_enable(struct kgsl_device *device) { Loading Loading @@ -1450,21 +1495,21 @@ void kgsl_pwrctrl_disable(struct kgsl_device *device) } EXPORT_SYMBOL(kgsl_pwrctrl_disable); void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state) static void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state) { trace_kgsl_pwr_set_state(device, state); device->state = state; device->requested_state = KGSL_STATE_NONE; } EXPORT_SYMBOL(kgsl_pwrctrl_set_state); void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state) static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state) { if (state != KGSL_STATE_NONE && state != device->requested_state) trace_kgsl_pwr_request_state(device, state); device->requested_state = state; } EXPORT_SYMBOL(kgsl_pwrctrl_request_state); const char *kgsl_pwrstate_to_str(unsigned int state) { Loading Loading @@ -1513,8 +1558,8 @@ int kgsl_active_count_get(struct kgsl_device *device) kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); wait_for_completion(&device->hwaccess_gate); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); ret = kgsl_pwrctrl_wake(device, 1); device->pwrctrl.superfast = true; ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); } if (ret == 0) atomic_inc(&device->active_cnt); Loading
drivers/gpu/msm/kgsl_pwrctrl.h +4 −7 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ struct kgsl_pwr_constraint { * @bus_index - default bus index into the bus_ib table * @bus_ib - the set of unique ib requests needed for the bus calculation * @constraint - currently active power constraint * @superfast - Boolean flag to indicate that the GPU start should be run in the * higher priority thread */ struct kgsl_pwrctrl { Loading Loading @@ -109,6 +111,7 @@ struct kgsl_pwrctrl { unsigned int bus_index[KGSL_MAX_PWRLEVELS]; uint64_t bus_ib[KGSL_MAX_PWRLEVELS]; struct kgsl_pwr_constraint constraint; bool superfast; }; void kgsl_pwrctrl_irq(struct kgsl_device *device, int state); Loading @@ -117,8 +120,6 @@ void kgsl_pwrctrl_close(struct kgsl_device *device); void kgsl_timer(unsigned long data); void kgsl_idle_check(struct work_struct *work); void kgsl_pre_hwaccess(struct kgsl_device *device); int kgsl_pwrctrl_sleep(struct kgsl_device *device); int kgsl_pwrctrl_wake(struct kgsl_device *device, int priority); void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, unsigned int level); void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device, Loading @@ -128,6 +129,7 @@ void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device); void kgsl_pwrctrl_enable(struct kgsl_device *device); void kgsl_pwrctrl_disable(struct kgsl_device *device); bool kgsl_pwrctrl_isenabled(struct kgsl_device *device); int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state); static inline unsigned long kgsl_get_clkrate(struct clk *clk) { Loading @@ -146,13 +148,8 @@ kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr) return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq; } void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state); void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); int __must_check kgsl_active_count_get(struct kgsl_device *device); void kgsl_active_count_put(struct kgsl_device *device); int kgsl_active_count_wait(struct kgsl_device *device, int count); int kgsl_pwrctrl_slumber(struct kgsl_device *device); void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy); #endif /* __KGSL_PWRCTRL_H */