Skip to content
Snippets Groups Projects
Commit 4fec268c authored by Tomeu Vizoso's avatar Tomeu Vizoso
Browse files

drm/panfrost: Improve fault reporting


Also put exception name resolution to a single function common to gpu,
job and mmu because the hw values are consecutive and we can read status
values in a block that correspond to error conditions that belong to
another IP block.

Signed-off-by: default avatarTomeu Vizoso <tomeu.vizoso@collabora.com>
parent 03325b0a
No related branches found
No related tags found
Loading
......@@ -7,6 +7,7 @@
#include <linux/regulator/consumer.h>
#include "panfrost_device.h"
#include "panfrost_features.h"
#include "panfrost_gpu.h"
#include "panfrost_job.h"
#include "panfrost_mmu.h"
......@@ -128,3 +129,59 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
panfrost_clk_fini(pfdev);
}
const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code)
{
switch (exception_code) {
/* Non-Fault Status code */
case 0x00: return "NOT_STARTED/IDLE/OK";
case 0x01: return "DONE";
case 0x02: return "INTERRUPTED";
case 0x03: return "STOPPED";
case 0x04: return "TERMINATED";
case 0x08: return "ACTIVE";
/* Job exceptions */
case 0x40: return "JOB_CONFIG_FAULT";
case 0x41: return "JOB_POWER_FAULT";
case 0x42: return "JOB_READ_FAULT";
case 0x43: return "JOB_WRITE_FAULT";
case 0x44: return "JOB_AFFINITY_FAULT";
case 0x48: return "JOB_BUS_FAULT";
case 0x50: return "INSTR_INVALID_PC";
case 0x51: return "INSTR_INVALID_ENC";
case 0x52: return "INSTR_TYPE_MISMATCH";
case 0x53: return "INSTR_OPERAND_FAULT";
case 0x54: return "INSTR_TLS_FAULT";
case 0x55: return "INSTR_BARRIER_FAULT";
case 0x56: return "INSTR_ALIGN_FAULT";
case 0x58: return "DATA_INVALID_FAULT";
case 0x59: return "TILE_RANGE_FAULT";
case 0x5A: return "ADDR_RANGE_FAULT";
case 0x60: return "OUT_OF_MEMORY";
/* GPU exceptions */
case 0x80: return "DELAYED_BUS_FAULT";
case 0x88: return "SHAREABILITY_FAULT";
/* MMU exceptions */
case 0xC1: return "TRANSLATION_FAULT_LEVEL1";
case 0xC2: return "TRANSLATION_FAULT_LEVEL2";
case 0xC3: return "TRANSLATION_FAULT_LEVEL3";
case 0xC4: return "TRANSLATION_FAULT_LEVEL4";
case 0xC8: return "PERMISSION_FAULT";
case 0xD1: return "TRANSTAB_BUS_FAULT_LEVEL1";
case 0xD2: return "TRANSTAB_BUS_FAULT_LEVEL2";
case 0xD3: return "TRANSTAB_BUS_FAULT_LEVEL3";
case 0xD4: return "TRANSTAB_BUS_FAULT_LEVEL4";
case 0xD8: return "ACCESS_FLAG";
}
if (panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU)) {
switch (exception_code) {
case 0xC9 ... 0xCF: return "PERMISSION_FAULT";
case 0xD9 ... 0xDF: return "ACCESS_FLAG";
case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT";
case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT";
};
}
return "UNKNOWN";
}
......@@ -98,4 +98,6 @@ static inline bool panfrost_model_eq(struct panfrost_device *pfdev, s32 id)
int panfrost_device_init(struct panfrost_device *pfdev);
void panfrost_device_fini(struct panfrost_device *pfdev);
const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code);
#endif
......@@ -22,15 +22,23 @@ static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
u32 state = gpu_read(pfdev, GPU_INT_STAT);
u32 status = gpu_read(pfdev, GPU_STATUS);
u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
u64 address;
bool done = false;
if (!state)
return IRQ_NONE;
if (state & GPU_IRQ_MASK_ERROR) {
dev_err(pfdev->dev, "gpu error irq state=%x status=%x\n",
state, status);
address = (u64) gpu_read(pfdev, GPU_FAULT_ADDRESS_HI) << 32;
address |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO);
dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
fault_status & 0xFF, panfrost_exception_name(pfdev, fault_status),
address);
if (state & GPU_IRQ_MULTIPLE_FAULT)
dev_warn(pfdev->dev, "There were multiple GPU faults - some have not been reported\n");
gpu_write(pfdev, GPU_INT_MASK, 0);
......@@ -288,7 +296,8 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
gpu_read(pfdev, GPU_AS_PRESENT),
gpu_read(pfdev, GPU_JS_PRESENT));
dev_info(pfdev->dev, "shader_present=0x%0llx", pfdev->features.shader_present);
dev_info(pfdev->dev, "shader_present=0x%0llx l2_present=0x%0llx",
pfdev->features.shader_present, pfdev->features.l2_present);
}
static void panfrost_gpu_power_on(struct panfrost_device *pfdev)
......
......@@ -360,39 +360,6 @@ static const struct drm_sched_backend_ops panfrost_sched_ops = {
.free_job = panfrost_job_free
};
static const char *job_exception_name(u32 exception_code)
{
switch (exception_code) {
/* Non-Fault Status code */
case 0x00: return "NOT_STARTED/IDLE/OK";
case 0x01: return "DONE";
case 0x02: return "INTERRUPTED";
case 0x03: return "STOPPED";
case 0x04: return "TERMINATED";
case 0x08: return "ACTIVE";
/* Job exceptions */
case 0x40: return "JOB_CONFIG_FAULT";
case 0x41: return "JOB_POWER_FAULT";
case 0x42: return "JOB_READ_FAULT";
case 0x43: return "JOB_WRITE_FAULT";
case 0x44: return "JOB_AFFINITY_FAULT";
case 0x48: return "JOB_BUS_FAULT";
case 0x50: return "INSTR_INVALID_PC";
case 0x51: return "INSTR_INVALID_ENC";
case 0x52: return "INSTR_TYPE_MISMATCH";
case 0x53: return "INSTR_OPERAND_FAULT";
case 0x54: return "INSTR_TLS_FAULT";
case 0x55: return "INSTR_BARRIER_FAULT";
case 0x56: return "INSTR_ALIGN_FAULT";
case 0x58: return "DATA_INVALID_FAULT";
case 0x59: return "TILE_RANGE_FAULT";
case 0x5A: return "ADDR_RANGE_FAULT";
case 0x60: return "OUT_OF_MEMORY";
}
return "UNKNOWN";
}
static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
......@@ -418,7 +385,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x",
j,
job_exception_name(job_read(pfdev, JS_STATUS(j))),
panfrost_exception_name(pfdev, job_read(pfdev, JS_STATUS(j))),
job_read(pfdev, JS_HEAD_LO(j)),
job_read(pfdev, JS_TAIL_LO(j)));
}
......
......@@ -202,27 +202,6 @@ static const struct iommu_gather_ops mmu_tlb_ops = {
.tlb_sync = mmu_tlb_sync_context,
};
static const char *mmu_exception_name(struct panfrost_device *pfdev,
u32 exception_code)
{
switch (exception_code) {
case 0xC0 ... 0xC7: return "TRANSLATION_FAULT";
case 0xC8: return "PERMISSION_FAULT";
case 0xD0 ... 0xD7: return "TRANSTAB_BUS_FAULT";
case 0xD8: return "ACCESS_FLAG";
}
if (panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU)) {
switch (exception_code) {
case 0xC9 ... 0xCF: return "PERMISSION_FAULT";
case 0xD9 ... 0xDF: return "ACCESS_FLAG";
case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT";
case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT";
};
}
return "UNKNOWN";
}
static const char *access_type_name(struct panfrost_device *pfdev,
u32 fault_status)
{
......@@ -288,7 +267,7 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data)
"TODO",
fault_status,
(fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
exception_type, mmu_exception_name(pfdev, exception_type),
exception_type, panfrost_exception_name(pfdev, exception_type),
access_type, access_type_name(pfdev, fault_status),
source_id);
......
......@@ -46,6 +46,9 @@
#define GPU_CMD_SOFT_RESET 0x01
#define GPU_STATUS 0x34
#define GPU_LATEST_FLUSH_ID 0x38
#define GPU_FAULT_STATUS 0x3C
#define GPU_FAULT_ADDRESS_LO 0x40
#define GPU_FAULT_ADDRESS_HI 0x44
#define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */
#define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment