diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index 0eff3da0e494..08d7d3c1b935 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -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"); diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index f42d822b451b..e0fa578d15a5 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -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; diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index dd004f9588e9..2c9f17f9e7a4 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -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; } diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h index 8167ff83a18b..e2ded87b7431 100644 --- a/drivers/gpu/msm/kgsl_snapshot.h +++ b/drivers/gpu/msm/kgsl_snapshot.h @@ -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 */