mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
Merge "msm: kgsl: Add panic notifier support for GPU"
This commit is contained in:
commit
bccd122b9d
5 changed files with 131 additions and 5 deletions
|
|
@ -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));
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1591,7 +1591,8 @@ static void _a6xx_do_crashdump(struct kgsl_device *device)
|
|||
|
||||
timeout = ktime_add_ms(ktime_get(), CP_CRASH_DUMPER_TIMEOUT);
|
||||
|
||||
might_sleep();
|
||||
if (!device->snapshot_atomic)
|
||||
might_sleep();
|
||||
|
||||
for (;;) {
|
||||
/* make sure we're reading the latest value */
|
||||
|
|
@ -1603,7 +1604,8 @@ static void _a6xx_do_crashdump(struct kgsl_device *device)
|
|||
break;
|
||||
|
||||
/* Wait 1msec to avoid unnecessary looping */
|
||||
usleep_range(100, 1000);
|
||||
if (!device->snapshot_atomic)
|
||||
usleep_range(100, 1000);
|
||||
}
|
||||
|
||||
kgsl_regread(device, A6XX_CP_CRASH_DUMP_STATUS, &val);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -671,6 +672,86 @@ err:
|
|||
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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -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…
Reference in a new issue