Merge "msm: kgsl: Revisit the GPU snapshot dumping"

This commit is contained in:
Linux Build Service Account 2016-09-29 11:20:49 -07:00 committed by Gerrit - the friendly Code Review server
commit be6bc701ce
4 changed files with 172 additions and 67 deletions

View file

@ -108,7 +108,7 @@ static void push_object(int type,
}
/*
* Return a 1 if the specified object is already on the list of buffers
* Returns index of the specified object is already on the list of buffers
* to be dumped
*/
@ -120,10 +120,9 @@ static int find_object(int type, uint64_t gpuaddr,
for (index = 0; index < objbufptr; index++) {
if (objbuf[index].gpuaddr == gpuaddr &&
objbuf[index].entry->priv == process)
return 1;
return index;
}
return 0;
return -ENOENT;
}
/*
@ -196,8 +195,6 @@ static inline void parse_ib(struct kgsl_device *device,
struct kgsl_process_private *process,
uint64_t gpuaddr, uint64_t dwords)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
uint64_t ib1base;
struct adreno_ib_object_list *ib_obj_list;
/*
@ -205,11 +202,7 @@ static inline void parse_ib(struct kgsl_device *device,
* then push it into the static blob otherwise put it in the dynamic
* list
*/
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &ib1base);
if (gpuaddr == ib1base) {
if (gpuaddr == snapshot->ib1base) {
push_object(SNAPSHOT_OBJ_TYPE_IB, process,
gpuaddr, dwords);
return;
@ -295,17 +288,12 @@ static void snapshot_rb_ibs(struct kgsl_device *device,
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int rptr, *rbptr;
uint64_t ibbase;
int index, i;
int parse_ibs = 0, ib_parse_start;
/* Get the current read pointers for the RB */
adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &rptr);
/* Address of the last processed IB */
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &ibbase);
/*
* Figure out the window of ringbuffer data to dump. First we need to
* find where the last processed IB ws submitted. Start walking back
@ -333,14 +321,14 @@ static void snapshot_rb_ibs(struct kgsl_device *device,
if (adreno_cmd_is_ib(adreno_dev, rbptr[index])) {
if (ADRENO_LEGACY_PM4(adreno_dev)) {
if (rbptr[index + 1] == ibbase)
if (rbptr[index + 1] == snapshot->ib1base)
break;
} else {
uint64_t ibaddr;
ibaddr = rbptr[index + 2];
ibaddr = ibaddr << 32 | rbptr[index + 1];
if (ibaddr == ibbase)
if (ibaddr == snapshot->ib1base)
break;
}
}
@ -564,6 +552,67 @@ struct snapshot_ib_meta {
uint64_t ib2size;
};
void kgsl_snapshot_add_active_ib_obj_list(struct kgsl_device *device,
struct kgsl_snapshot *snapshot)
{
struct adreno_ib_object_list *ib_obj_list;
int index = -ENOENT;
if (!snapshot->ib1dumped)
index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base,
snapshot->process);
/* only do this for IB1 because the IB2's are part of IB1 objects */
if ((index != -ENOENT) &&
(snapshot->ib1base == objbuf[index].gpuaddr)) {
if (-E2BIG == adreno_ib_create_object_list(device,
objbuf[index].entry->priv,
objbuf[index].gpuaddr,
objbuf[index].size >> 2,
&ib_obj_list))
ib_max_objs = 1;
if (ib_obj_list) {
/* freeze the IB objects in the IB */
snapshot_freeze_obj_list(snapshot,
objbuf[index].entry->priv,
ib_obj_list, snapshot->ib2base);
adreno_ib_destroy_obj_list(ib_obj_list);
}
} else {
/* Get the IB2 index from parsed object */
index = find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base,
snapshot->process);
if (index != -ENOENT)
parse_ib(device, snapshot, snapshot->process,
snapshot->ib2base, objbuf[index].size >> 2);
}
}
/*
* active_ib_is_parsed() - Checks if active ib is already parsed
* @gpuaddr: Active IB base address at the time of fault
* @size: Active IB size
* @process: The process to which the IB belongs
*
* Function returns true if the active is already is parsed
* else false
*/
static bool active_ib_is_parsed(uint64_t gpuaddr, uint64_t size,
struct kgsl_process_private *process)
{
int index;
/* go through the static list for gpuaddr is in list or not */
for (index = 0; index < objbufptr; index++) {
if ((objbuf[index].gpuaddr <= gpuaddr) &&
((objbuf[index].gpuaddr +
(objbuf[index].size)) >=
(gpuaddr + size)) &&
(objbuf[index].entry->priv == process))
return true;
}
return false;
}
/* Snapshot the memory for an indirect buffer */
static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
size_t remain, void *priv)
@ -596,13 +645,11 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
return 0;
}
if (remain < (obj->size + sizeof(*header))) {
KGSL_CORE_ERR("snapshot: Not enough memory for the ib\n");
return 0;
}
/* only do this for IB1 because the IB2's are part of IB1 objects */
if (meta->ib1base == obj->gpuaddr) {
snapshot->ib1dumped = active_ib_is_parsed(obj->gpuaddr,
obj->size, obj->entry->priv);
if (-E2BIG == adreno_ib_create_object_list(device,
obj->entry->priv,
obj->gpuaddr, obj->size >> 2,
@ -617,6 +664,11 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
}
}
if (meta->ib2base == obj->gpuaddr)
snapshot->ib2dumped = active_ib_is_parsed(obj->gpuaddr,
obj->size, obj->entry->priv);
/* Write the sub-header for the section */
header->gpuaddr = obj->gpuaddr;
header->ptbase =
@ -632,9 +684,7 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
/* Dump another item on the current pending list */
static void dump_object(struct kgsl_device *device, int obj,
struct kgsl_snapshot *snapshot,
uint64_t ib1base, uint64_t ib1size,
uint64_t ib2base, uint64_t ib2size)
struct kgsl_snapshot *snapshot)
{
struct snapshot_ib_meta meta;
@ -642,10 +692,10 @@ static void dump_object(struct kgsl_device *device, int obj,
case SNAPSHOT_OBJ_TYPE_IB:
meta.snapshot = snapshot;
meta.obj = &objbuf[obj];
meta.ib1base = ib1base;
meta.ib1size = ib1size;
meta.ib2base = ib2base;
meta.ib2size = ib2size;
meta.ib1base = snapshot->ib1base;
meta.ib1size = snapshot->ib1size;
meta.ib2base = snapshot->ib2base;
meta.ib2size = snapshot->ib2size;
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2,
snapshot, snapshot_ib, &meta);
@ -792,8 +842,6 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
struct kgsl_context *context)
{
unsigned int i;
uint64_t ib1base, ib2base;
unsigned int ib1size, ib2size;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@ -806,6 +854,16 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
setup_fault_process(device, snapshot,
context ? context->proc_priv : NULL);
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &snapshot->ib1base);
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ, &snapshot->ib1size);
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB2_BASE,
ADRENO_REG_CP_IB2_BASE_HI, &snapshot->ib2base);
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ, &snapshot->ib2size);
snapshot->ib1dumped = false;
snapshot->ib2dumped = false;
adreno_snapshot_ringbuffer(device, snapshot, adreno_dev->cur_rb);
/* Dump the prev ringbuffer */
@ -818,13 +876,6 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
adreno_snapshot_ringbuffer(device, snapshot,
adreno_dev->next_rb);
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &ib1base);
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ, &ib1size);
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB2_BASE,
ADRENO_REG_CP_IB2_BASE_HI, &ib2base);
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ, &ib2size);
/* Add GPU specific sections - registers mainly, but other stuff too */
if (gpudev->snapshot)
gpudev->snapshot(adreno_dev, snapshot);
@ -858,13 +909,13 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
* figure how often this really happens.
*/
if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ib1base,
snapshot->process) && ib1size) {
if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib1base,
snapshot->process) && snapshot->ib1size) {
push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
ib1base, ib1size);
snapshot->ib1base, snapshot->ib1size);
KGSL_CORE_ERR(
"CP_IB1_BASE not found in the ringbuffer.Dumping %x dwords of the buffer.\n",
ib1size);
snapshot->ib1size);
}
/*
@ -875,10 +926,10 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
* correct size.
*/
if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ib2base,
snapshot->process) && ib2size) {
if (-ENOENT == find_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->ib2base,
snapshot->process)) {
push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
ib2base, ib2size);
snapshot->ib2base, snapshot->ib2size);
}
/*
@ -886,8 +937,15 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
* are parsed, more objects might be found, and objbufptr will increase
*/
for (i = 0; i < objbufptr; i++)
dump_object(device, i, snapshot, ib1base, ib1size,
ib2base, ib2size);
dump_object(device, i, snapshot);
/*
* Incase snapshot static blob is running out of memory, Add Active IB1
* and IB2 entries to obj_list so that active ib's can be dumped to
* snapshot dynamic blob.
*/
if (!snapshot->ib1dumped || !snapshot->ib2dumped)
kgsl_snapshot_add_active_ib_obj_list(device, snapshot);
if (ib_max_objs)
KGSL_CORE_ERR("Max objects found in IB\n");

