msm: kgsl: Don't silently ignore events that have a retired timestamp

After all the current events are processed in the main loop, the next
pending event is marked to fire an interrupt to start the cycle anew.
When the event is marked, we check the timestamp again to make sure that
we are always caught up with the GPU.  If the timestamp for the next
event happens to be retired when we get to this point, we silently leave
the function.

If there are no other subsequent events or waittimestamp requests, then
it is possible that another interrupt might never be fired for that context
and then the event gets missed.  Return a 1 in this case all the way back
up the stack and make the event code keep processing events until we are
positive that none are past.

Change-Id: I5a770e7f06612e1aecbfe2e8ccbfeebdab3fc9fc
CRs-Fixed: 441191
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
Jordan Crouse 2013-01-28 16:58:45 -07:00 committed by Iliyan Malchev
parent 07531fbafe
commit 6ded9eb5ac
3 changed files with 27 additions and 10 deletions

View file

@ -2620,10 +2620,11 @@ static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
return 0;
}
static void adreno_next_event(struct kgsl_device *device,
/* Return 1 if the event timestmp has already passed, 0 if it was marked */
static int adreno_next_event(struct kgsl_device *device,
struct kgsl_event *event)
{
adreno_check_hw_ts(device, event->context, event->timestamp);
return adreno_check_hw_ts(device, event->context, event->timestamp);
}
static int adreno_check_interrupt_timestamp(struct kgsl_device *device,

View file

@ -114,7 +114,7 @@ struct kgsl_functable {
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*postmortem_dump) (struct kgsl_device *device, int manual);
void (*next_event)(struct kgsl_device *device,
int (*next_event)(struct kgsl_device *device,
struct kgsl_event *event);
};

View file

@ -218,27 +218,43 @@ static void _process_event_list(struct kgsl_device *device,
}
}
static inline void _mark_next_event(struct kgsl_device *device,
static inline int _mark_next_event(struct kgsl_device *device,
struct list_head *head)
{
struct kgsl_event *event;
if (!list_empty(head)) {
event = list_first_entry(head, struct kgsl_event, list);
device->ftbl->next_event(device, event);
/*
* Next event will return 0 if the event was marked or 1 if the
* timestamp on the event has passed - return that up a layer
*/
return device->ftbl->next_event(device, event);
}
return 0;
}
static int kgsl_process_context_events(struct kgsl_device *device,
struct kgsl_context *context)
{
unsigned int timestamp = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
while (1) {
unsigned int timestamp = kgsl_readtimestamp(device, context,
KGSL_TIMESTAMP_RETIRED);
_process_event_list(device, &context->events, timestamp);
_process_event_list(device, &context->events, timestamp);
/* Mark the next pending event on the list to fire an interrupt */
_mark_next_event(device, &context->events);
/*
* _mark_next event will return 1 as long as the next event
* timestamp has expired - this is to cope with an unavoidable
* race condition with the GPU that is still processing events.
*/
if (!_mark_next_event(device, &context->events))
break;
}
/*
* Return 0 if the list is empty so the calling function can remove the