msm: kgsl: Create a separate function to extract valid commands

Create a separate function that extracts valid commands from good
contexts and invalid commands from bad contexts during recovery

Change-Id: Icffe34821c1b70ca1a8c1a8e13a0b7e23d0ec193
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
This commit is contained in:
Shubhraprakash Das 2012-05-31 18:28:22 -06:00 committed by Stephen Boyd
parent 991014f77e
commit d70af9c9a4

View file

@ -946,19 +946,97 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
return 0;
}
static void _copy_valid_rb_content(struct adreno_ringbuffer *rb,
unsigned int rb_rptr, unsigned int *temp_rb_buffer,
int *rb_size, unsigned int *bad_rb_buffer,
int *bad_rb_size,
int *last_valid_ctx_id)
{
unsigned int good_rb_idx = 0, cmd_start_idx = 0;
unsigned int val1 = 0;
struct kgsl_context *k_ctxt;
struct adreno_context *a_ctxt;
unsigned int bad_rb_idx = 0;
int copy_rb_contents = 0;
unsigned int temp_rb_rptr;
unsigned int size = rb->buffer_desc.size;
unsigned int good_cmd_start_idx = 0;
/* Walk the rb from the context switch. Omit any commands
* for an invalid context. */
while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
if (KGSL_CMD_IDENTIFIER == val1) {
/* Start is the NOP dword that comes before
* KGSL_CMD_IDENTIFIER */
cmd_start_idx = bad_rb_idx - 1;
if (copy_rb_contents)
good_cmd_start_idx = good_rb_idx - 1;
}
/* check for context switch indicator */
if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
unsigned int temp_idx, val2;
/* increment by 3 to get to the context_id */
temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
size;
kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
temp_rb_rptr);
/* if context switches to a context that did not cause
* hang then start saving the rb contents as those
* commands can be executed */
k_ctxt = idr_find(&rb->device->context_idr, val2);
if (k_ctxt) {
a_ctxt = k_ctxt->devctxt;
/* If we are changing to a good context and were not
* copying commands then copy over commands to the good
* context */
if (!copy_rb_contents && ((k_ctxt &&
!(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
!k_ctxt)) {
for (temp_idx = cmd_start_idx;
temp_idx < bad_rb_idx;
temp_idx++)
temp_rb_buffer[good_rb_idx++] =
bad_rb_buffer[temp_idx];
*last_valid_ctx_id = val2;
copy_rb_contents = 1;
} else if (copy_rb_contents && k_ctxt &&
(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
/* If we are changing to bad context then remove
* the dwords we copied for this sequence from
* the good buffer */
good_rb_idx = good_cmd_start_idx;
copy_rb_contents = 0;
}
}
}
if (copy_rb_contents)
temp_rb_buffer[good_rb_idx++] = val1;
/* Copy both good and bad commands for replay to the bad
* buffer */
bad_rb_buffer[bad_rb_idx++] = val1;
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
}
*rb_size = good_rb_idx;
*bad_rb_size = bad_rb_idx;
}
int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
struct adreno_recovery_data *rec_data)
{
struct kgsl_device *device = rb->device;
unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
unsigned int temp_idx = 0;
unsigned int value;
unsigned int val1;
unsigned int val2;
unsigned int val3;
unsigned int copy_rb_contents = 0;
struct kgsl_context *context;
unsigned int *temp_rb_buffer = rec_data->rb_buffer;
KGSL_DRV_ERR(device, "Last context id: %d\n", rec_data->context_id);
context = idr_find(&device->context_idr, rec_data->context_id);
@ -1032,86 +1110,16 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
" successful timestamp is overwritten\n");
return -EINVAL;
}
/* rb_rptr is now pointing to the first dword of the command following
* the last sucessfully executed command sequence. Assumption is that
* GPU is hung in the command sequence pointed by rb_rptr */
/* make sure the GPU is not hung in a command submitted by kgsl
* itself */
kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size));
if (val1 == cp_nop_packet(1) && val2 == KGSL_CMD_IDENTIFIER) {
KGSL_DRV_ERR(device,
"GPU recovery from hang not possible because "
"of hang in kgsl command\n");
return -EINVAL;
}
while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
/* check for context switch indicator */
if (value == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
BUG_ON(value != cp_type3_packet(CP_MEM_WRITE, 2));
kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
BUG_ON(val1 != (device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context)));
kgsl_sharedmem_readl(&rb->buffer_desc, &value, rb_rptr);
rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr,
rb->buffer_desc.size);
/*
* If other context switches were already lost and
* and the current context is the one that is hanging,
* then we cannot recover. Print an error message
* and leave.
*/
if ((copy_rb_contents == 0) && (value ==
rec_data->context_id)) {
KGSL_DRV_ERR(device, "GPU recovery could not "
"find the previous context\n");
return -EINVAL;
}
/*
* If we were copying the commands and got to this point
* then we need to remove the 3 commands that appear
* before KGSL_CONTEXT_TO_MEM_IDENTIFIER
*/
if (temp_idx)
temp_idx -= 3;
/* if context switches to a context that did not cause
* hang then start saving the rb contents as those
* commands can be executed */
if (value != rec_data->context_id) {
copy_rb_contents = 1;
temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
temp_rb_buffer[temp_idx++] =
KGSL_CMD_IDENTIFIER;
temp_rb_buffer[temp_idx++] = cp_nop_packet(1);
temp_rb_buffer[temp_idx++] =
KGSL_CONTEXT_TO_MEM_IDENTIFIER;
temp_rb_buffer[temp_idx++] =
cp_type3_packet(CP_MEM_WRITE, 2);
temp_rb_buffer[temp_idx++] = val1;
temp_rb_buffer[temp_idx++] = value;
} else {
copy_rb_contents = 0;
}
} else if (copy_rb_contents)
temp_rb_buffer[temp_idx++] = value;
}
rec_data->rb_size = temp_idx;
KGSL_DRV_ERR(rb->device, "Hang recovery start: %x\n", rb_rptr / 4);
_copy_valid_rb_content(rb, rb_rptr, rec_data->rb_buffer,
&rec_data->rb_size,
rec_data->bad_rb_buffer,
&rec_data->bad_rb_size,
&rec_data->last_valid_ctx_id);
/* Do not replay bad commands until we change the code to
* handle this in adreno.c */
rec_data->bad_rb_size = 0;
return 0;
}