Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58d27b21 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add the pseudo keepalive bit for preemption"

parents 3c9c65ae 4a288a07
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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 */
+16 −0
Original line number Diff line number Diff line
@@ -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),
+77 −15
Original line number Diff line number Diff line
@@ -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);

@@ -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,
@@ -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;

@@ -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)
+4 −43
Original line number Diff line number Diff line
@@ -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)
{
@@ -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);

		}
	}
+43 −0
Original line number Diff line number Diff line
@@ -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