Commit ed7a34c5 authored by Boris Brezillon's avatar Boris Brezillon

drm/panfrost: Disable the AS on unhandled page faults

If we don't do that, we have to wait for the job timeout to expire
before the fault jobs gets killed.

v3:
* Make sure the AS is re-enabled when new jobs are submitted to the
  context
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: default avatarSteven Price <steven.price@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210630062751.2832545-12-boris.brezillon@collabora.com
parent 1d0cab54
...@@ -97,6 +97,7 @@ struct panfrost_device { ...@@ -97,6 +97,7 @@ struct panfrost_device {
spinlock_t as_lock; spinlock_t as_lock;
unsigned long as_in_use_mask; unsigned long as_in_use_mask;
unsigned long as_alloc_mask; unsigned long as_alloc_mask;
unsigned long as_faulty_mask;
struct list_head as_lru_list; struct list_head as_lru_list;
struct panfrost_job_slot *js; struct panfrost_job_slot *js;
......
...@@ -154,6 +154,7 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu) ...@@ -154,6 +154,7 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
as = mmu->as; as = mmu->as;
if (as >= 0) { if (as >= 0) {
int en = atomic_inc_return(&mmu->as_count); int en = atomic_inc_return(&mmu->as_count);
u32 mask = BIT(as) | BIT(16 + as);
/* /*
* AS can be retained by active jobs or a perfcnt context, * AS can be retained by active jobs or a perfcnt context,
...@@ -162,6 +163,18 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu) ...@@ -162,6 +163,18 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
WARN_ON(en >= (NUM_JOB_SLOTS + 1)); WARN_ON(en >= (NUM_JOB_SLOTS + 1));
list_move(&mmu->list, &pfdev->as_lru_list); list_move(&mmu->list, &pfdev->as_lru_list);
if (pfdev->as_faulty_mask & mask) {
/* Unhandled pagefault on this AS, the MMU was
* disabled. We need to re-enable the MMU after
* clearing+unmasking the AS interrupts.
*/
mmu_write(pfdev, MMU_INT_CLEAR, mask);
mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
pfdev->as_faulty_mask &= ~mask;
panfrost_mmu_enable(pfdev, mmu);
}
goto out; goto out;
} }
...@@ -211,6 +224,7 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev) ...@@ -211,6 +224,7 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
spin_lock(&pfdev->as_lock); spin_lock(&pfdev->as_lock);
pfdev->as_alloc_mask = 0; pfdev->as_alloc_mask = 0;
pfdev->as_faulty_mask = 0;
list_for_each_entry_safe(mmu, mmu_tmp, &pfdev->as_lru_list, list) { list_for_each_entry_safe(mmu, mmu_tmp, &pfdev->as_lru_list, list) {
mmu->as = -1; mmu->as = -1;
...@@ -661,7 +675,7 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data) ...@@ -661,7 +675,7 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
if ((status & mask) == BIT(as) && (exception_type & 0xF8) == 0xC0) if ((status & mask) == BIT(as) && (exception_type & 0xF8) == 0xC0)
ret = panfrost_mmu_map_fault_addr(pfdev, as, addr); ret = panfrost_mmu_map_fault_addr(pfdev, as, addr);
if (ret) if (ret) {
/* terminal fault, print info about the fault */ /* terminal fault, print info about the fault */
dev_err(pfdev->dev, dev_err(pfdev->dev,
"Unhandled Page fault in AS%d at VA 0x%016llX\n" "Unhandled Page fault in AS%d at VA 0x%016llX\n"
...@@ -679,14 +693,28 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data) ...@@ -679,14 +693,28 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
access_type, access_type_name(pfdev, fault_status), access_type, access_type_name(pfdev, fault_status),
source_id); source_id);
spin_lock(&pfdev->as_lock);
/* Ignore MMU interrupts on this AS until it's been
* re-enabled.
*/
pfdev->as_faulty_mask |= mask;
/* Disable the MMU to kill jobs on this AS. */
panfrost_mmu_disable(pfdev, as);
spin_unlock(&pfdev->as_lock);
}
status &= ~mask; status &= ~mask;
/* If we received new MMU interrupts, process them before returning. */ /* If we received new MMU interrupts, process them before returning. */
if (!status) if (!status)
status = mmu_read(pfdev, MMU_INT_RAWSTAT); status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask;
} }
mmu_write(pfdev, MMU_INT_MASK, ~0); spin_lock(&pfdev->as_lock);
mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
spin_unlock(&pfdev->as_lock);
return IRQ_HANDLED; return IRQ_HANDLED;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment