mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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:
parent
991014f77e
commit
d70af9c9a4
1 changed files with 90 additions and 82 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue