summaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/midgard/mali_kbase_mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/arm/midgard/mali_kbase_mmu.c')
-rw-r--r--drivers/gpu/arm/midgard/mali_kbase_mmu.c503
1 files changed, 110 insertions, 393 deletions
diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu.c b/drivers/gpu/arm/midgard/mali_kbase_mmu.c
index 48d53723a9b4..d81ef593e928 100644
--- a/drivers/gpu/arm/midgard/mali_kbase_mmu.c
+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu.c
@@ -1,6 +1,6 @@
/*
*
- * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@@ -30,8 +30,9 @@
#if defined(CONFIG_MALI_GATOR_SUPPORT)
#include <mali_kbase_gator.h>
#endif
+#if defined(CONFIG_MALI_MIPE_ENABLED)
#include <mali_kbase_tlstream.h>
-#include <mali_kbase_instr_defs.h>
+#endif
#include <mali_kbase_debug.h>
#define beenthere(kctx, f, a...) dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a)
@@ -40,32 +41,10 @@
#include <mali_kbase_hw.h>
#include <mali_kbase_mmu_hw.h>
#include <mali_kbase_hwaccess_jm.h>
-#include <mali_kbase_time.h>
#define KBASE_MMU_PAGE_ENTRIES 512
/**
- * kbase_mmu_flush_invalidate() - Flush and invalidate the GPU caches.
- * @kctx: The KBase context.
- * @vpfn: The virtual page frame number to start the flush on.
- * @nr: The number of pages to flush.
- * @sync: Set if the operation should be synchronous or not.
- *
- * Issue a cache flush + invalidate to the GPU caches and invalidate the TLBs.
- *
- * If sync is not set then transactions still in flight when the flush is issued
- * may use the old page tables and the data they write will not be written out
- * to memory, this function returns after the flush has been issued but
- * before all accesses which might effect the flushed region have completed.
- *
- * If sync is set then accesses in the flushed region will be drained
- * before data is flush and invalidated through L1, L2 and into memory,
- * after which point this function will return.
- */
-static void kbase_mmu_flush_invalidate(struct kbase_context *kctx,
- u64 vpfn, size_t nr, bool sync);
-
-/**
* kbase_mmu_sync_pgd - sync page directory to memory
* @kbdev: Device pointer.
* @handle: Address of DMA region.
@@ -77,12 +56,8 @@ static void kbase_mmu_flush_invalidate(struct kbase_context *kctx,
static void kbase_mmu_sync_pgd(struct kbase_device *kbdev,
dma_addr_t handle, size_t size)
{
- /* If page table is not coherent then ensure the gpu can read
- * the pages from memory
- */
- if (kbdev->system_coherency != COHERENCY_ACE)
- dma_sync_single_for_device(kbdev->dev, handle, size,
- DMA_TO_DEVICE);
+
+ dma_sync_single_for_device(kbdev->dev, handle, size, DMA_TO_DEVICE);
}
/*
@@ -161,18 +136,6 @@ void page_fault_worker(struct work_struct *data)
dev_warn(kbdev->dev, "Access flag unexpectedly set");
goto fault_done;
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- case AS_FAULTSTATUS_EXCEPTION_CODE_ADDRESS_SIZE_FAULT:
-
- kbase_mmu_report_fault_and_kill(kctx, faulting_as,
- "Address size fault");
- goto fault_done;
-
- case AS_FAULTSTATUS_EXCEPTION_CODE_MEMORY_ATTRIBUTES_FAULT:
- kbase_mmu_report_fault_and_kill(kctx, faulting_as,
- "Memory attributes fault");
- goto fault_done;
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
default:
kbase_mmu_report_fault_and_kill(kctx, faulting_as,
@@ -201,13 +164,6 @@ void page_fault_worker(struct work_struct *data)
goto fault_done;
}
- if ((region->flags & KBASE_REG_DONT_NEED)) {
- kbase_gpu_vm_unlock(kctx);
- kbase_mmu_report_fault_and_kill(kctx, faulting_as,
- "Don't need memory can't be grown");
- goto fault_done;
- }
-
/* find the size we need to grow it by */
/* we know the result fit in a size_t due to kbase_region_tracker_find_region_enclosing_address
* validating the fault_adress to be within a size_t from the start_pfn */
@@ -277,27 +233,19 @@ void page_fault_worker(struct work_struct *data)
if (grown) {
- u64 pfn_offset;
u32 op;
/* alloc success */
KBASE_DEBUG_ASSERT(kbase_reg_current_backed_size(region) <= region->nr_pages);
+ /* AS transaction begin */
+ mutex_lock(&faulting_as->transaction_mutex);
+
/* set up the new pages */
- pfn_offset = kbase_reg_current_backed_size(region) - new_pages;
- /*
- * Note:
- * Issuing an MMU operation will unlock the MMU and cause the
- * translation to be replayed. If the page insertion fails then
- * rather then trying to continue the context should be killed
- * so the no_flush version of insert_pages is used which allows
- * us to unlock the MMU as we see fit.
- */
- err = kbase_mmu_insert_pages_no_flush(kctx,
- region->start_pfn + pfn_offset,
- &kbase_get_gpu_phy_pages(region)[pfn_offset],
- new_pages, region->flags);
+ err = kbase_mmu_insert_pages(kctx, region->start_pfn + kbase_reg_current_backed_size(region) - new_pages, &kbase_get_gpu_phy_pages(region)[kbase_reg_current_backed_size(region) - new_pages], new_pages, region->flags);
if (err) {
+ /* failed to insert pages, handle as a normal PF */
+ mutex_unlock(&faulting_as->transaction_mutex);
kbase_free_phy_pages_helper(region->gpu_alloc, new_pages);
if (region->gpu_alloc != region->cpu_alloc)
kbase_free_phy_pages_helper(region->cpu_alloc,
@@ -311,10 +259,9 @@ void page_fault_worker(struct work_struct *data)
#if defined(CONFIG_MALI_GATOR_SUPPORT)
kbase_trace_mali_page_fault_insert_pages(as_no, new_pages);
#endif
+#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagefault(kctx->id, (u64)new_pages);
-
- /* AS transaction begin */
- mutex_lock(&faulting_as->transaction_mutex);
+#endif
/* flush L2 and unlock the VA (resumes the MMU) */
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6367))
@@ -377,9 +324,11 @@ phys_addr_t kbase_mmu_alloc_pgd(struct kbase_context *kctx)
if (!p)
goto sub_pages;
+#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
+#endif
page = kmap(p);
if (NULL == page)
@@ -416,7 +365,7 @@ static phys_addr_t mmu_get_next_pgd(struct kbase_context *kctx, phys_addr_t pgd,
KBASE_DEBUG_ASSERT(pgd);
KBASE_DEBUG_ASSERT(NULL != kctx);
- lockdep_assert_held(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
/*
* Architecture spec defines level-0 as being the top-most.
@@ -457,9 +406,8 @@ static phys_addr_t mmu_get_bottom_pgd(struct kbase_context *kctx, u64 vpfn)
phys_addr_t pgd;
int l;
- lockdep_assert_held(&kctx->mmu_lock);
-
pgd = kctx->pgd;
+
for (l = MIDGARD_MMU_TOPLEVEL; l < MIDGARD_MMU_BOTTOMLEVEL; l++) {
pgd = mmu_get_next_pgd(kctx, pgd, vpfn, l);
/* Handle failure condition */
@@ -480,7 +428,7 @@ static phys_addr_t mmu_insert_pages_recover_get_next_pgd(struct kbase_context *k
KBASE_DEBUG_ASSERT(pgd);
KBASE_DEBUG_ASSERT(NULL != kctx);
- lockdep_assert_held(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
/*
* Architecture spec defines level-0 as being the top-most.
@@ -505,8 +453,6 @@ static phys_addr_t mmu_insert_pages_recover_get_bottom_pgd(struct kbase_context
phys_addr_t pgd;
int l;
- lockdep_assert_held(&kctx->mmu_lock);
-
pgd = kctx->pgd;
for (l = MIDGARD_MMU_TOPLEVEL; l < MIDGARD_MMU_BOTTOMLEVEL; l++) {
@@ -530,7 +476,7 @@ static void mmu_insert_pages_failure_recovery(struct kbase_context *kctx, u64 vp
/* 64-bit address range is the max */
KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE));
- lockdep_assert_held(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
mmu_mode = kctx->kbdev->mmu_mode;
@@ -578,28 +524,22 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn,
bool recover_required = false;
u64 recover_vpfn = vpfn;
size_t recover_count = 0;
- size_t remain = nr;
- int err;
KBASE_DEBUG_ASSERT(NULL != kctx);
KBASE_DEBUG_ASSERT(0 != vpfn);
/* 64-bit address range is the max */
KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE));
- /* Early out if there is nothing to do */
- if (nr == 0)
- return 0;
-
- mutex_lock(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
- while (remain) {
+ while (nr) {
unsigned int i;
unsigned int index = vpfn & 0x1FF;
unsigned int count = KBASE_MMU_PAGE_ENTRIES - index;
struct page *p;
- if (count > remain)
- count = remain;
+ if (count > nr)
+ count = nr;
/*
* Repeatedly calling mmu_get_bottom_pte() is clearly
@@ -618,8 +558,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn,
recover_vpfn,
recover_count);
}
- err = -EINVAL;
- goto fail_unlock;
+ return -EINVAL;
}
p = pfn_to_page(PFN_DOWN(pgd));
@@ -633,8 +572,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn,
recover_vpfn,
recover_count);
}
- err = -ENOMEM;
- goto fail_unlock;
+ return -ENOMEM;
}
for (i = 0; i < count; i++) {
@@ -646,7 +584,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn,
}
vpfn += count;
- remain -= count;
+ nr -= count;
kbase_mmu_sync_pgd(kctx->kbdev,
kbase_dma_addr(p) + (index * sizeof(u64)),
@@ -659,17 +597,13 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn,
recover_required = true;
recover_count += count;
}
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, nr, false);
return 0;
-
-fail_unlock:
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, nr, false);
- return err;
}
-int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
+/*
+ * Map 'nr' pages pointed to by 'phys' at GPU PFN 'vpfn'
+ */
+int kbase_mmu_insert_pages(struct kbase_context *kctx, u64 vpfn,
phys_addr_t *phys, size_t nr,
unsigned long flags)
{
@@ -680,28 +614,22 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
bool recover_required = false;
u64 recover_vpfn = vpfn;
size_t recover_count = 0;
- size_t remain = nr;
- int err;
KBASE_DEBUG_ASSERT(NULL != kctx);
KBASE_DEBUG_ASSERT(0 != vpfn);
/* 64-bit address range is the max */
KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE));
- /* Early out if there is nothing to do */
- if (nr == 0)
- return 0;
-
- mutex_lock(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
- while (remain) {
+ while (nr) {
unsigned int i;
unsigned int index = vpfn & 0x1FF;
unsigned int count = KBASE_MMU_PAGE_ENTRIES - index;
struct page *p;
- if (count > remain)
- count = remain;
+ if (count > nr)
+ count = nr;
/*
* Repeatedly calling mmu_get_bottom_pte() is clearly
@@ -720,8 +648,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
recover_vpfn,
recover_count);
}
- err = -EINVAL;
- goto fail_unlock;
+ return -EINVAL;
}
p = pfn_to_page(PFN_DOWN(pgd));
@@ -735,8 +662,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
recover_vpfn,
recover_count);
}
- err = -ENOMEM;
- goto fail_unlock;
+ return -ENOMEM;
}
for (i = 0; i < count; i++) {
@@ -749,7 +675,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
phys += count;
vpfn += count;
- remain -= count;
+ nr -= count;
kbase_mmu_sync_pgd(kctx->kbdev,
kbase_dma_addr(p) + (index * sizeof(u64)),
@@ -762,209 +688,81 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn,
recover_required = true;
recover_count += count;
}
-
- mutex_unlock(&kctx->mmu_lock);
return 0;
-
-fail_unlock:
- mutex_unlock(&kctx->mmu_lock);
- return err;
-}
-
-/*
- * Map 'nr' pages pointed to by 'phys' at GPU PFN 'vpfn'
- */
-int kbase_mmu_insert_pages(struct kbase_context *kctx, u64 vpfn,
- phys_addr_t *phys, size_t nr,
- unsigned long flags)
-{
- int err;
-
- err = kbase_mmu_insert_pages_no_flush(kctx, vpfn, phys, nr, flags);
- kbase_mmu_flush_invalidate(kctx, vpfn, nr, false);
- return err;
}
KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages);
/**
- * kbase_mmu_flush_invalidate_noretain() - Flush and invalidate the GPU caches
- * without retaining the kbase context.
- * @kctx: The KBase context.
- * @vpfn: The virtual page frame number to start the flush on.
- * @nr: The number of pages to flush.
- * @sync: Set if the operation should be synchronous or not.
+ * This function is responsible for validating the MMU PTs
+ * triggering reguired flushes.
*
- * As per kbase_mmu_flush_invalidate but doesn't retain the kctx or do any
- * other locking.
+ * * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is
+ * currently scheduled into the runpool, and so potentially uses a lot of locks.
+ * These locks must be taken in the correct order with respect to others
+ * already held by the caller. Refer to kbasep_js_runpool_release_ctx() for more
+ * information.
*/
-static void kbase_mmu_flush_invalidate_noretain(struct kbase_context *kctx,
- u64 vpfn, size_t nr, bool sync)
-{
- struct kbase_device *kbdev = kctx->kbdev;
- int err;
- u32 op;
-
- /* Early out if there is nothing to do */
- if (nr == 0)
- return;
-
- if (sync)
- op = AS_COMMAND_FLUSH_MEM;
- else
- op = AS_COMMAND_FLUSH_PT;
-
- err = kbase_mmu_hw_do_operation(kbdev,
- &kbdev->as[kctx->as_nr],
- kctx, vpfn, nr, op, 0);
-#if KBASE_GPU_RESET_EN
- if (err) {
- /* Flush failed to complete, assume the
- * GPU has hung and perform a reset to
- * recover */
- dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover\n");
-
- if (kbase_prepare_to_reset_gpu_locked(kbdev))
- kbase_reset_gpu_locked(kbdev);
- }
-#endif /* KBASE_GPU_RESET_EN */
-
-#ifndef CONFIG_MALI_NO_MALI
- /*
- * As this function could be called in interrupt context the sync
- * request can't block. Instead log the request and the next flush
- * request will pick it up.
- */
- if ((!err) && sync &&
- kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_6367))
- atomic_set(&kctx->drain_pending, 1);
-#endif /* !CONFIG_MALI_NO_MALI */
-}
-
-static void kbase_mmu_flush_invalidate(struct kbase_context *kctx,
- u64 vpfn, size_t nr, bool sync)
+static void kbase_mmu_flush(struct kbase_context *kctx, u64 vpfn, size_t nr)
{
struct kbase_device *kbdev;
bool ctx_is_in_runpool;
-#ifndef CONFIG_MALI_NO_MALI
- bool drain_pending = false;
- if (atomic_xchg(&kctx->drain_pending, 0))
- drain_pending = true;
-#endif /* !CONFIG_MALI_NO_MALI */
-
- /* Early out if there is nothing to do */
- if (nr == 0)
- return;
+ KBASE_DEBUG_ASSERT(NULL != kctx);
kbdev = kctx->kbdev;
+
+ /* We must flush if we're currently running jobs. At the very least, we need to retain the
+ * context to ensure it doesn't schedule out whilst we're trying to flush it */
ctx_is_in_runpool = kbasep_js_runpool_retain_ctx(kbdev, kctx);
if (ctx_is_in_runpool) {
KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
- if (!kbase_pm_context_active_handle_suspend(kbdev,
- KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) {
- int err;
- u32 op;
-
- /* AS transaction begin */
- mutex_lock(&kbdev->as[
- kctx->as_nr].transaction_mutex);
-
- if (sync)
- op = AS_COMMAND_FLUSH_MEM;
- else
- op = AS_COMMAND_FLUSH_PT;
-
- err = kbase_mmu_hw_do_operation(kbdev,
- &kbdev->as[kctx->as_nr],
- kctx, vpfn, nr, op, 0);
-
+ /* Second level check is to try to only do this when jobs are running. The refcount is
+ * a heuristic for this. */
+ if (kbdev->js_data.runpool_irq.per_as_data[kctx->as_nr].as_busy_refcount >= 2) {
+ if (!kbase_pm_context_active_handle_suspend(kbdev,
+ KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) {
+ int ret;
+ u32 op;
+
+ /* AS transaction begin */
+ mutex_lock(&kbdev->as[
+ kctx->as_nr].transaction_mutex);
+
+ if (kbase_hw_has_issue(kbdev,
+ BASE_HW_ISSUE_6367))
+ op = AS_COMMAND_FLUSH;
+ else
+ op = AS_COMMAND_FLUSH_MEM;
+
+ ret = kbase_mmu_hw_do_operation(kbdev,
+ &kbdev->as[kctx->as_nr],
+ kctx, vpfn, nr,
+ op, 0);
#if KBASE_GPU_RESET_EN
- if (err) {
- /* Flush failed to complete, assume the
- * GPU has hung and perform a reset to
- * recover */
- dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issueing GPU soft-reset to recover\n");
-
- if (kbase_prepare_to_reset_gpu(kbdev))
- kbase_reset_gpu(kbdev);
- }
+ if (ret) {
+ /* Flush failed to complete, assume the
+ * GPU has hung and perform a reset to
+ * recover */
+ dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issueing GPU soft-reset to recover\n");
+ if (kbase_prepare_to_reset_gpu(kbdev))
+ kbase_reset_gpu(kbdev);
+ }
#endif /* KBASE_GPU_RESET_EN */
- mutex_unlock(&kbdev->as[
- kctx->as_nr].transaction_mutex);
- /* AS transaction end */
+ mutex_unlock(&kbdev->as[
+ kctx->as_nr].transaction_mutex);
+ /* AS transaction end */
-#ifndef CONFIG_MALI_NO_MALI
- /*
- * The transaction lock must be dropped before here
- * as kbase_wait_write_flush could take it if
- * the GPU was powered down (static analysis doesn't
- * know this can't happen).
- */
- drain_pending |= (!err) && sync &&
- kbase_hw_has_issue(kctx->kbdev,
- BASE_HW_ISSUE_6367);
- if (drain_pending) {
- /* Wait for GPU to flush write buffer */
- kbase_wait_write_flush(kctx);
+ kbase_pm_context_idle(kbdev);
}
-#endif /* !CONFIG_MALI_NO_MALI */
-
- kbase_pm_context_idle(kbdev);
}
kbasep_js_runpool_release_ctx(kbdev, kctx);
}
}
-void kbase_mmu_update(struct kbase_context *kctx)
-{
- lockdep_assert_held(&kctx->kbdev->js_data.runpool_irq.lock);
- /* ASSERT that the context has a valid as_nr, which is only the case
- * when it's scheduled in.
- *
- * as_nr won't change because the caller has the runpool_irq lock */
- KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
- lockdep_assert_held(&kctx->kbdev->as[kctx->as_nr].transaction_mutex);
-
- kctx->kbdev->mmu_mode->update(kctx);
-}
-KBASE_EXPORT_TEST_API(kbase_mmu_update);
-
-void kbase_mmu_disable_as(struct kbase_device *kbdev, int as_nr)
-{
- lockdep_assert_held(&kbdev->as[as_nr].transaction_mutex);
- lockdep_assert_held(&kbdev->js_data.runpool_irq.lock);
-
- kbdev->mmu_mode->disable_as(kbdev, as_nr);
-}
-
-void kbase_mmu_disable(struct kbase_context *kctx)
-{
- /* ASSERT that the context has a valid as_nr, which is only the case
- * when it's scheduled in.
- *
- * as_nr won't change because the caller has the runpool_irq lock */
- KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
-
- lockdep_assert_held(&kctx->kbdev->as[kctx->as_nr].transaction_mutex);
- lockdep_assert_held(&kctx->kbdev->js_data.runpool_irq.lock);
-
- /*
- * The address space is being disabled, drain all knowledge of it out
- * from the caches as pages and page tables might be freed after this.
- *
- * The job scheduler code will already be holding the locks and context
- * so just do the flush.
- */
- kbase_mmu_flush_invalidate_noretain(kctx, 0, ~0, true);
-
- kctx->kbdev->mmu_mode->disable_as(kctx->kbdev, kctx->as_nr);
-}
-KBASE_EXPORT_TEST_API(kbase_mmu_disable);
-
/*
* We actually only discard the ATE, and not the page table
* pages. There is a potential DoS here, as we'll leak memory by
@@ -984,18 +782,17 @@ int kbase_mmu_teardown_pages(struct kbase_context *kctx, u64 vpfn, size_t nr)
struct kbase_device *kbdev;
size_t requested_nr = nr;
struct kbase_mmu_mode const *mmu_mode;
- int err;
KBASE_DEBUG_ASSERT(NULL != kctx);
beenthere(kctx, "kctx %p vpfn %lx nr %zd", (void *)kctx, (unsigned long)vpfn, nr);
+ lockdep_assert_held(&kctx->reg_lock);
+
if (0 == nr) {
/* early out if nothing to do */
return 0;
}
- mutex_lock(&kctx->mmu_lock);
-
kbdev = kctx->kbdev;
mmu_mode = kbdev->mmu_mode;
@@ -1011,16 +808,14 @@ int kbase_mmu_teardown_pages(struct kbase_context *kctx, u64 vpfn, size_t nr)
pgd = mmu_get_bottom_pgd(kctx, vpfn);
if (!pgd) {
dev_warn(kbdev->dev, "kbase_mmu_teardown_pages: mmu_get_bottom_pgd failure\n");
- err = -EINVAL;
- goto fail_unlock;
+ return -EINVAL;
}
p = pfn_to_page(PFN_DOWN(pgd));
pgd_page = kmap(p);
if (!pgd_page) {
dev_warn(kbdev->dev, "kbase_mmu_teardown_pages: kmap failure\n");
- err = -ENOMEM;
- goto fail_unlock;
+ return -ENOMEM;
}
for (i = 0; i < count; i++)
@@ -1036,14 +831,8 @@ int kbase_mmu_teardown_pages(struct kbase_context *kctx, u64 vpfn, size_t nr)
kunmap(p);
}
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true);
+ kbase_mmu_flush(kctx, vpfn, requested_nr);
return 0;
-
-fail_unlock:
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true);
- return err;
}
KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages);
@@ -1066,17 +855,12 @@ int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, phys_addr_t *ph
u64 *pgd_page;
size_t requested_nr = nr;
struct kbase_mmu_mode const *mmu_mode;
- int err;
KBASE_DEBUG_ASSERT(NULL != kctx);
KBASE_DEBUG_ASSERT(0 != vpfn);
KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE));
- /* Early out if there is nothing to do */
- if (nr == 0)
- return 0;
-
- mutex_lock(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
mmu_mode = kctx->kbdev->mmu_mode;
@@ -1095,16 +879,14 @@ int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, phys_addr_t *ph
pgd = mmu_get_bottom_pgd(kctx, vpfn);
if (!pgd) {
dev_warn(kctx->kbdev->dev, "mmu_get_bottom_pgd failure\n");
- err = -EINVAL;
- goto fail_unlock;
+ return -EINVAL;
}
p = pfn_to_page(PFN_DOWN(pgd));
pgd_page = kmap(p);
if (!pgd_page) {
dev_warn(kctx->kbdev->dev, "kmap failure\n");
- err = -ENOMEM;
- goto fail_unlock;
+ return -ENOMEM;
}
for (i = 0; i < count; i++)
@@ -1122,14 +904,9 @@ int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, phys_addr_t *ph
kunmap(pfn_to_page(PFN_DOWN(pgd)));
}
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true);
- return 0;
+ kbase_mmu_flush(kctx, vpfn, requested_nr);
-fail_unlock:
- mutex_unlock(&kctx->mmu_lock);
- kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true);
- return err;
+ return 0;
}
/* This is a debug feature only */
@@ -1157,7 +934,7 @@ static void mmu_teardown_level(struct kbase_context *kctx, phys_addr_t pgd, int
struct kbase_mmu_mode const *mmu_mode;
KBASE_DEBUG_ASSERT(NULL != kctx);
- lockdep_assert_held(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
pgd_page = kmap_atomic(pfn_to_page(PFN_DOWN(pgd)));
/* kmap_atomic should NEVER fail. */
@@ -1202,8 +979,6 @@ int kbase_mmu_init(struct kbase_context *kctx)
KBASE_DEBUG_ASSERT(NULL != kctx);
KBASE_DEBUG_ASSERT(NULL == kctx->mmu_teardown_pages);
- mutex_init(&kctx->mmu_lock);
-
/* Preallocate MMU depth of four pages for mmu_teardown_level to use */
kctx->mmu_teardown_pages = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
@@ -1229,9 +1004,9 @@ void kbase_mmu_free_pgd(struct kbase_context *kctx)
KBASE_DEBUG_ASSERT(NULL != kctx);
KBASE_DEBUG_ASSERT(NULL != kctx->mmu_teardown_pages);
- mutex_lock(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
+
mmu_teardown_level(kctx, kctx->pgd, MIDGARD_MMU_TOPLEVEL, 1, kctx->mmu_teardown_pages);
- mutex_unlock(&kctx->mmu_lock);
beenthere(kctx, "pgd %lx", (unsigned long)kctx->pgd);
kbase_mem_pool_free(&kctx->mem_pool, phys_to_page(kctx->pgd), true);
@@ -1239,9 +1014,11 @@ void kbase_mmu_free_pgd(struct kbase_context *kctx)
new_page_count = kbase_atomic_sub_pages(1, &kctx->used_pages);
kbase_atomic_sub_pages(1, &kctx->kbdev->memdev.used_pages);
+#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
+#endif
}
KBASE_EXPORT_TEST_API(kbase_mmu_free_pgd);
@@ -1256,7 +1033,7 @@ static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd,
struct kbase_mmu_mode const *mmu_mode;
KBASE_DEBUG_ASSERT(NULL != kctx);
- lockdep_assert_held(&kctx->mmu_lock);
+ lockdep_assert_held(&kctx->reg_lock);
mmu_mode = kctx->kbdev->mmu_mode;
@@ -1311,13 +1088,13 @@ void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages)
KBASE_DEBUG_ASSERT(kctx);
+ lockdep_assert_held(&kctx->reg_lock);
+
if (0 == nr_pages) {
/* can't dump in a 0 sized buffer, early out */
return NULL;
}
- mutex_lock(&kctx->mmu_lock);
-
size_left = nr_pages * PAGE_SIZE;
KBASE_DEBUG_ASSERT(0 != size_left);
@@ -1339,7 +1116,7 @@ void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages)
kctx->kbdev->mmu_mode->get_as_setup(kctx, &as_setup);
config[0] = as_setup.transtab;
config[1] = as_setup.memattr;
- config[2] = as_setup.transcfg;
+ config[2] = 0;
memcpy(buffer, &config, sizeof(config));
mmu_dump_buffer += sizeof(config);
size_left -= sizeof(config);
@@ -1353,8 +1130,10 @@ void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages)
&mmu_dump_buffer,
&size_left);
- if (!size)
- goto fail_free;
+ if (!size) {
+ vfree(kaddr);
+ return NULL;
+ }
/* Add on the size for the end marker */
size += sizeof(u64);
@@ -1365,20 +1144,15 @@ void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages)
if (size > nr_pages * PAGE_SIZE || size_left < sizeof(u64)) {
/* The buffer isn't big enough - free the memory and return failure */
- goto fail_free;
+ vfree(kaddr);
+ return NULL;
}
/* Add the end marker */
memcpy(mmu_dump_buffer, &end_marker, sizeof(u64));
}
- mutex_unlock(&kctx->mmu_lock);
return kaddr;
-
-fail_free:
- vfree(kaddr);
- mutex_unlock(&kctx->mmu_lock);
- return NULL;
}
KBASE_EXPORT_TEST_API(kbase_mmu_dump);
@@ -1419,17 +1193,13 @@ void bus_fault_worker(struct work_struct *data)
#endif /* KBASE_GPU_RESET_EN */
/* NOTE: If GPU already powered off for suspend, we don't need to switch to unmapped */
if (!kbase_pm_context_active_handle_suspend(kbdev, KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) {
- unsigned long flags;
/* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */
/* AS transaction begin */
mutex_lock(&kbdev->as[as_no].transaction_mutex);
/* Set the MMU into unmapped mode */
- spin_lock_irqsave(&kbdev->js_data.runpool_irq.lock, flags);
- kbase_mmu_disable(kctx);
- spin_unlock_irqrestore(&kbdev->js_data.runpool_irq.lock,
- flags);
+ kbase_mmu_disable_as(kbdev, as_no);
mutex_unlock(&kbdev->as[as_no].transaction_mutex);
/* AS transaction end */
@@ -1547,15 +1317,6 @@ const char *kbase_exception_name(struct kbase_device *kbdev, u32 exception_code)
e = "TRANSLATION_FAULT";
break;
case 0xC8:
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- case 0xC9:
- case 0xCA:
- case 0xCB:
- case 0xCC:
- case 0xCD:
- case 0xCE:
- case 0xCF:
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
e = "PERMISSION_FAULT";
break;
case 0xD0:
@@ -1569,38 +1330,8 @@ const char *kbase_exception_name(struct kbase_device *kbdev, u32 exception_code)
e = "TRANSTAB_BUS_FAULT";
break;
case 0xD8:
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- case 0xD9:
- case 0xDA:
- case 0xDB:
- case 0xDC:
- case 0xDD:
- case 0xDE:
- case 0xDF:
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
e = "ACCESS_FLAG";
break;
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- case 0xE0:
- case 0xE1:
- case 0xE2:
- case 0xE3:
- case 0xE4:
- case 0xE5:
- case 0xE6:
- case 0xE7:
- e = "ADDRESS_SIZE_FAULT";
- break;
- case 0xE8:
- case 0xE9:
- case 0xEA:
- case 0xEB:
- case 0xEC:
- case 0xED:
- case 0xEE:
- case 0xEF:
- e = "MEMORY_ATTRIBUTES_FAULT";
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
break;
default:
e = "UNKNOWN";
@@ -1614,12 +1345,7 @@ static const char *access_type_name(struct kbase_device *kbdev,
u32 fault_status)
{
switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) {
- case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC:
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- return "ATOMIC";
-#else
return "UNKNOWN";
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
case AS_FAULTSTATUS_ACCESS_TYPE_READ:
return "READ";
case AS_FAULTSTATUS_ACCESS_TYPE_WRITE:
@@ -1715,9 +1441,7 @@ static void kbase_mmu_report_fault_and_kill(struct kbase_context *kctx,
}
#endif /* KBASE_GPU_RESET_EN */
/* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */
- spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
- kbase_mmu_disable(kctx);
- spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ kbase_mmu_disable_as(kbdev, as_no);
mutex_unlock(&as->transaction_mutex);
/* AS transaction end */
@@ -1954,15 +1678,8 @@ void kbase_mmu_interrupt_process(struct kbase_device *kbdev, struct kbase_contex
*/
kbasep_js_clear_submit_allowed(js_devdata, kctx);
-#ifdef CONFIG_MALI_GPU_MMU_AARCH64
- dev_warn(kbdev->dev,
- "Bus error in AS%d at VA=0x%016llx, IPA=0x%016llx\n",
- as->number, as->fault_addr,
- as->fault_extra_addr);
-#else
dev_warn(kbdev->dev, "Bus error in AS%d at 0x%016llx\n",
as->number, as->fault_addr);
-#endif /* CONFIG_MALI_GPU_MMU_AARCH64 */
/*
* We need to switch to UNMAPPED mode - but we do this in a