Loading drivers/gpu/msm/adreno_snapshot.c +106 −48 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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; } /* Loading Loading @@ -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; /* Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; } } Loading Loading @@ -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) Loading Loading @@ -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, Loading @@ -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 = Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); Loading @@ -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 */ Loading @@ -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); Loading Loading @@ -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); } /* Loading @@ -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); } /* Loading @@ -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"); Loading drivers/gpu/msm/kgsl_device.h +13 −0 Original line number Diff line number Diff line Loading @@ -263,6 +263,7 @@ struct kgsl_device { struct kgsl_snapshot *snapshot; u32 snapshot_faultcount; /* Total number of faults since boot */ bool force_panic; /* Force panic after snapshot dump */ struct kobject snapshot_kobj; struct kobject ppd_kobj; Loading Loading @@ -429,6 +430,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 Loading @@ -444,6 +451,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; Loading drivers/gpu/msm/kgsl_snapshot.c +64 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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 Loading @@ -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) { Loading @@ -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)); Loading @@ -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; Loading Loading @@ -804,6 +803,29 @@ static ssize_t faultcount_store(struct kgsl_device *device, const char *buf, return count; } /* Show the force_panic request status */ static ssize_t force_panic_show(struct kgsl_device *device, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", device->force_panic); } /* Store the panic request value to force_panic */ static ssize_t force_panic_store(struct kgsl_device *device, const char *buf, size_t count) { unsigned int val = 0; int ret; if (device && count > 0) device->force_panic = 0; ret = kgsl_sysfs_store(buf, &val); if (!ret && device) device->force_panic = (bool)val; return (ssize_t) ret < 0 ? ret : count; } /* Show the timestamp of the last collected snapshot */ static ssize_t timestamp_show(struct kgsl_device *device, char *buf) { Loading @@ -829,6 +851,7 @@ struct kgsl_snapshot_attribute attr_##_name = { \ static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL); static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store); static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store); static ssize_t snapshot_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) Loading Loading @@ -908,6 +931,7 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) device->snapshot = NULL; device->snapshot_faultcount = 0; device->force_panic = 0; ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot, &device->dev->kobj, "snapshot"); Loading @@ -923,7 +947,11 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) goto done; ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr); if (ret) goto done; ret = sysfs_create_file(&device->snapshot_kobj, &attr_force_panic.attr); done: return ret; } Loading @@ -948,6 +976,7 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) device->snapshot_memory.ptr = NULL; device->snapshot_memory.size = 0; device->snapshot_faultcount = 0; device->force_panic = 0; } EXPORT_SYMBOL(kgsl_device_snapshot_close); Loading Loading @@ -975,7 +1004,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; Loading @@ -1001,6 +1031,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); Loading @@ -1017,6 +1055,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) { struct kgsl_snapshot *snapshot = container_of(work, struct kgsl_snapshot, work); struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct kgsl_snapshot_object *obj, *tmp; size_t size = 0; void *ptr; Loading @@ -1036,7 +1075,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) snapshot->mempool = vmalloc(size); if (snapshot->mempool != NULL) KGSL_CORE_ERR("snapshot: mempool address %p, size %zx\n", KGSL_DRV_ERR(device, "snapshot: mempool address %p, size %zx\n", snapshot->mempool, size); ptr = snapshot->mempool; Loading @@ -1045,7 +1084,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; } Loading @@ -1060,6 +1099,16 @@ done: kgsl_process_private_put(snapshot->process); snapshot->process = NULL; if (snapshot->ib1base && !snapshot->ib1dumped) KGSL_DRV_ERR(device, "snapshot: Active IB1:%016llx not dumped\n", snapshot->ib1base); else if (snapshot->ib2base && !snapshot->ib2dumped) KGSL_DRV_ERR(device, "snapshot: Active IB2:%016llx not dumped\n", snapshot->ib2base); complete_all(&snapshot->dump_gate); BUG_ON(device->force_panic); return; } drivers/gpu/msm/kgsl_snapshot.h +25 −5 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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 */ Loading @@ -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 Loading @@ -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 */ Loading Loading
drivers/gpu/msm/adreno_snapshot.c +106 −48 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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; } /* Loading Loading @@ -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; /* Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; } } Loading Loading @@ -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) Loading Loading @@ -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, Loading @@ -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 = Loading @@ -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; Loading @@ -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); Loading Loading @@ -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); Loading @@ -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 */ Loading @@ -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); Loading Loading @@ -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); } /* Loading @@ -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); } /* Loading @@ -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"); Loading
drivers/gpu/msm/kgsl_device.h +13 −0 Original line number Diff line number Diff line Loading @@ -263,6 +263,7 @@ struct kgsl_device { struct kgsl_snapshot *snapshot; u32 snapshot_faultcount; /* Total number of faults since boot */ bool force_panic; /* Force panic after snapshot dump */ struct kobject snapshot_kobj; struct kobject ppd_kobj; Loading Loading @@ -429,6 +430,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 Loading @@ -444,6 +451,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; Loading
drivers/gpu/msm/kgsl_snapshot.c +64 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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 Loading @@ -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) { Loading @@ -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)); Loading @@ -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; Loading Loading @@ -804,6 +803,29 @@ static ssize_t faultcount_store(struct kgsl_device *device, const char *buf, return count; } /* Show the force_panic request status */ static ssize_t force_panic_show(struct kgsl_device *device, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", device->force_panic); } /* Store the panic request value to force_panic */ static ssize_t force_panic_store(struct kgsl_device *device, const char *buf, size_t count) { unsigned int val = 0; int ret; if (device && count > 0) device->force_panic = 0; ret = kgsl_sysfs_store(buf, &val); if (!ret && device) device->force_panic = (bool)val; return (ssize_t) ret < 0 ? ret : count; } /* Show the timestamp of the last collected snapshot */ static ssize_t timestamp_show(struct kgsl_device *device, char *buf) { Loading @@ -829,6 +851,7 @@ struct kgsl_snapshot_attribute attr_##_name = { \ static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL); static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store); static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store); static ssize_t snapshot_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) Loading Loading @@ -908,6 +931,7 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) device->snapshot = NULL; device->snapshot_faultcount = 0; device->force_panic = 0; ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot, &device->dev->kobj, "snapshot"); Loading @@ -923,7 +947,11 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) goto done; ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr); if (ret) goto done; ret = sysfs_create_file(&device->snapshot_kobj, &attr_force_panic.attr); done: return ret; } Loading @@ -948,6 +976,7 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) device->snapshot_memory.ptr = NULL; device->snapshot_memory.size = 0; device->snapshot_faultcount = 0; device->force_panic = 0; } EXPORT_SYMBOL(kgsl_device_snapshot_close); Loading Loading @@ -975,7 +1004,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; Loading @@ -1001,6 +1031,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); Loading @@ -1017,6 +1055,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) { struct kgsl_snapshot *snapshot = container_of(work, struct kgsl_snapshot, work); struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct kgsl_snapshot_object *obj, *tmp; size_t size = 0; void *ptr; Loading @@ -1036,7 +1075,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) snapshot->mempool = vmalloc(size); if (snapshot->mempool != NULL) KGSL_CORE_ERR("snapshot: mempool address %p, size %zx\n", KGSL_DRV_ERR(device, "snapshot: mempool address %p, size %zx\n", snapshot->mempool, size); ptr = snapshot->mempool; Loading @@ -1045,7 +1084,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; } Loading @@ -1060,6 +1099,16 @@ done: kgsl_process_private_put(snapshot->process); snapshot->process = NULL; if (snapshot->ib1base && !snapshot->ib1dumped) KGSL_DRV_ERR(device, "snapshot: Active IB1:%016llx not dumped\n", snapshot->ib1base); else if (snapshot->ib2base && !snapshot->ib2dumped) KGSL_DRV_ERR(device, "snapshot: Active IB2:%016llx not dumped\n", snapshot->ib2base); complete_all(&snapshot->dump_gate); BUG_ON(device->force_panic); return; }
drivers/gpu/msm/kgsl_snapshot.h +25 −5 Original line number Diff line number Diff line /* 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 Loading Loading @@ -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 */ Loading @@ -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 Loading @@ -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 */ Loading