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: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-by: Steven Price <steven.price@arm.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210630062751.2832545-12-boris.brezillon@collabora.com
This commit is contained in:
parent
1d0cab5461
commit
ed7a34c57d
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user