View file

@ -422,6 +422,12 @@ struct kgsl_device_private {
/**
* struct kgsl_snapshot - details for a specific snapshot instance
* @ib1base: Active IB1 base address at the time of fault
* @ib2base: Active IB2 base address at the time of fault
* @ib1size: Number of DWORDS pending in IB1 at the time of fault
* @ib2size: Number of DWORDS pending in IB2 at the time of fault
* @ib1dumped: Active IB1 dump status to sansphot binary
* @ib2dumped: Active IB2 dump status to sansphot binary
* @start: Pointer to the start of the static snapshot region
* @size: Size of the current snapshot instance
* @ptr: Pointer to the next block of memory to write to during snapshotting
@ -437,6 +443,12 @@ struct kgsl_device_private {
* @sysfs_read: An atomic for concurrent snapshot reads via syfs.
*/
struct kgsl_snapshot {
uint64_t ib1base;
uint64_t ib2base;
unsigned int ib1size;
unsigned int ib2size;
bool ib1dumped;
bool ib2dumped;
u8 *start;
size_t size;
u8 *ptr;

View file

@ -100,8 +100,8 @@ static u8 *_ctxtptr;
static int snapshot_context_info(int id, void *ptr, void *data)
{
struct kgsl_snapshot_linux_context *header =
(struct kgsl_snapshot_linux_context *)_ctxtptr;
struct kgsl_snapshot_linux_context_v2 *header =
(struct kgsl_snapshot_linux_context_v2 *)_ctxtptr;
struct kgsl_context *context = ptr;
struct kgsl_device *device;
@ -115,10 +115,12 @@ static int snapshot_context_info(int id, void *ptr, void *data)
kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED,
&header->timestamp_queued);
kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_CONSUMED,
&header->timestamp_consumed);
kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED,
&header->timestamp_retired);
_ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
_ctxtptr += sizeof(struct kgsl_snapshot_linux_context_v2);
return 0;
}
@ -127,11 +129,11 @@ static int snapshot_context_info(int id, void *ptr, void *data)
static size_t snapshot_os(struct kgsl_device *device,
u8 *buf, size_t remain, void *priv)
{
struct kgsl_snapshot_linux *header = (struct kgsl_snapshot_linux *)buf;
struct kgsl_snapshot_linux_v2 *header =
(struct kgsl_snapshot_linux_v2 *)buf;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int ctxtcount = 0;
size_t size = sizeof(*header);
u64 temp_ptbase;
struct kgsl_context *context;
/* Figure out how many active contexts there are - these will
@ -141,7 +143,7 @@ static size_t snapshot_os(struct kgsl_device *device,
idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
read_unlock(&device->context_lock);
size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context_v2);
/* Make sure there is enough room for the data */
if (remain < size) {
@ -151,9 +153,7 @@ static size_t snapshot_os(struct kgsl_device *device,
memset(header, 0, sizeof(*header));
header->osid = KGSL_SNAPSHOT_OS_LINUX;
header->state = SNAPSHOT_STATE_HUNG;
header->osid = KGSL_SNAPSHOT_OS_LINUX_V3;
/* Get the kernel build information */
strlcpy(header->release, utsname()->release, sizeof(header->release));
@ -178,9 +178,8 @@ static size_t snapshot_os(struct kgsl_device *device,
context = kgsl_context_get(device, header->current_context);
/* Get the current PT base */
temp_ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
/* Truncate to 32 bits in case LPAE is used */
header->ptbase = (__u32)temp_ptbase;
header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
/* And the PID for the task leader */
if (context) {
header->pid = context->tid;
@ -982,7 +981,8 @@ int kgsl_snapshot_add_ib_obj_list(struct kgsl_snapshot *snapshot,
return 0;
}
static size_t _mempool_add_object(u8 *data, struct kgsl_snapshot_object *obj)
static size_t _mempool_add_object(struct kgsl_snapshot *snapshot, u8 *data,
struct kgsl_snapshot_object *obj)
{
struct kgsl_snapshot_section_header *section =
(struct kgsl_snapshot_section_header *)data;
@ -1008,6 +1008,14 @@ static size_t _mempool_add_object(u8 *data, struct kgsl_snapshot_object *obj)
kgsl_mmu_pagetable_get_ttbr0(obj->entry->priv->pagetable);
header->type = obj->type;
if (kgsl_addr_range_overlap(obj->gpuaddr, obj->size,
snapshot->ib1base, snapshot->ib1size))
snapshot->ib1dumped = true;
if (kgsl_addr_range_overlap(obj->gpuaddr, obj->size,
snapshot->ib2base, snapshot->ib2size))
snapshot->ib2dumped = true;
memcpy(dest, obj->entry->memdesc.hostptr + obj->offset, size);
kgsl_memdesc_unmap(&obj->entry->memdesc);
@ -1049,7 +1057,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
/* even if vmalloc fails, make sure we clean up the obj_list */
list_for_each_entry_safe(obj, tmp, &snapshot->obj_list, node) {
if (snapshot->mempool) {
size_t ret = _mempool_add_object(ptr, obj);
size_t ret = _mempool_add_object(snapshot, ptr, obj);
ptr += ret;
snapshot->mempool_size += ret;
}
@ -1064,6 +1072,13 @@ done:
kgsl_process_private_put(snapshot->process);
snapshot->process = NULL;
if (snapshot->ib1base && !snapshot->ib1dumped)
pr_warn("kgsl: snapshot: Active IB1:%016llx not dumped\n",
snapshot->ib1base);
else if (snapshot->ib2base && !snapshot->ib2dumped)
pr_warn("kgsl: snapshot: Active IB2:%016llx not dumped\n",
snapshot->ib2base);
complete_all(&snapshot->dump_gate);
return;
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -63,12 +63,9 @@ struct kgsl_snapshot_section_header {
/* OS sub-section header */
#define KGSL_SNAPSHOT_OS_LINUX 0x0001
#define KGSL_SNAPSHOT_OS_LINUX_V3 0x00000202
/* Linux OS specific information */
#define SNAPSHOT_STATE_HUNG 0
#define SNAPSHOT_STATE_RUNNING 1
struct kgsl_snapshot_linux {
int osid; /* subsection OS identifier */
int state; /* 1 if the thread is running, 0 for hung */
@ -87,6 +84,23 @@ struct kgsl_snapshot_linux {
unsigned char comm[16]; /* Name of the process that owns the PT */
} __packed;
struct kgsl_snapshot_linux_v2 {
int osid; /* subsection OS identifier */
__u32 seconds; /* Unix timestamp for the snapshot */
__u32 power_flags; /* Current power flags */
__u32 power_level; /* Current power level */
__u32 power_interval_timeout; /* Power interval timeout */
__u32 grpclk; /* Current GP clock value */
__u32 busclk; /* Current busclk value */
__u64 ptbase; /* Current ptbase */
__u32 pid; /* PID of the process that owns the PT */
__u32 current_context; /* ID of the current context */
__u32 ctxtcount; /* Number of contexts appended to section */
unsigned char release[32]; /* kernel release */
unsigned char version[32]; /* kernel version */
unsigned char comm[16]; /* Name of the process that owns the PT */
} __packed;
/*
* This structure contains a record of an active context.
* These are appended one after another in the OS section below
@ -99,6 +113,12 @@ struct kgsl_snapshot_linux_context {
__u32 timestamp_retired; /* The last timestamp retired by HW */
};
struct kgsl_snapshot_linux_context_v2 {
__u32 id; /* The context ID */
__u32 timestamp_queued; /* The last queued timestamp */
__u32 timestamp_consumed; /* The last timestamp consumed by HW */
__u32 timestamp_retired; /* The last timestamp retired by HW */
};
/* Ringbuffer sub-section header */
struct kgsl_snapshot_rb {
int start; /* dword at the start of the dump */