Loading drivers/gpu/msm/adreno.c +12 −0 Original line number Diff line number Diff line Loading @@ -2794,6 +2794,7 @@ int adreno_idle(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); int ret; /* * Make sure the device mutex is held so the dispatcher can't send any Loading @@ -2806,6 +2807,17 @@ int adreno_idle(struct kgsl_device *device) adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2, 0x00000000, 0x80000000); /* Check if we are already idle before idling dispatcher */ if (adreno_isidle(device)) return 0; /* * Wait for dispatcher to finish completing commands * already submitted */ ret = adreno_dispatcher_idle(adreno_dev); if (ret) return ret; while (time_before(jiffies, wait)) { /* * If we fault, stop waiting and return an error. The dispatcher Loading drivers/gpu/msm/adreno.h +29 −3 Original line number Diff line number Diff line Loading @@ -120,6 +120,7 @@ enum adreno_gpurev { * submitted operation * @work: work_struct to put the dispatcher in a work queue * @kobj: kobject for the dispatcher directory in the device sysfs node * @idle_gate: Gate to wait on for dispatcher to idle */ struct adreno_dispatcher { struct mutex mutex; Loading @@ -135,6 +136,7 @@ struct adreno_dispatcher { unsigned int tail; struct work_struct work; struct kobject kobj; struct completion idle_gate; }; enum adreno_dispatcher_flags { Loading Loading @@ -192,6 +194,7 @@ struct adreno_device { struct adreno_busy_data busy_data; unsigned int ram_cycles_lo; unsigned int starved_ram_lo; atomic_t halt; }; /** Loading Loading @@ -623,8 +626,7 @@ void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain, void adreno_dispatcher_start(struct kgsl_device *device); int adreno_dispatcher_init(struct adreno_device *adreno_dev); void adreno_dispatcher_close(struct adreno_device *adreno_dev); int adreno_dispatcher_idle(struct adreno_device *adreno_dev, unsigned int timeout); int adreno_dispatcher_idle(struct adreno_device *adreno_dev); void adreno_dispatcher_irq_fault(struct kgsl_device *device); void adreno_dispatcher_stop(struct adreno_device *adreno_dev); Loading Loading @@ -929,7 +931,7 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev, /** * adreno_gpu_fault() - Return the current state of the GPU * @adreno_dev: A ponter to the adreno_device to query * @adreno_dev: A pointer to the adreno_device to query * * Return 0 if there is no fault or positive with the last type of fault that * occurred Loading @@ -940,6 +942,18 @@ static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev) return atomic_read(&adreno_dev->dispatcher.fault); } /** * adreno_gpu_halt() - Return the halt status of GPU * @adreno_dev: A pointer to the adreno_device to query * * Return the halt request value */ static inline unsigned int adreno_gpu_halt(struct adreno_device *adreno_dev) { smp_rmb(); return atomic_read(&adreno_dev->halt); } /** * adreno_set_gpu_fault() - Set the current fault status of the GPU * @adreno_dev: A pointer to the adreno_device to set Loading @@ -954,6 +968,18 @@ static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev, smp_wmb(); } /** * adreno_set_gpu_halt() - Set the halt request * @adreno_dev: A pointer to the adreno_device to set * @state: Value to set */ static inline void adreno_set_gpu_halt(struct adreno_device *adreno_dev, int state) { atomic_set(&adreno_dev->halt, state); smp_wmb(); } /** * adreno_clear_gpu_fault() - Clear the GPU fault register * @adreno_dev: A pointer to an adreno_device structure Loading drivers/gpu/msm/adreno_dispatch.c +73 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/err.h> #include "kgsl.h" #include "kgsl_cffdump.h" #include "adreno.h" #include "adreno_ringbuffer.h" #include "adreno_trace.h" Loading Loading @@ -292,6 +293,9 @@ static int sendcmd(struct adreno_device *adreno_dev, struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int ret; if (0 != adreno_gpu_halt(adreno_dev)) return -EINVAL; dispatcher->inflight++; mutex_lock(&device->mutex); Loading @@ -317,9 +321,10 @@ static int sendcmd(struct adreno_device *adreno_dev, */ if (dispatcher->inflight == 1) { if (ret == 0) if (ret == 0) { fault_detect_read(device); else { init_completion(&dispatcher->idle_gate); } else { kgsl_active_count_put(device); clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); } Loading Loading @@ -477,6 +482,9 @@ static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev) if (adreno_gpu_fault(adreno_dev) != 0) break; if (0 != adreno_gpu_halt(adreno_dev)) break; spin_lock(&dispatcher->plist_lock); if (plist_head_empty(&dispatcher->pending)) { Loading Loading @@ -971,6 +979,7 @@ static int dispatcher_do_fault(struct kgsl_device *device) int fault, first = 0; bool pagefault = false; char *state = "failed"; int halt; fault = atomic_xchg(&dispatcher->fault, 0); if (fault == 0) Loading @@ -997,6 +1006,9 @@ static int dispatcher_do_fault(struct kgsl_device *device) mutex_lock(&device->mutex); /* hang opcode */ kgsl_cffdump_hang(device); cmdbatch = dispatcher->cmdqueue[dispatcher->head]; trace_adreno_cmdbatch_fault(cmdbatch, fault); Loading Loading @@ -1220,7 +1232,9 @@ replay: /* Reset the GPU */ mutex_lock(&device->mutex); /* make sure halt is not set during recovery */ halt = adreno_gpu_halt(adreno_dev); adreno_set_gpu_halt(adreno_dev, 0); ret = adreno_reset(device); mutex_unlock(&device->mutex); /* if any other fault got in until reset then ignore */ Loading Loading @@ -1279,6 +1293,8 @@ replay: } kfree(replay); /* restore halt indicator */ adreno_set_gpu_halt(adreno_dev, halt); return 1; } Loading Loading @@ -1480,6 +1496,7 @@ done: } else { /* There is nothing left in the pipeline. Shut 'er down boys */ mutex_lock(&device->mutex); complete_all(&dispatcher->idle_gate); /* * Stop the fault timer before decrementing the active count to * avoid reading the hardware registers while we are trying to Loading Loading @@ -1791,6 +1808,9 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) INIT_WORK(&dispatcher->work, adreno_dispatcher_work); init_completion(&dispatcher->idle_gate); complete_all(&dispatcher->idle_gate); plist_head_init(&dispatcher->pending); spin_lock_init(&dispatcher->plist_lock); Loading @@ -1799,3 +1819,53 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) return ret; } /* * adreno_dispatcher_idle() - Wait for dispatcher to idle * @adreno_dev: Adreno device whose dispatcher needs to idle * * Signal dispatcher to stop sending more commands and complete * the commands that have already been submitted. This function * should not be called when dispatcher mutex is held. */ int adreno_dispatcher_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int ret; BUG_ON(!mutex_is_locked(&device->mutex)); if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; /* * Ensure that this function is not called when dispatcher * mutex is held and device is started */ if (mutex_is_locked(&dispatcher->mutex) && dispatcher->mutex.owner == current) BUG_ON(1); adreno_set_gpu_halt(adreno_dev, 1); mutex_unlock(&device->mutex); ret = wait_for_completion_timeout(&dispatcher->idle_gate, msecs_to_jiffies(ADRENO_IDLE_TIMEOUT)); if (ret <= 0) { if (!ret) ret = -ETIMEDOUT; KGSL_DRV_ERR(device, "Dispatcher halt failed %d\n", ret); } else { ret = 0; } mutex_lock(&device->mutex); adreno_set_gpu_halt(adreno_dev, 0); /* * requeue dispatcher work to resubmit pending commands * that may have been blocked due to this idling request */ adreno_dispatcher_schedule(device); return ret; } drivers/gpu/msm/adreno_ringbuffer.c +6 −4 Original line number Diff line number Diff line Loading @@ -1277,16 +1277,18 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, /* Set the constraints before adding to ringbuffer */ adreno_ringbuffer_set_constraint(device, cmdbatch); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, drawctxt, flags, &link[0], (cmds - link), cmdbatch->timestamp); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); kgsl_cff_core_idle(device); kgsl_cffdump_regpoll(device, adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2, 0x00000000, 0x80000000); done: device->pwrctrl.irq_last = 0; trace_kgsl_issueibcmds(device, context->id, cmdbatch, Loading drivers/gpu/msm/kgsl_cffdump.h +1 −12 Original line number Diff line number Diff line /* Copyright (c) 2010-2011,2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2011,2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -149,15 +149,4 @@ static inline int kgsl_cff_dump_enable_get(void *data, u64 *val) } #endif /* CONFIG_MSM_KGSL_CFF_DUMP */ /* * kgsl_cff_core_idle() - Idle the device if CFF is on * @device: Device whose idle fuunction is called */ static inline void kgsl_cff_core_idle(struct kgsl_device *device) { if (device->cff_dump_enable) device->ftbl->idle(device); } #endif /* __KGSL_CFFDUMP_H */ Loading
drivers/gpu/msm/adreno.c +12 −0 Original line number Diff line number Diff line Loading @@ -2794,6 +2794,7 @@ int adreno_idle(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); int ret; /* * Make sure the device mutex is held so the dispatcher can't send any Loading @@ -2806,6 +2807,17 @@ int adreno_idle(struct kgsl_device *device) adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2, 0x00000000, 0x80000000); /* Check if we are already idle before idling dispatcher */ if (adreno_isidle(device)) return 0; /* * Wait for dispatcher to finish completing commands * already submitted */ ret = adreno_dispatcher_idle(adreno_dev); if (ret) return ret; while (time_before(jiffies, wait)) { /* * If we fault, stop waiting and return an error. The dispatcher Loading
drivers/gpu/msm/adreno.h +29 −3 Original line number Diff line number Diff line Loading @@ -120,6 +120,7 @@ enum adreno_gpurev { * submitted operation * @work: work_struct to put the dispatcher in a work queue * @kobj: kobject for the dispatcher directory in the device sysfs node * @idle_gate: Gate to wait on for dispatcher to idle */ struct adreno_dispatcher { struct mutex mutex; Loading @@ -135,6 +136,7 @@ struct adreno_dispatcher { unsigned int tail; struct work_struct work; struct kobject kobj; struct completion idle_gate; }; enum adreno_dispatcher_flags { Loading Loading @@ -192,6 +194,7 @@ struct adreno_device { struct adreno_busy_data busy_data; unsigned int ram_cycles_lo; unsigned int starved_ram_lo; atomic_t halt; }; /** Loading Loading @@ -623,8 +626,7 @@ void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain, void adreno_dispatcher_start(struct kgsl_device *device); int adreno_dispatcher_init(struct adreno_device *adreno_dev); void adreno_dispatcher_close(struct adreno_device *adreno_dev); int adreno_dispatcher_idle(struct adreno_device *adreno_dev, unsigned int timeout); int adreno_dispatcher_idle(struct adreno_device *adreno_dev); void adreno_dispatcher_irq_fault(struct kgsl_device *device); void adreno_dispatcher_stop(struct adreno_device *adreno_dev); Loading Loading @@ -929,7 +931,7 @@ static inline unsigned int adreno_getreg(struct adreno_device *adreno_dev, /** * adreno_gpu_fault() - Return the current state of the GPU * @adreno_dev: A ponter to the adreno_device to query * @adreno_dev: A pointer to the adreno_device to query * * Return 0 if there is no fault or positive with the last type of fault that * occurred Loading @@ -940,6 +942,18 @@ static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev) return atomic_read(&adreno_dev->dispatcher.fault); } /** * adreno_gpu_halt() - Return the halt status of GPU * @adreno_dev: A pointer to the adreno_device to query * * Return the halt request value */ static inline unsigned int adreno_gpu_halt(struct adreno_device *adreno_dev) { smp_rmb(); return atomic_read(&adreno_dev->halt); } /** * adreno_set_gpu_fault() - Set the current fault status of the GPU * @adreno_dev: A pointer to the adreno_device to set Loading @@ -954,6 +968,18 @@ static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev, smp_wmb(); } /** * adreno_set_gpu_halt() - Set the halt request * @adreno_dev: A pointer to the adreno_device to set * @state: Value to set */ static inline void adreno_set_gpu_halt(struct adreno_device *adreno_dev, int state) { atomic_set(&adreno_dev->halt, state); smp_wmb(); } /** * adreno_clear_gpu_fault() - Clear the GPU fault register * @adreno_dev: A pointer to an adreno_device structure Loading
drivers/gpu/msm/adreno_dispatch.c +73 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/err.h> #include "kgsl.h" #include "kgsl_cffdump.h" #include "adreno.h" #include "adreno_ringbuffer.h" #include "adreno_trace.h" Loading Loading @@ -292,6 +293,9 @@ static int sendcmd(struct adreno_device *adreno_dev, struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int ret; if (0 != adreno_gpu_halt(adreno_dev)) return -EINVAL; dispatcher->inflight++; mutex_lock(&device->mutex); Loading @@ -317,9 +321,10 @@ static int sendcmd(struct adreno_device *adreno_dev, */ if (dispatcher->inflight == 1) { if (ret == 0) if (ret == 0) { fault_detect_read(device); else { init_completion(&dispatcher->idle_gate); } else { kgsl_active_count_put(device); clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); } Loading Loading @@ -477,6 +482,9 @@ static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev) if (adreno_gpu_fault(adreno_dev) != 0) break; if (0 != adreno_gpu_halt(adreno_dev)) break; spin_lock(&dispatcher->plist_lock); if (plist_head_empty(&dispatcher->pending)) { Loading Loading @@ -971,6 +979,7 @@ static int dispatcher_do_fault(struct kgsl_device *device) int fault, first = 0; bool pagefault = false; char *state = "failed"; int halt; fault = atomic_xchg(&dispatcher->fault, 0); if (fault == 0) Loading @@ -997,6 +1006,9 @@ static int dispatcher_do_fault(struct kgsl_device *device) mutex_lock(&device->mutex); /* hang opcode */ kgsl_cffdump_hang(device); cmdbatch = dispatcher->cmdqueue[dispatcher->head]; trace_adreno_cmdbatch_fault(cmdbatch, fault); Loading Loading @@ -1220,7 +1232,9 @@ replay: /* Reset the GPU */ mutex_lock(&device->mutex); /* make sure halt is not set during recovery */ halt = adreno_gpu_halt(adreno_dev); adreno_set_gpu_halt(adreno_dev, 0); ret = adreno_reset(device); mutex_unlock(&device->mutex); /* if any other fault got in until reset then ignore */ Loading Loading @@ -1279,6 +1293,8 @@ replay: } kfree(replay); /* restore halt indicator */ adreno_set_gpu_halt(adreno_dev, halt); return 1; } Loading Loading @@ -1480,6 +1496,7 @@ done: } else { /* There is nothing left in the pipeline. Shut 'er down boys */ mutex_lock(&device->mutex); complete_all(&dispatcher->idle_gate); /* * Stop the fault timer before decrementing the active count to * avoid reading the hardware registers while we are trying to Loading Loading @@ -1791,6 +1808,9 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) INIT_WORK(&dispatcher->work, adreno_dispatcher_work); init_completion(&dispatcher->idle_gate); complete_all(&dispatcher->idle_gate); plist_head_init(&dispatcher->pending); spin_lock_init(&dispatcher->plist_lock); Loading @@ -1799,3 +1819,53 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) return ret; } /* * adreno_dispatcher_idle() - Wait for dispatcher to idle * @adreno_dev: Adreno device whose dispatcher needs to idle * * Signal dispatcher to stop sending more commands and complete * the commands that have already been submitted. This function * should not be called when dispatcher mutex is held. */ int adreno_dispatcher_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = &adreno_dev->dev; struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int ret; BUG_ON(!mutex_is_locked(&device->mutex)); if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; /* * Ensure that this function is not called when dispatcher * mutex is held and device is started */ if (mutex_is_locked(&dispatcher->mutex) && dispatcher->mutex.owner == current) BUG_ON(1); adreno_set_gpu_halt(adreno_dev, 1); mutex_unlock(&device->mutex); ret = wait_for_completion_timeout(&dispatcher->idle_gate, msecs_to_jiffies(ADRENO_IDLE_TIMEOUT)); if (ret <= 0) { if (!ret) ret = -ETIMEDOUT; KGSL_DRV_ERR(device, "Dispatcher halt failed %d\n", ret); } else { ret = 0; } mutex_lock(&device->mutex); adreno_set_gpu_halt(adreno_dev, 0); /* * requeue dispatcher work to resubmit pending commands * that may have been blocked due to this idling request */ adreno_dispatcher_schedule(device); return ret; }
drivers/gpu/msm/adreno_ringbuffer.c +6 −4 Original line number Diff line number Diff line Loading @@ -1277,16 +1277,18 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, /* Set the constraints before adding to ringbuffer */ adreno_ringbuffer_set_constraint(device, cmdbatch); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer, drawctxt, flags, &link[0], (cmds - link), cmdbatch->timestamp); /* CFF stuff executed only if CFF is enabled */ kgsl_cffdump_capture_ib_desc(device, context, ibdesc, numibs); kgsl_cff_core_idle(device); kgsl_cffdump_regpoll(device, adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2, 0x00000000, 0x80000000); done: device->pwrctrl.irq_last = 0; trace_kgsl_issueibcmds(device, context->id, cmdbatch, Loading
drivers/gpu/msm/kgsl_cffdump.h +1 −12 Original line number Diff line number Diff line /* Copyright (c) 2010-2011,2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2011,2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -149,15 +149,4 @@ static inline int kgsl_cff_dump_enable_get(void *data, u64 *val) } #endif /* CONFIG_MSM_KGSL_CFF_DUMP */ /* * kgsl_cff_core_idle() - Idle the device if CFF is on * @device: Device whose idle fuunction is called */ static inline void kgsl_cff_core_idle(struct kgsl_device *device) { if (device->cff_dump_enable) device->ftbl->idle(device); } #endif /* __KGSL_CFFDUMP_H */