msm: kgsl: fix error handling in adreno_waittimestamp()
This function was incorrectly reporting hangs when an error such as ERESTARTSYS was returned by __wait_event_interruptible_timeout(). msm: kgsl: Make sure WPTR reg is updated properly Sometimes writes to WPTR register do not take effect, causing a 3D core hang. Make sure the WPTR is updated properly when waiting. msm: kgsl: Set default value of wait_timeout in the adreno_dev struct Set the initalization value of wait_timeout at compile time in the declaration of the adreno_device struct instead of at runtime in adreno_probe.
This commit is contained in:
		| @@ -120,6 +120,7 @@ static struct adreno_device device_3d0 = { | ||||
| 	}, | ||||
| 	.pfp_fw = NULL, | ||||
| 	.pm4_fw = NULL, | ||||
| 	.wait_timeout = 10000, /* in milliseconds */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
| @@ -432,8 +433,6 @@ adreno_probe(struct platform_device *pdev) | ||||
| 	adreno_dev = ADRENO_DEVICE(device); | ||||
| 	device->parentdev = &pdev->dev; | ||||
|  | ||||
| 	adreno_dev->wait_timeout = 10000; /* default value in milliseconds */ | ||||
|  | ||||
| 	init_completion(&device->recovery_gate); | ||||
|  | ||||
| 	status = adreno_ringbuffer_init(device); | ||||
| @@ -834,6 +833,12 @@ static int adreno_getproperty(struct kgsl_device *device, | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static inline void adreno_poke(struct kgsl_device *device) | ||||
| { | ||||
| 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device); | ||||
| 	adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr); | ||||
| } | ||||
|  | ||||
| /* Caller must hold the device mutex. */ | ||||
| int adreno_idle(struct kgsl_device *device, unsigned int timeout) | ||||
| { | ||||
| @@ -852,6 +857,7 @@ int adreno_idle(struct kgsl_device *device, unsigned int timeout) | ||||
| retry: | ||||
| 	if (rb->flags & KGSL_FLAGS_STARTED) { | ||||
| 		do { | ||||
| 			adreno_poke(device); | ||||
| 			GSL_RB_GET_READPTR(rb, &rb->rptr); | ||||
| 			if (time_after(jiffies, wait_time)) { | ||||
| 				KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n", | ||||
| @@ -1111,8 +1117,12 @@ static int adreno_waittimestamp(struct kgsl_device *device, | ||||
| { | ||||
| 	long status = 0; | ||||
| 	uint io = 1; | ||||
| 	static uint io_cnt; | ||||
| 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device); | ||||
| 	struct kgsl_pwrctrl *pwr = &device->pwrctrl; | ||||
| 	int retries; | ||||
| 	unsigned int msecs_first; | ||||
| 	unsigned int msecs_part; | ||||
|  | ||||
| 	/* Don't wait forever, set a max value for now */ | ||||
| 	if (msecs == -1) | ||||
| @@ -1125,26 +1135,45 @@ static int adreno_waittimestamp(struct kgsl_device *device, | ||||
| 		status = -EINVAL; | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* Keep the first timeout as 100msecs before rewriting | ||||
| 	 * the WPTR. Less visible impact if the WPTR has not | ||||
| 	 * been updated properly. | ||||
| 	 */ | ||||
| 	msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100; | ||||
| 	msecs_part = (msecs - msecs_first + 3) / 4; | ||||
| 	for (retries = 0; retries < 5; retries++) { | ||||
| 	if (!kgsl_check_timestamp(device, timestamp)) { | ||||
| 		if (pwr->active_pwrlevel) { | ||||
| 			int low_pwrlevel = pwr->num_pwrlevels - | ||||
| 					KGSL_PWRLEVEL_LOW_OFFSET; | ||||
| 			if (pwr->active_pwrlevel == low_pwrlevel) | ||||
| 				io = 0; | ||||
| 		} | ||||
| 			adreno_poke(device); | ||||
| //          the QSD8X50 don't support io_fraction ?? // SecureCRT 2012-06-20 | ||||
| //			io_cnt = (io_cnt + 1) % 100; | ||||
| //			if (io_cnt < | ||||
| //				pwr->pwrlevels[pwr->active_pwrlevel]. | ||||
| //					io_fraction) | ||||
| //				io = 0; | ||||
| 		mutex_unlock(&device->mutex); | ||||
| 		/* We need to make sure that the process is placed in wait-q | ||||
| 		 * before its condition is called */ | ||||
| 			/* We need to make sure that the process is | ||||
| 			 * placed in wait-q before its condition is called | ||||
| 			 */ | ||||
| 		status = kgsl_wait_event_interruptible_timeout( | ||||
| 				device->wait_queue, | ||||
| 				kgsl_check_interrupt_timestamp(device, | ||||
| 					timestamp), | ||||
| 				msecs_to_jiffies(msecs), io); | ||||
| 					msecs_to_jiffies(retries ? | ||||
| 						msecs_part : msecs_first), io); | ||||
| 		mutex_lock(&device->mutex); | ||||
|  | ||||
| 		if (status > 0) | ||||
| 			status = 0; | ||||
| 		else if (status == 0) { | ||||
| 			if (status > 0) { | ||||
|                                 /*completed before the wait finished */ | ||||
| 			        status = 0; | ||||
| 				goto done; | ||||
|                         } else if (status < 0) { | ||||
|                                /*an error occurred*/ | ||||
|                                 goto done; | ||||
|                         } | ||||
|                         /*this wait timed out*/ | ||||
| 		} | ||||
| 	} | ||||
| 			if (!kgsl_check_timestamp(device, timestamp)) { | ||||
| 				status = -ETIMEDOUT; | ||||
| 				KGSL_DRV_ERR(device, | ||||
| @@ -1162,8 +1191,8 @@ static int adreno_waittimestamp(struct kgsl_device *device, | ||||
| 						KGSL_TIMEOUT_DEFAULT)) | ||||
| 						status = 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		status = 0; | ||||
| 	} | ||||
|  | ||||
| done: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user