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:
SecureCRT 2012-06-21 00:02:15 +08:00
parent 73aff24078
commit ae32a212a5

View File

@ -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: