Loading drivers/gpu/msm/adreno.c +14 −2 Original line number Diff line number Diff line Loading @@ -2914,7 +2914,13 @@ static void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, offsetwords, device->reg_len >> 2)) return; if (!in_interrupt()) /* * kgsl panic notifier will be called in atomic context to get * GPU snapshot. Also panic handler will skip snapshot dumping * incase GPU is in SLUMBER state. So we can safely ignore the * kgsl_pre_hwaccess(). */ if (!device->snapshot_atomic && !in_interrupt()) kgsl_pre_hwaccess(device); *value = readl_relaxed(device->reg_virt + (offsetwords << 2)); Loading @@ -2938,7 +2944,13 @@ static void adreno_regwrite(struct kgsl_device *device, offsetwords, device->reg_len >> 2)) return; if (!in_interrupt()) /* * kgsl panic notifier will be called in atomic context to get * GPU snapshot. Also panic handler will skip snapshot dumping * incase GPU is in SLUMBER state. So we can safely ignore the * kgsl_pre_hwaccess(). */ if (!device->snapshot_atomic && !in_interrupt()) kgsl_pre_hwaccess(device); trace_kgsl_regwrite(device, offsetwords, value); Loading drivers/gpu/msm/adreno_a6xx_snapshot.c +4 −2 Original line number Diff line number Diff line Loading @@ -1591,6 +1591,7 @@ static void _a6xx_do_crashdump(struct kgsl_device *device) timeout = ktime_add_ms(ktime_get(), CP_CRASH_DUMPER_TIMEOUT); if (!device->snapshot_atomic) might_sleep(); for (;;) { Loading @@ -1603,6 +1604,7 @@ static void _a6xx_do_crashdump(struct kgsl_device *device) break; /* Wait 1msec to avoid unnecessary looping */ if (!device->snapshot_atomic) usleep_range(100, 1000); } Loading drivers/gpu/msm/adreno_snapshot.c +3 −0 Original line number Diff line number Diff line Loading @@ -846,6 +846,9 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, adreno_snapshot_ringbuffer(device, snapshot, adreno_dev->next_rb); if (device->snapshot_atomic) return; /* Dump selected global buffers */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, snapshot, adreno_snapshot_global, device->memstore); Loading drivers/gpu/msm/kgsl_device.h +7 −1 Original line number Diff line number Diff line Loading @@ -268,13 +268,19 @@ struct kgsl_device { } snapshot_memory; struct kgsl_snapshot *snapshot; /** @panic_nb: notifier block to capture GPU snapshot on kernel panic */ struct notifier_block panic_nb; struct { void *ptr; u32 size; } snapshot_memory_atomic; u32 snapshot_faultcount; /* Total number of faults since boot */ bool force_panic; /* Force panic after snapshot dump */ bool skip_ib_capture; /* Skip IB capture after snapshot */ bool prioritize_unrecoverable; /* Overwrite with new GMU snapshots */ bool set_isdb_breakpoint; /* Set isdb registers before snapshot */ bool snapshot_atomic; /* To capture snapshot in atomic context*/ /* Use CP Crash dumper to get GPU snapshot*/ bool snapshot_crashdumper; /* Use HOST side register reads to get GPU snapshot*/ Loading drivers/gpu/msm/kgsl_snapshot.c +103 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include <linux/notifier.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/utsname.h> Loading Loading @@ -671,6 +672,86 @@ static void set_isdb_breakpoint_registers(struct kgsl_device *device) device->force_panic = false; } static void kgsl_device_snapshot_atomic(struct kgsl_device *device) { struct kgsl_snapshot_header *header; struct kgsl_snapshot *snapshot; phys_addr_t pa; device->snapshot_atomic = true; if (device->snapshot && device->force_panic) return; if (!atomic_read(&device->active_cnt)) { dev_err(device->dev, "snapshot: device is powered off\n"); return; } device->snapshot_memory_atomic.size = device->snapshot_memory.size; device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev, device->snapshot_memory_atomic.size, GFP_ATOMIC); if (!device->snapshot_memory_atomic.ptr) { dev_err(device->dev, "KGSL failed to allocate memory for atomic snapshot\n"); return; } /* Allocate memory for the snapshot instance */ snapshot = kzalloc(sizeof(*snapshot), GFP_ATOMIC); if (snapshot == NULL) return; INIT_LIST_HEAD(&snapshot->obj_list); INIT_LIST_HEAD(&snapshot->cp_list); snapshot->start = device->snapshot_memory_atomic.ptr; snapshot->ptr = device->snapshot_memory_atomic.ptr; snapshot->remain = device->snapshot_memory_atomic.size; header = (struct kgsl_snapshot_header *) snapshot->ptr; header->magic = SNAPSHOT_MAGIC; header->gpuid = kgsl_gpuid(device, &header->chipid); snapshot->ptr += sizeof(*header); snapshot->remain -= sizeof(*header); snapshot->size += sizeof(*header); /* Build the Linux specific header */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS, snapshot, snapshot_os_no_ctxt, NULL); /* * Trigger both GPU and GMU snapshot. GPU specific code * will take care of whether to dumps full state or only * GMU state based on current GPU power state. */ if (device->ftbl->snapshot) device->ftbl->snapshot(device, snapshot, NULL); if (msm_minidump_enabled()) { struct md_region md_entry; int ret; scnprintf(md_entry.name, sizeof(md_entry.name), "ATOMIC_GPU_SNAPSHOT"); md_entry.virt_addr = (u64)(device->snapshot_memory_atomic.ptr); md_entry.phys_addr = __pa(device->snapshot_memory_atomic.ptr); md_entry.size = device->snapshot_memory_atomic.size; ret = msm_minidump_add_region(&md_entry); if (ret < 0) dev_err(device->dev, "Fail to add atomic snapshot with minidump: %d\n", ret); } /* log buffer info to aid in ramdump fault tolerance */ pa = __pa(device->snapshot_memory_atomic.ptr); dev_err(device->dev, "Atomic GPU snapshot created at pa %pa++0x%zx\n", &pa, snapshot->size); } /** * kgsl_snapshot() - construct a device snapshot * @device: device to snapshot Loading Loading @@ -1144,6 +1225,19 @@ static const struct attribute *snapshot_attrs[] = { NULL, }; static int kgsl_panic_notifier_callback(struct notifier_block *nb, unsigned long action, void *unused) { struct kgsl_device *device = container_of(nb, struct kgsl_device, panic_nb); /* To send NMI to GMU */ device->gmu_fault = true; kgsl_device_snapshot_atomic(device); return NOTIFY_OK; } void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) { device->snapshot_memory.size = size; Loading Loading @@ -1174,6 +1268,10 @@ void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) device->snapshot_crashdumper = true; device->snapshot_legacy = false; device->snapshot_atomic = false; device->panic_nb.notifier_call = kgsl_panic_notifier_callback; device->panic_nb.priority = 1; /* * Set this to false so that we only ever keep the first snapshot around * If we want to over-write with a gmu snapshot, then set it to true Loading @@ -1187,6 +1285,8 @@ void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) WARN_ON(sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr)); WARN_ON(sysfs_create_files(&device->snapshot_kobj, snapshot_attrs)); atomic_notifier_chain_register(&panic_notifier_list, &device->panic_nb); } /** Loading @@ -1209,6 +1309,9 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) dev_err(device->dev, "Failed to remove snapshot with minidump\n"); } atomic_notifier_chain_unregister(&panic_notifier_list, &device->panic_nb); sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr); sysfs_remove_files(&device->snapshot_kobj, snapshot_attrs); Loading Loading
drivers/gpu/msm/adreno.c +14 −2 Original line number Diff line number Diff line Loading @@ -2914,7 +2914,13 @@ static void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, offsetwords, device->reg_len >> 2)) return; if (!in_interrupt()) /* * kgsl panic notifier will be called in atomic context to get * GPU snapshot. Also panic handler will skip snapshot dumping * incase GPU is in SLUMBER state. So we can safely ignore the * kgsl_pre_hwaccess(). */ if (!device->snapshot_atomic && !in_interrupt()) kgsl_pre_hwaccess(device); *value = readl_relaxed(device->reg_virt + (offsetwords << 2)); Loading @@ -2938,7 +2944,13 @@ static void adreno_regwrite(struct kgsl_device *device, offsetwords, device->reg_len >> 2)) return; if (!in_interrupt()) /* * kgsl panic notifier will be called in atomic context to get * GPU snapshot. Also panic handler will skip snapshot dumping * incase GPU is in SLUMBER state. So we can safely ignore the * kgsl_pre_hwaccess(). */ if (!device->snapshot_atomic && !in_interrupt()) kgsl_pre_hwaccess(device); trace_kgsl_regwrite(device, offsetwords, value); Loading
drivers/gpu/msm/adreno_a6xx_snapshot.c +4 −2 Original line number Diff line number Diff line Loading @@ -1591,6 +1591,7 @@ static void _a6xx_do_crashdump(struct kgsl_device *device) timeout = ktime_add_ms(ktime_get(), CP_CRASH_DUMPER_TIMEOUT); if (!device->snapshot_atomic) might_sleep(); for (;;) { Loading @@ -1603,6 +1604,7 @@ static void _a6xx_do_crashdump(struct kgsl_device *device) break; /* Wait 1msec to avoid unnecessary looping */ if (!device->snapshot_atomic) usleep_range(100, 1000); } Loading
drivers/gpu/msm/adreno_snapshot.c +3 −0 Original line number Diff line number Diff line Loading @@ -846,6 +846,9 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot, adreno_snapshot_ringbuffer(device, snapshot, adreno_dev->next_rb); if (device->snapshot_atomic) return; /* Dump selected global buffers */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2, snapshot, adreno_snapshot_global, device->memstore); Loading
drivers/gpu/msm/kgsl_device.h +7 −1 Original line number Diff line number Diff line Loading @@ -268,13 +268,19 @@ struct kgsl_device { } snapshot_memory; struct kgsl_snapshot *snapshot; /** @panic_nb: notifier block to capture GPU snapshot on kernel panic */ struct notifier_block panic_nb; struct { void *ptr; u32 size; } snapshot_memory_atomic; u32 snapshot_faultcount; /* Total number of faults since boot */ bool force_panic; /* Force panic after snapshot dump */ bool skip_ib_capture; /* Skip IB capture after snapshot */ bool prioritize_unrecoverable; /* Overwrite with new GMU snapshots */ bool set_isdb_breakpoint; /* Set isdb registers before snapshot */ bool snapshot_atomic; /* To capture snapshot in atomic context*/ /* Use CP Crash dumper to get GPU snapshot*/ bool snapshot_crashdumper; /* Use HOST side register reads to get GPU snapshot*/ Loading
drivers/gpu/msm/kgsl_snapshot.c +103 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include <linux/notifier.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/utsname.h> Loading Loading @@ -671,6 +672,86 @@ static void set_isdb_breakpoint_registers(struct kgsl_device *device) device->force_panic = false; } static void kgsl_device_snapshot_atomic(struct kgsl_device *device) { struct kgsl_snapshot_header *header; struct kgsl_snapshot *snapshot; phys_addr_t pa; device->snapshot_atomic = true; if (device->snapshot && device->force_panic) return; if (!atomic_read(&device->active_cnt)) { dev_err(device->dev, "snapshot: device is powered off\n"); return; } device->snapshot_memory_atomic.size = device->snapshot_memory.size; device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev, device->snapshot_memory_atomic.size, GFP_ATOMIC); if (!device->snapshot_memory_atomic.ptr) { dev_err(device->dev, "KGSL failed to allocate memory for atomic snapshot\n"); return; } /* Allocate memory for the snapshot instance */ snapshot = kzalloc(sizeof(*snapshot), GFP_ATOMIC); if (snapshot == NULL) return; INIT_LIST_HEAD(&snapshot->obj_list); INIT_LIST_HEAD(&snapshot->cp_list); snapshot->start = device->snapshot_memory_atomic.ptr; snapshot->ptr = device->snapshot_memory_atomic.ptr; snapshot->remain = device->snapshot_memory_atomic.size; header = (struct kgsl_snapshot_header *) snapshot->ptr; header->magic = SNAPSHOT_MAGIC; header->gpuid = kgsl_gpuid(device, &header->chipid); snapshot->ptr += sizeof(*header); snapshot->remain -= sizeof(*header); snapshot->size += sizeof(*header); /* Build the Linux specific header */ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS, snapshot, snapshot_os_no_ctxt, NULL); /* * Trigger both GPU and GMU snapshot. GPU specific code * will take care of whether to dumps full state or only * GMU state based on current GPU power state. */ if (device->ftbl->snapshot) device->ftbl->snapshot(device, snapshot, NULL); if (msm_minidump_enabled()) { struct md_region md_entry; int ret; scnprintf(md_entry.name, sizeof(md_entry.name), "ATOMIC_GPU_SNAPSHOT"); md_entry.virt_addr = (u64)(device->snapshot_memory_atomic.ptr); md_entry.phys_addr = __pa(device->snapshot_memory_atomic.ptr); md_entry.size = device->snapshot_memory_atomic.size; ret = msm_minidump_add_region(&md_entry); if (ret < 0) dev_err(device->dev, "Fail to add atomic snapshot with minidump: %d\n", ret); } /* log buffer info to aid in ramdump fault tolerance */ pa = __pa(device->snapshot_memory_atomic.ptr); dev_err(device->dev, "Atomic GPU snapshot created at pa %pa++0x%zx\n", &pa, snapshot->size); } /** * kgsl_snapshot() - construct a device snapshot * @device: device to snapshot Loading Loading @@ -1144,6 +1225,19 @@ static const struct attribute *snapshot_attrs[] = { NULL, }; static int kgsl_panic_notifier_callback(struct notifier_block *nb, unsigned long action, void *unused) { struct kgsl_device *device = container_of(nb, struct kgsl_device, panic_nb); /* To send NMI to GMU */ device->gmu_fault = true; kgsl_device_snapshot_atomic(device); return NOTIFY_OK; } void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) { device->snapshot_memory.size = size; Loading Loading @@ -1174,6 +1268,10 @@ void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) device->snapshot_crashdumper = true; device->snapshot_legacy = false; device->snapshot_atomic = false; device->panic_nb.notifier_call = kgsl_panic_notifier_callback; device->panic_nb.priority = 1; /* * Set this to false so that we only ever keep the first snapshot around * If we want to over-write with a gmu snapshot, then set it to true Loading @@ -1187,6 +1285,8 @@ void kgsl_device_snapshot_probe(struct kgsl_device *device, u32 size) WARN_ON(sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr)); WARN_ON(sysfs_create_files(&device->snapshot_kobj, snapshot_attrs)); atomic_notifier_chain_register(&panic_notifier_list, &device->panic_nb); } /** Loading @@ -1209,6 +1309,9 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) dev_err(device->dev, "Failed to remove snapshot with minidump\n"); } atomic_notifier_chain_unregister(&panic_notifier_list, &device->panic_nb); sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr); sysfs_remove_files(&device->snapshot_kobj, snapshot_attrs); Loading