msm: kgsl: rework ib checking
Separate ib parse checking from cffdump as it is useful in other situations. This is controlled by a new debugfs file, ib_check. All ib checking is off (0) by default, because parsing and mem_entry lookup can have a performance impact on some benchmarks. Level 1 checking verifies the IB1's. Level 2 checking also verifies the IB2.
This commit is contained in:
parent
d842173fc6
commit
c6e8ee54ff
@ -122,8 +122,10 @@ static struct adreno_device device_3d0 = {
|
||||
.pfp_fw = NULL,
|
||||
.pm4_fw = NULL,
|
||||
.wait_timeout = 10000, /* in milliseconds */
|
||||
.ib_check_level = 0,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This is the master list of all GPU cores that are supported by this
|
||||
* driver.
|
||||
|
@ -75,6 +75,7 @@ struct adreno_device {
|
||||
unsigned int istore_size;
|
||||
unsigned int pix_shader_start;
|
||||
unsigned int instruction_size;
|
||||
unsigned int ib_check_level;
|
||||
};
|
||||
|
||||
struct adreno_gpudev {
|
||||
|
@ -444,6 +444,8 @@ void adreno_debugfs_init(struct kgsl_device *device)
|
||||
&kgsl_cff_dump_enable_fops);
|
||||
debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
|
||||
&adreno_dev->wait_timeout);
|
||||
debugfs_create_u32("ib_check", 0644, device->d_debugfs,
|
||||
&adreno_dev->ib_check_level);
|
||||
|
||||
/* Create post mortem control files */
|
||||
|
||||
|
@ -29,11 +29,6 @@
|
||||
/* skip N 32-bit words to get to the next packet */
|
||||
#define CP_NOP 0x10
|
||||
|
||||
/* indirect buffer dispatch. prefetch parser uses this packet type to determine
|
||||
* whether to pre-fetch the IB
|
||||
*/
|
||||
#define CP_INDIRECT_BUFFER 0x3f
|
||||
|
||||
/* indirect buffer dispatch. same as IB, but init is pipelined */
|
||||
#define CP_INDIRECT_BUFFER_PFD 0x37
|
||||
|
||||
@ -117,6 +112,9 @@
|
||||
/* load constants from a location in memory */
|
||||
#define CP_LOAD_CONSTANT_CONTEXT 0x2e
|
||||
|
||||
/* (A2x) sets binning configuration registers */
|
||||
#define CP_SET_BIN_DATA 0x2f
|
||||
|
||||
/* selective invalidation of state pointers */
|
||||
#define CP_INVALIDATE_STATE 0x3b
|
||||
|
||||
@ -197,11 +195,20 @@
|
||||
#define cp_nop_packet(cnt) \
|
||||
(CP_TYPE3_PKT | (((cnt)-1) << 16) | (CP_NOP << 8))
|
||||
|
||||
#define pkt_is_type0(pkt) (((pkt) & 0XC0000000) == CP_TYPE0_PKT)
|
||||
|
||||
#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
|
||||
|
||||
#define pkt_is_type3(pkt) (((pkt) & 0xC0000000) == CP_TYPE3_PKT)
|
||||
|
||||
#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
|
||||
#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
|
||||
/* packet headers */
|
||||
#define CP_HDR_ME_INIT cp_type3_packet(CP_ME_INIT, 18)
|
||||
#define CP_HDR_INDIRECT_BUFFER_PFD cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)
|
||||
#define CP_HDR_INDIRECT_BUFFER cp_type3_packet(CP_INDIRECT_BUFFER, 2)
|
||||
#define CP_HDR_INDIRECT_BUFFER_PFE cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2)
|
||||
|
||||
/* dword base address of the GFX decode space */
|
||||
#define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000)))
|
||||
|
@ -52,7 +52,7 @@ static const struct pm_id_name pm3_types[] = {
|
||||
{CP_IM_LOAD, "IN__LOAD"},
|
||||
{CP_IM_LOAD_IMMEDIATE, "IM_LOADI"},
|
||||
{CP_IM_STORE, "IM_STORE"},
|
||||
{CP_INDIRECT_BUFFER, "IND_BUF_"},
|
||||
{CP_INDIRECT_BUFFER_PFE, "IND_BUF_"},
|
||||
{CP_INDIRECT_BUFFER_PFD, "IND_BUFP"},
|
||||
{CP_INTERRUPT, "PM4_INTR"},
|
||||
{CP_INVALIDATE_STATE, "INV_STAT"},
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "adreno.h"
|
||||
#include "adreno_pm4types.h"
|
||||
#include "adreno_ringbuffer.h"
|
||||
#include "adreno_debugfs.h"
|
||||
|
||||
#include "a2xx_reg.h"
|
||||
#include "a3xx_reg.h"
|
||||
@ -550,6 +551,198 @@ adreno_ringbuffer_issuecmds(struct kgsl_device *device,
|
||||
adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
|
||||
}
|
||||
|
||||
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
|
||||
int sizedwords);
|
||||
|
||||
static bool
|
||||
_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
|
||||
{
|
||||
unsigned int opcode = cp_type3_opcode(*hostaddr);
|
||||
switch (opcode) {
|
||||
case CP_INDIRECT_BUFFER_PFD:
|
||||
case CP_INDIRECT_BUFFER_PFE:
|
||||
case CP_COND_INDIRECT_BUFFER_PFE:
|
||||
case CP_COND_INDIRECT_BUFFER_PFD:
|
||||
return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
|
||||
case CP_NOP:
|
||||
case CP_WAIT_FOR_IDLE:
|
||||
case CP_WAIT_REG_MEM:
|
||||
case CP_WAIT_REG_EQ:
|
||||
case CP_WAT_REG_GTE:
|
||||
case CP_WAIT_UNTIL_READ:
|
||||
case CP_WAIT_IB_PFD_COMPLETE:
|
||||
case CP_REG_RMW:
|
||||
case CP_REG_TO_MEM:
|
||||
case CP_MEM_WRITE:
|
||||
case CP_MEM_WRITE_CNTR:
|
||||
case CP_COND_EXEC:
|
||||
case CP_COND_WRITE:
|
||||
case CP_EVENT_WRITE:
|
||||
case CP_EVENT_WRITE_SHD:
|
||||
case CP_EVENT_WRITE_CFL:
|
||||
case CP_EVENT_WRITE_ZPD:
|
||||
case CP_DRAW_INDX:
|
||||
case CP_DRAW_INDX_2:
|
||||
case CP_DRAW_INDX_BIN:
|
||||
case CP_DRAW_INDX_2_BIN:
|
||||
case CP_VIZ_QUERY:
|
||||
case CP_SET_STATE:
|
||||
case CP_SET_CONSTANT:
|
||||
case CP_IM_LOAD:
|
||||
case CP_IM_LOAD_IMMEDIATE:
|
||||
case CP_LOAD_CONSTANT_CONTEXT:
|
||||
case CP_INVALIDATE_STATE:
|
||||
case CP_SET_SHADER_BASES:
|
||||
case CP_SET_BIN_MASK:
|
||||
case CP_SET_BIN_SELECT:
|
||||
case CP_SET_BIN_BASE_OFFSET:
|
||||
case CP_SET_BIN_DATA:
|
||||
case CP_CONTEXT_UPDATE:
|
||||
case CP_INTERRUPT:
|
||||
case CP_IM_STORE:
|
||||
case CP_LOAD_STATE:
|
||||
break;
|
||||
/* these shouldn't come from userspace */
|
||||
case CP_ME_INIT:
|
||||
case CP_SET_PROTECTED_MODE:
|
||||
default:
|
||||
KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
|
||||
{
|
||||
unsigned int reg = type0_pkt_offset(*hostaddr);
|
||||
unsigned int cnt = type0_pkt_size(*hostaddr);
|
||||
if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
|
||||
KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
|
||||
reg, cnt);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse IBs and dump them to test vector. Detect swap by inspecting
|
||||
* register writes, keeping note of the current state, and dump
|
||||
* framebuffer config to test vector
|
||||
*/
|
||||
static bool _parse_ibs(struct kgsl_device_private *dev_priv,
|
||||
uint gpuaddr, int sizedwords)
|
||||
{
|
||||
static uint level; /* recursion level */
|
||||
bool ret = false;
|
||||
uint *hostaddr, *hoststart;
|
||||
int dwords_left = sizedwords; /* dwords left in the current command
|
||||
buffer */
|
||||
struct kgsl_mem_entry *entry;
|
||||
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
gpuaddr, sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"no mapping for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
|
||||
if (hostaddr == NULL) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"no mapping for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hoststart = hostaddr;
|
||||
|
||||
level++;
|
||||
|
||||
KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
|
||||
gpuaddr, sizedwords, hostaddr);
|
||||
|
||||
mb();
|
||||
while (dwords_left > 0) {
|
||||
bool cur_ret = true;
|
||||
int count = 0; /* dword count including packet header */
|
||||
|
||||
switch (*hostaddr >> 30) {
|
||||
case 0x0: /* type-0 */
|
||||
count = (*hostaddr >> 16)+2;
|
||||
cur_ret = _handle_type0(dev_priv, hostaddr);
|
||||
break;
|
||||
case 0x1: /* type-1 */
|
||||
count = 2;
|
||||
break;
|
||||
case 0x3: /* type-3 */
|
||||
count = ((*hostaddr >> 16) & 0x3fff) + 2;
|
||||
cur_ret = _handle_type3(dev_priv, hostaddr);
|
||||
break;
|
||||
default:
|
||||
KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
|
||||
"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
|
||||
*hostaddr >> 30, *hostaddr, hostaddr,
|
||||
gpuaddr+4*(sizedwords-dwords_left));
|
||||
cur_ret = false;
|
||||
count = dwords_left;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cur_ret) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"bad sub-type: #:%d/%d, v:0x%08x"
|
||||
" @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
sizedwords-dwords_left, sizedwords, *hostaddr,
|
||||
hostaddr, gpuaddr+4*(sizedwords-dwords_left),
|
||||
level);
|
||||
|
||||
if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
|
||||
>= 2)
|
||||
print_hex_dump(KERN_ERR,
|
||||
level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* jump to next packet */
|
||||
dwords_left -= count;
|
||||
hostaddr += count;
|
||||
if (dwords_left < 0) {
|
||||
KGSL_CMD_ERR(dev_priv->device,
|
||||
"bad count: c:%d, #:%d/%d, "
|
||||
"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
count, sizedwords-(dwords_left+count),
|
||||
sizedwords, *(hostaddr-count), hostaddr-count,
|
||||
gpuaddr+4*(sizedwords-(dwords_left+count)),
|
||||
level);
|
||||
if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
|
||||
>= 2)
|
||||
print_hex_dump(KERN_ERR,
|
||||
level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
done:
|
||||
if (!ret)
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"parsing failed: gpuaddr:0x%08x, "
|
||||
"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
|
||||
|
||||
level--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_context *context,
|
||||
@ -608,9 +801,12 @@ adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
*cmds++ = ibdesc[0].sizedwords;
|
||||
}
|
||||
for (i = start_index; i < numibs; i++) {
|
||||
(void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
|
||||
|
||||
if (unlikely(adreno_dev->ib_check_level >= 1 &&
|
||||
!_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords))) {
|
||||
kfree(link);
|
||||
return -EINVAL;
|
||||
}
|
||||
*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
|
||||
*cmds++ = ibdesc[i].gpuaddr;
|
||||
*cmds++ = ibdesc[i].sizedwords;
|
||||
@ -660,7 +856,6 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
unsigned int val3;
|
||||
unsigned int copy_rb_contents = 0;
|
||||
unsigned int cur_context;
|
||||
unsigned int j;
|
||||
|
||||
GSL_RB_GET_READPTR(rb, &rb->rptr);
|
||||
|
||||
@ -811,19 +1006,6 @@ int adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
|
||||
}
|
||||
|
||||
*rb_size = temp_idx;
|
||||
KGSL_DRV_ERR(device, "Extracted rb contents, size: %x\n", *rb_size);
|
||||
for (temp_idx = 0; temp_idx < *rb_size;) {
|
||||
char str[80];
|
||||
int idx = 0;
|
||||
if ((temp_idx + 8) <= *rb_size)
|
||||
j = 8;
|
||||
else
|
||||
j = *rb_size - temp_idx;
|
||||
for (; j != 0; j--)
|
||||
idx += scnprintf(str + idx, 80 - idx,
|
||||
"%8.8X ", temp_rb_buffer[temp_idx++]);
|
||||
printk(KERN_ALERT "%s", str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -909,40 +909,6 @@ static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
|
||||
|
||||
return result;
|
||||
}
|
||||
static bool check_ibdesc(struct kgsl_device_private *dev_priv,
|
||||
struct kgsl_ibdesc *ibdesc, unsigned int numibs,
|
||||
bool parse)
|
||||
{
|
||||
bool result = true;
|
||||
unsigned int i;
|
||||
for (i = 0; i < numibs; i++) {
|
||||
struct kgsl_mem_entry *entry;
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"invalid cmd buffer gpuaddr %08x " \
|
||||
"sizedwords %d\n", ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (parse && !kgsl_cffdump_parse_ibs(dev_priv, &entry->memdesc,
|
||||
ibdesc[i].gpuaddr, ibdesc[i].sizedwords, true)) {
|
||||
KGSL_DRV_ERR(dev_priv->device,
|
||||
"invalid cmd buffer gpuaddr %08x " \
|
||||
"sizedwords %d numibs %d/%d\n",
|
||||
ibdesc[i].gpuaddr,
|
||||
ibdesc[i].sizedwords, i+1, numibs);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
@ -1012,12 +978,6 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
param->numibs = 1;
|
||||
}
|
||||
|
||||
if (!check_ibdesc(dev_priv, ibdesc, param->numibs, true)) {
|
||||
KGSL_DRV_ERR(dev_priv->device, "bad ibdesc");
|
||||
result = -EINVAL;
|
||||
goto free_ibdesc;
|
||||
}
|
||||
|
||||
result = dev_priv->device->ftbl->issueibcmds(dev_priv,
|
||||
context,
|
||||
ibdesc,
|
||||
@ -1025,17 +985,6 @@ static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
¶m->timestamp,
|
||||
param->flags);
|
||||
|
||||
if (result != 0)
|
||||
goto free_ibdesc;
|
||||
|
||||
/* this is a check to try to detect if a command buffer was freed
|
||||
* during issueibcmds().
|
||||
*/
|
||||
if (!check_ibdesc(dev_priv, ibdesc, param->numibs, false)) {
|
||||
KGSL_DRV_ERR(dev_priv->device, "bad ibdesc AFTER issue");
|
||||
result = -EINVAL;
|
||||
goto free_ibdesc;
|
||||
}
|
||||
|
||||
free_ibdesc:
|
||||
kfree(ibdesc);
|
||||
|
@ -497,195 +497,6 @@ int kgsl_cffdump_waitirq(void)
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_cffdump_waitirq);
|
||||
|
||||
#define ADDRESS_STACK_SIZE 256
|
||||
#define GET_PM4_TYPE3_OPCODE(x) ((*(x) >> 8) & 0xFF)
|
||||
static unsigned int kgsl_cffdump_addr_count;
|
||||
|
||||
static bool kgsl_cffdump_handle_type3(struct kgsl_device_private *dev_priv,
|
||||
uint *hostaddr, bool check_only)
|
||||
{
|
||||
static uint addr_stack[ADDRESS_STACK_SIZE];
|
||||
static uint size_stack[ADDRESS_STACK_SIZE];
|
||||
|
||||
switch (GET_PM4_TYPE3_OPCODE(hostaddr)) {
|
||||
case CP_INDIRECT_BUFFER_PFD:
|
||||
case CP_INDIRECT_BUFFER:
|
||||
{
|
||||
/* traverse indirect buffers */
|
||||
int i;
|
||||
uint ibaddr = hostaddr[1];
|
||||
uint ibsize = hostaddr[2];
|
||||
|
||||
/* is this address already in encountered? */
|
||||
for (i = 0;
|
||||
i < kgsl_cffdump_addr_count && addr_stack[i] != ibaddr;
|
||||
++i)
|
||||
;
|
||||
|
||||
if (kgsl_cffdump_addr_count == i) {
|
||||
addr_stack[kgsl_cffdump_addr_count] = ibaddr;
|
||||
size_stack[kgsl_cffdump_addr_count++] = ibsize;
|
||||
|
||||
if (kgsl_cffdump_addr_count >= ADDRESS_STACK_SIZE) {
|
||||
KGSL_CORE_ERR("stack overflow\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return kgsl_cffdump_parse_ibs(dev_priv, NULL,
|
||||
ibaddr, ibsize, check_only);
|
||||
} else if (size_stack[i] != ibsize) {
|
||||
KGSL_CORE_ERR("gpuaddr: 0x%08x, "
|
||||
"wc: %u, with size wc: %u already on the "
|
||||
"stack\n", ibaddr, ibsize, size_stack[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse IBs and dump them to test vector. Detect swap by inspecting
|
||||
* register writes, keeping note of the current state, and dump
|
||||
* framebuffer config to test vector
|
||||
*/
|
||||
bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
|
||||
const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
|
||||
bool check_only)
|
||||
{
|
||||
static uint level; /* recursion level */
|
||||
bool ret = true;
|
||||
uint *hostaddr, *hoststart;
|
||||
int dwords_left = sizedwords; /* dwords left in the current command
|
||||
buffer */
|
||||
|
||||
if (level == 0)
|
||||
kgsl_cffdump_addr_count = 0;
|
||||
|
||||
if (memdesc == NULL) {
|
||||
struct kgsl_mem_entry *entry;
|
||||
spin_lock(&dev_priv->process_priv->mem_lock);
|
||||
entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
|
||||
gpuaddr, sizedwords * sizeof(uint));
|
||||
spin_unlock(&dev_priv->process_priv->mem_lock);
|
||||
if (entry == NULL) {
|
||||
KGSL_CORE_ERR("did not find mapping "
|
||||
"for gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return true;
|
||||
}
|
||||
memdesc = &entry->memdesc;
|
||||
}
|
||||
hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
|
||||
if (hostaddr == NULL) {
|
||||
KGSL_CORE_ERR("no kernel mapping for "
|
||||
"gpuaddr: 0x%08x\n", gpuaddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
hoststart = hostaddr;
|
||||
|
||||
level++;
|
||||
|
||||
if (!memdesc->physaddr) {
|
||||
KGSL_CORE_ERR("no physaddr");
|
||||
} else {
|
||||
mb();
|
||||
kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
|
||||
KGSL_CACHE_OP_INV);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
pr_info("kgsl: cffdump: ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
|
||||
gpuaddr, sizedwords, hostaddr);
|
||||
#endif
|
||||
|
||||
while (dwords_left > 0) {
|
||||
int count = 0; /* dword count including packet header */
|
||||
bool cur_ret = true;
|
||||
|
||||
switch (*hostaddr >> 30) {
|
||||
case 0x0: /* type-0 */
|
||||
count = (*hostaddr >> 16)+2;
|
||||
break;
|
||||
case 0x1: /* type-1 */
|
||||
count = 2;
|
||||
break;
|
||||
case 0x3: /* type-3 */
|
||||
count = ((*hostaddr >> 16) & 0x3fff) + 2;
|
||||
cur_ret = kgsl_cffdump_handle_type3(dev_priv,
|
||||
hostaddr, check_only);
|
||||
break;
|
||||
default:
|
||||
pr_warn("kgsl: cffdump: parse-ib: unexpected type: "
|
||||
"type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
|
||||
*hostaddr >> 30, *hostaddr, hostaddr,
|
||||
gpuaddr+4*(sizedwords-dwords_left));
|
||||
cur_ret = false;
|
||||
count = dwords_left;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!cur_ret) {
|
||||
pr_info("kgsl: cffdump: bad sub-type: #:%d/%d, v:0x%08x"
|
||||
" @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
sizedwords-dwords_left, sizedwords, *hostaddr,
|
||||
hostaddr, gpuaddr+4*(sizedwords-dwords_left),
|
||||
level);
|
||||
|
||||
print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
}
|
||||
#endif
|
||||
ret = ret && cur_ret;
|
||||
|
||||
/* jump to next packet */
|
||||
dwords_left -= count;
|
||||
hostaddr += count;
|
||||
cur_ret = dwords_left >= 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!cur_ret) {
|
||||
pr_info("kgsl: cffdump: bad count: c:%d, #:%d/%d, "
|
||||
"v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
|
||||
count, sizedwords-(dwords_left+count),
|
||||
sizedwords, *(hostaddr-count), hostaddr-count,
|
||||
gpuaddr+4*(sizedwords-(dwords_left+count)),
|
||||
level);
|
||||
|
||||
print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
|
||||
DUMP_PREFIX_OFFSET, 32, 4, hoststart,
|
||||
sizedwords*4, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = ret && cur_ret;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
pr_info("kgsl: cffdump: parsing failed: gpuaddr:0x%08x, "
|
||||
"host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
|
||||
|
||||
if (!check_only) {
|
||||
#ifdef DEBUG
|
||||
uint offset = gpuaddr - memdesc->gpuaddr;
|
||||
pr_info("kgsl: cffdump: ib-dump: hostptr:%p, gpuaddr:%08x, "
|
||||
"physaddr:%08x, offset:%d, size:%d", hoststart,
|
||||
gpuaddr, memdesc->physaddr + offset, offset,
|
||||
sizedwords*4);
|
||||
#endif
|
||||
kgsl_cffdump_syncmem(dev_priv, memdesc, gpuaddr, sizedwords*4,
|
||||
false);
|
||||
}
|
||||
|
||||
level--;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int subbuf_start_handler(struct rchan_buf *buf,
|
||||
void *subbuf, void *prev_subbuf, uint prev_padding)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user