Loading drivers/gpu/msm/adreno.h +9 −0 Original line number Diff line number Diff line Loading @@ -625,6 +625,12 @@ enum adreno_regs { ADRENO_REG_CP_PROTECT_REG_0, ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO, ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, ADRENO_REG_RBBM_STATUS, ADRENO_REG_RBBM_STATUS3, ADRENO_REG_RBBM_PERFCTR_CTL, Loading Loading @@ -1911,4 +1917,7 @@ static inline int adreno_vbif_clear_pending_transactions( return ret; } void adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask); #endif /*__ADRENO_H */ drivers/gpu/msm/adreno_a6xx.c +16 −0 Original line number Diff line number Diff line Loading @@ -3070,6 +3070,22 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS, A6XX_RBBM_STATUS), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS3, A6XX_RBBM_STATUS3), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_CTL, A6XX_RBBM_PERFCTR_CNTL), Loading drivers/gpu/msm/adreno_a6xx_preempt.c +77 −15 Original line number Diff line number Diff line Loading @@ -35,6 +35,25 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned int wptr; unsigned long flags; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); /* * Need to make sure GPU is up before we read the * WPTR as fence doesn't wake GPU on read operation. */ if (in_interrupt() == 0) { int status; if (gpudev->oob_set) { status = gpudev->oob_set(adreno_dev, OOB_PREEMPTION_SET_MASK, OOB_PREEMPTION_CHECK_MASK, OOB_PREEMPTION_CLEAR_MASK); if (status) return; } } spin_lock_irqsave(&rb->preempt_lock, flags); Loading @@ -55,6 +74,12 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) msecs_to_jiffies(adreno_drawobj_timeout); spin_unlock_irqrestore(&rb->preempt_lock, flags); if (in_interrupt() == 0) { if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_PREEMPTION_CLEAR_MASK); } } static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev, Loading Loading @@ -275,20 +300,47 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) kgsl_sharedmem_writel(device, &iommu->smmu_info, PREEMPT_SMMU_RECORD(context_idr), contextidr); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, lower_32_bits(next->preemption_desc.gpuaddr)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, upper_32_bits(next->preemption_desc.gpuaddr)); kgsl_sharedmem_readq(&device->scratch, &gpuaddr, SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(next->id)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, lower_32_bits(gpuaddr)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, upper_32_bits(gpuaddr)); /* * Set a keepalive bit before the first preemption register write. * This is required since while each individual write to the context * switch registers will wake the GPU from collapse, it will not in * itself cause GPU activity. Thus, the GPU could technically be * re-collapsed between subsequent register writes leading to a * prolonged preemption sequence. The keepalive bit prevents any * further power collapse while it is set. * It is more efficient to use a keepalive+wake-on-fence approach here * rather than an OOB. Both keepalive and the fence are effectively * free when the GPU is already powered on, whereas an OOB requires an * unconditional handshake with the GMU. */ kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x0, 0x2); /* * Fenced writes on this path will make sure the GPU is woken up * in case it was power collapsed by the GMU. */ adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, lower_32_bits(next->preemption_desc.gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, upper_32_bits(next->preemption_desc.gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, lower_32_bits(gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, upper_32_bits(gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_dev->next_rb = next; Loading @@ -301,10 +353,20 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED); /* Trigger the preemption */ adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, ((preempt_level << 6) & 0xC0) | adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_PREEMPT, (((preempt_level << 6) & 0xC0) | ((skipsaverestore << 9) & 0x200) | ((usesgmem << 8) & 0x100) | 0x1); ((usesgmem << 8) & 0x100) | 0x1), FENCE_STATUS_WRITEDROPPED1_MASK); /* * Once preemption has been requested with the final register write, * the preemption process starts and the GPU is considered busy. * We can now safely clear the preemption keepalive bit, allowing * power collapse to resume its regular activity. */ kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0); } void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit) Loading drivers/gpu/msm/adreno_ringbuffer.c +4 −43 Original line number Diff line number Diff line Loading @@ -80,44 +80,6 @@ static void adreno_get_submit_time(struct adreno_device *adreno_dev, local_irq_restore(flags); } /* * Wait time before trying to write the register again. * Hopefully the GMU has finished waking up during this delay. * This delay must be less than the IFPC main hysteresis or * the GMU will start shutting down before we try again. */ #define GMU_WAKEUP_DELAY 10 /* Max amount of tries to wake up the GMU. */ #define GMU_WAKEUP_RETRY_MAX 60 /* * Check the WRITEDROPPED0 bit in the * FENCE_STATUS regsiter to check if the write went * through. If it didn't then we retry the write. */ static inline void _gmu_wptr_update_if_dropped(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { unsigned int val, i; for (i = 0; i < GMU_WAKEUP_RETRY_MAX; i++) { adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, &val); /* If !writedropped, then wptr update was successful */ if (!(val & 0x1)) return; /* Wait a small amount of time before trying again */ udelay(GMU_WAKEUP_DELAY); /* Try to write WPTR again */ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr); } dev_err(adreno_dev->dev.dev, "GMU WPTR update timed out\n"); } static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { Loading @@ -132,15 +94,14 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, * been submitted. */ kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr); /* * If GMU, ensure the write posted after a possible * Ensure the write posted after a possible * GMU wakeup (write could have dropped during wakeup) */ if (kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) _gmu_wptr_update_if_dropped(adreno_dev, rb); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr, FENCE_STATUS_WRITEDROPPED0_MASK); } } Loading drivers/gpu/msm/kgsl_gmu.c +43 −0 Original line number Diff line number Diff line Loading @@ -1620,3 +1620,46 @@ void gmu_remove(struct kgsl_device *device) device->gmu.pdev = NULL; } /* * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled * @adreno_dev: Pointer to the Adreno device device that owns the GMU * @offset: 32bit register enum that is to be written * @val: The value to be written to the register * @fence_mask: The value to poll the fence status register * * Check the WRITEDROPPED0/1 bit in the FENCE_STATUS regsiter to check if * the write to the fenced register went through. If it didn't then we retry * the write until it goes through or we time out. */ void adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask) { unsigned int status, i; adreno_writereg(adreno_dev, offset, val); if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) return; for (i = 0; i < GMU_WAKEUP_RETRY_MAX; i++) { adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, &status); /* * If !writedropped0/1, then the write to fenced register * was successful */ if (!(status & fence_mask)) return; /* Wait a small amount of time before trying again */ udelay(GMU_WAKEUP_DELAY_US); /* Try to write the fenced register again */ adreno_writereg(adreno_dev, offset, val); } dev_err(adreno_dev->dev.dev, "GMU fenced register write timed out: reg %x\n", offset); } Loading
drivers/gpu/msm/adreno.h +9 −0 Original line number Diff line number Diff line Loading @@ -625,6 +625,12 @@ enum adreno_regs { ADRENO_REG_CP_PROTECT_REG_0, ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO, ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, ADRENO_REG_RBBM_STATUS, ADRENO_REG_RBBM_STATUS3, ADRENO_REG_RBBM_PERFCTR_CTL, Loading Loading @@ -1911,4 +1917,7 @@ static inline int adreno_vbif_clear_pending_transactions( return ret; } void adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask); #endif /*__ADRENO_H */
drivers/gpu/msm/adreno_a6xx.c +16 −0 Original line number Diff line number Diff line Loading @@ -3070,6 +3070,22 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, A6XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_LO), ADRENO_REG_DEFINE( ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_PRIV_SECURE_RESTORE_ADDR_HI), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO), ADRENO_REG_DEFINE(ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS, A6XX_RBBM_STATUS), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_STATUS3, A6XX_RBBM_STATUS3), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_CTL, A6XX_RBBM_PERFCTR_CNTL), Loading
drivers/gpu/msm/adreno_a6xx_preempt.c +77 −15 Original line number Diff line number Diff line Loading @@ -35,6 +35,25 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned int wptr; unsigned long flags; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); /* * Need to make sure GPU is up before we read the * WPTR as fence doesn't wake GPU on read operation. */ if (in_interrupt() == 0) { int status; if (gpudev->oob_set) { status = gpudev->oob_set(adreno_dev, OOB_PREEMPTION_SET_MASK, OOB_PREEMPTION_CHECK_MASK, OOB_PREEMPTION_CLEAR_MASK); if (status) return; } } spin_lock_irqsave(&rb->preempt_lock, flags); Loading @@ -55,6 +74,12 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) msecs_to_jiffies(adreno_drawobj_timeout); spin_unlock_irqrestore(&rb->preempt_lock, flags); if (in_interrupt() == 0) { if (gpudev->oob_clear) gpudev->oob_clear(adreno_dev, OOB_PREEMPTION_CLEAR_MASK); } } static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev, Loading Loading @@ -275,20 +300,47 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) kgsl_sharedmem_writel(device, &iommu->smmu_info, PREEMPT_SMMU_RECORD(context_idr), contextidr); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, lower_32_bits(next->preemption_desc.gpuaddr)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, upper_32_bits(next->preemption_desc.gpuaddr)); kgsl_sharedmem_readq(&device->scratch, &gpuaddr, SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(next->id)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, lower_32_bits(gpuaddr)); kgsl_regwrite(device, A6XX_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, upper_32_bits(gpuaddr)); /* * Set a keepalive bit before the first preemption register write. * This is required since while each individual write to the context * switch registers will wake the GPU from collapse, it will not in * itself cause GPU activity. Thus, the GPU could technically be * re-collapsed between subsequent register writes leading to a * prolonged preemption sequence. The keepalive bit prevents any * further power collapse while it is set. * It is more efficient to use a keepalive+wake-on-fence approach here * rather than an OOB. Both keepalive and the fence are effectively * free when the GPU is already powered on, whereas an OOB requires an * unconditional handshake with the GMU. */ kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x0, 0x2); /* * Fenced writes on this path will make sure the GPU is woken up * in case it was power collapsed by the GMU. */ adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_LO, lower_32_bits(next->preemption_desc.gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR_HI, upper_32_bits(next->preemption_desc.gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_LO, lower_32_bits(gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_CONTEXT_SWITCH_NON_PRIV_RESTORE_ADDR_HI, upper_32_bits(gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); adreno_dev->next_rb = next; Loading @@ -301,10 +353,20 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED); /* Trigger the preemption */ adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, ((preempt_level << 6) & 0xC0) | adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_PREEMPT, (((preempt_level << 6) & 0xC0) | ((skipsaverestore << 9) & 0x200) | ((usesgmem << 8) & 0x100) | 0x1); ((usesgmem << 8) & 0x100) | 0x1), FENCE_STATUS_WRITEDROPPED1_MASK); /* * Once preemption has been requested with the final register write, * the preemption process starts and the GPU is considered busy. * We can now safely clear the preemption keepalive bit, allowing * power collapse to resume its regular activity. */ kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0); } void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit) Loading
drivers/gpu/msm/adreno_ringbuffer.c +4 −43 Original line number Diff line number Diff line Loading @@ -80,44 +80,6 @@ static void adreno_get_submit_time(struct adreno_device *adreno_dev, local_irq_restore(flags); } /* * Wait time before trying to write the register again. * Hopefully the GMU has finished waking up during this delay. * This delay must be less than the IFPC main hysteresis or * the GMU will start shutting down before we try again. */ #define GMU_WAKEUP_DELAY 10 /* Max amount of tries to wake up the GMU. */ #define GMU_WAKEUP_RETRY_MAX 60 /* * Check the WRITEDROPPED0 bit in the * FENCE_STATUS regsiter to check if the write went * through. If it didn't then we retry the write. */ static inline void _gmu_wptr_update_if_dropped(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { unsigned int val, i; for (i = 0; i < GMU_WAKEUP_RETRY_MAX; i++) { adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, &val); /* If !writedropped, then wptr update was successful */ if (!(val & 0x1)) return; /* Wait a small amount of time before trying again */ udelay(GMU_WAKEUP_DELAY); /* Try to write WPTR again */ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr); } dev_err(adreno_dev->dev.dev, "GMU WPTR update timed out\n"); } static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { Loading @@ -132,15 +94,14 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, * been submitted. */ kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr); /* * If GMU, ensure the write posted after a possible * Ensure the write posted after a possible * GMU wakeup (write could have dropped during wakeup) */ if (kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) _gmu_wptr_update_if_dropped(adreno_dev, rb); adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr, FENCE_STATUS_WRITEDROPPED0_MASK); } } Loading
drivers/gpu/msm/kgsl_gmu.c +43 −0 Original line number Diff line number Diff line Loading @@ -1620,3 +1620,46 @@ void gmu_remove(struct kgsl_device *device) device->gmu.pdev = NULL; } /* * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled * @adreno_dev: Pointer to the Adreno device device that owns the GMU * @offset: 32bit register enum that is to be written * @val: The value to be written to the register * @fence_mask: The value to poll the fence status register * * Check the WRITEDROPPED0/1 bit in the FENCE_STATUS regsiter to check if * the write to the fenced register went through. If it didn't then we retry * the write until it goes through or we time out. */ void adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask) { unsigned int status, i; adreno_writereg(adreno_dev, offset, val); if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) return; for (i = 0; i < GMU_WAKEUP_RETRY_MAX; i++) { adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, &status); /* * If !writedropped0/1, then the write to fenced register * was successful */ if (!(status & fence_mask)) return; /* Wait a small amount of time before trying again */ udelay(GMU_WAKEUP_DELAY_US); /* Try to write the fenced register again */ adreno_writereg(adreno_dev, offset, val); } dev_err(adreno_dev->dev.dev, "GMU fenced register write timed out: reg %x\n", offset); }