summaryrefslogtreecommitdiff
path: root/mali_kbase/mmu
diff options
context:
space:
mode:
authorJörg Wagner <jorwag@google.com>2023-08-31 19:15:13 +0000
committerJörg Wagner <jorwag@google.com>2023-09-01 09:13:55 +0000
commitb6fd708b3a4da86a196a61592ea3585f1aca7313 (patch)
tree1cbe3029a45bf9869c17a5b6954e5ae074b44ac8 /mali_kbase/mmu
parent46edf1b5965d872c5f8a09c6dc3dcbff58f78a92 (diff)
parente61eb93296e9f940b32d4ad4b0c3a5557cbeaf17 (diff)
downloadgpu-b6fd708b3a4da86a196a61592ea3585f1aca7313.tar.gz
Merge r44p1-00dev3 from partner/upstream into android13-gs-pixel-5.10-udc-qpr1
Bug: 290882327 Change-Id: I90723cbaa3f294431087587fd8025f0688e51bf2
Diffstat (limited to 'mali_kbase/mmu')
-rw-r--r--mali_kbase/mmu/backend/mali_kbase_mmu_csf.c48
-rw-r--r--mali_kbase/mmu/backend/mali_kbase_mmu_jm.c31
-rw-r--r--mali_kbase/mmu/mali_kbase_mmu.c294
-rw-r--r--mali_kbase/mmu/mali_kbase_mmu.h86
-rw-r--r--mali_kbase/mmu/mali_kbase_mmu_hw.h4
-rw-r--r--mali_kbase/mmu/mali_kbase_mmu_hw_direct.c56
6 files changed, 307 insertions, 212 deletions
diff --git a/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c b/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
index 4cac787..a057d3c 100644
--- a/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
+++ b/mali_kbase/mmu/backend/mali_kbase_mmu_csf.c
@@ -146,8 +146,7 @@ void kbase_gpu_report_bus_fault_and_kill(struct kbase_context *kctx,
GPU_FAULTSTATUS_ACCESS_TYPE_SHIFT;
int source_id = (status & GPU_FAULTSTATUS_SOURCE_ID_MASK) >>
GPU_FAULTSTATUS_SOURCE_ID_SHIFT;
- const char *addr_valid = (status & GPU_FAULTSTATUS_ADDR_VALID_FLAG) ?
- "true" : "false";
+ const char *addr_valid = (status & GPU_FAULTSTATUS_ADDRESS_VALID_MASK) ? "true" : "false";
int as_no = as->number;
unsigned long flags;
const uintptr_t fault_addr = fault->addr;
@@ -247,12 +246,13 @@ void kbase_mmu_report_fault_and_kill(struct kbase_context *kctx,
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_mmu_disable(kctx);
kbase_ctx_flag_set(kctx, KCTX_AS_DISABLED_ON_FAULT);
+ kbase_debug_csf_fault_notify(kbdev, kctx, DF_GPU_PAGE_FAULT);
+ kbase_csf_ctx_report_page_fault_for_active_groups(kctx, fault);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
mutex_unlock(&kbdev->mmu_hw_mutex);
/* AS transaction end */
- kbase_debug_csf_fault_notify(kbdev, kctx, DF_GPU_PAGE_FAULT);
/* Switching to UNMAPPED mode above would have enabled the firmware to
* recover from the fault (if the memory access was made by firmware)
* and it can then respond to CSG termination requests to be sent now.
@@ -368,9 +368,9 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
/* remember current mask */
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
- new_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK));
+ new_mask = kbase_reg_read(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK));
/* mask interrupts for now */
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK), 0);
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
while (pf_bits) {
@@ -380,11 +380,11 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
struct kbase_fault *fault = &as->pf_data;
/* find faulting address */
- fault->addr = kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTADDRESS_HI));
+ fault->addr = kbase_reg_read(kbdev,
+ MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTADDRESS_HI)));
fault->addr <<= 32;
- fault->addr |= kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTADDRESS_LO));
+ fault->addr |= kbase_reg_read(
+ kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTADDRESS_LO)));
/* Mark the fault protected or not */
fault->protected_mode = false;
@@ -393,14 +393,14 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
kbase_as_fault_debugfs_new(kbdev, as_no);
/* record the fault status */
- fault->status = kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTSTATUS));
+ fault->status =
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTSTATUS)));
- fault->extra_addr = kbase_reg_read(kbdev,
- MMU_AS_REG(as_no, AS_FAULTEXTRA_HI));
+ fault->extra_addr =
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTEXTRA_HI)));
fault->extra_addr <<= 32;
- fault->extra_addr |= kbase_reg_read(kbdev,
- MMU_AS_REG(as_no, AS_FAULTEXTRA_LO));
+ fault->extra_addr |=
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTEXTRA_LO)));
/* Mark page fault as handled */
pf_bits &= ~(1UL << as_no);
@@ -432,9 +432,9 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
/* reenable interrupts */
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
- tmp = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK));
+ tmp = kbase_reg_read(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK));
new_mask |= tmp;
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), new_mask);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK), new_mask);
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
}
@@ -470,19 +470,16 @@ static void kbase_mmu_gpu_fault_worker(struct work_struct *data)
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
fault = &faulting_as->gf_data;
status = fault->status;
- as_valid = status & GPU_FAULTSTATUS_JASID_VALID_FLAG;
+ as_valid = status & GPU_FAULTSTATUS_JASID_VALID_MASK;
address = fault->addr;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
dev_warn(kbdev->dev,
"GPU Fault 0x%08x (%s) in AS%u at 0x%016llx\n"
"ASID_VALID: %s, ADDRESS_VALID: %s\n",
- status,
- kbase_gpu_exception_name(
- GPU_FAULTSTATUS_EXCEPTION_TYPE_GET(status)),
- as_nr, address,
- as_valid ? "true" : "false",
- status & GPU_FAULTSTATUS_ADDR_VALID_FLAG ? "true" : "false");
+ status, kbase_gpu_exception_name(GPU_FAULTSTATUS_EXCEPTION_TYPE_GET(status)),
+ as_nr, address, as_valid ? "true" : "false",
+ status & GPU_FAULTSTATUS_ADDRESS_VALID_MASK ? "true" : "false");
kctx = kbase_ctx_sched_as_to_ctx(kbdev, as_nr);
kbase_csf_ctx_handle_fault(kctx, fault);
@@ -558,9 +555,8 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i)
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
kbdev->as[i].gf_data.addr = 0ULL;
- kbdev->as[i].is_unresponsive = false;
- kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 1, i);
+ kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 0, i);
if (!kbdev->as[i].pf_wq)
return -ENOMEM;
diff --git a/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c b/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
index d716ce0..5c774c2 100644
--- a/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
+++ b/mali_kbase/mmu/backend/mali_kbase_mmu_jm.c
@@ -322,9 +322,9 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
/* remember current mask */
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
- new_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK));
+ new_mask = kbase_reg_read(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK));
/* mask interrupts for now */
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK), 0);
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
while (bf_bits | pf_bits) {
@@ -355,11 +355,11 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
kctx = kbase_ctx_sched_as_to_ctx_refcount(kbdev, as_no);
/* find faulting address */
- fault->addr = kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTADDRESS_HI));
+ fault->addr = kbase_reg_read(kbdev,
+ MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTADDRESS_HI)));
fault->addr <<= 32;
- fault->addr |= kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTADDRESS_LO));
+ fault->addr |= kbase_reg_read(
+ kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTADDRESS_LO)));
/* Mark the fault protected or not */
fault->protected_mode = kbdev->protected_mode;
@@ -372,13 +372,13 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
kbase_as_fault_debugfs_new(kbdev, as_no);
/* record the fault status */
- fault->status = kbase_reg_read(kbdev, MMU_AS_REG(as_no,
- AS_FAULTSTATUS));
- fault->extra_addr = kbase_reg_read(kbdev,
- MMU_AS_REG(as_no, AS_FAULTEXTRA_HI));
+ fault->status =
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTSTATUS)));
+ fault->extra_addr =
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTEXTRA_HI)));
fault->extra_addr <<= 32;
- fault->extra_addr |= kbase_reg_read(kbdev,
- MMU_AS_REG(as_no, AS_FAULTEXTRA_LO));
+ fault->extra_addr |=
+ kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_no, AS_FAULTEXTRA_LO)));
if (kbase_as_has_bus_fault(as, fault)) {
/* Mark bus fault as handled.
@@ -406,9 +406,9 @@ void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
/* reenable interrupts */
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
- tmp = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK));
+ tmp = kbase_reg_read(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK));
new_mask |= tmp;
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), new_mask);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK), new_mask);
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
dev_dbg(kbdev->dev, "Leaving %s irq_stat %u\n",
@@ -429,9 +429,8 @@ int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i)
kbdev->as[i].number = i;
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
- kbdev->as[i].is_unresponsive = false;
- kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%u", 0, 1, i);
+ kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%u", 0, 0, i);
if (!kbdev->as[i].pf_wq)
return -ENOMEM;
diff --git a/mali_kbase/mmu/mali_kbase_mmu.c b/mali_kbase/mmu/mali_kbase_mmu.c
index ccbd9c3..f8641a6 100644
--- a/mali_kbase/mmu/mali_kbase_mmu.c
+++ b/mali_kbase/mmu/mali_kbase_mmu.c
@@ -46,6 +46,7 @@
#if !MALI_USE_CSF
#include <mali_kbase_hwaccess_jm.h>
#endif
+#include <linux/version_compat_defs.h>
#include <mali_kbase_trace_gpu_mem.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
@@ -57,6 +58,11 @@
/* Macro to convert updated PDGs to flags indicating levels skip in flush */
#define pgd_level_to_skip_flush(dirty_pgds) (~(dirty_pgds) & 0xF)
+static int mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
+ const u64 start_vpfn, struct tagged_addr *phys, size_t nr,
+ unsigned long flags, int const group_id, u64 *dirty_pgds,
+ struct kbase_va_region *reg, bool ignore_page_migration);
+
/* Small wrapper function to factor out GPU-dependent context releasing */
static void release_ctx(struct kbase_device *kbdev,
struct kbase_context *kctx)
@@ -201,7 +207,7 @@ static void mmu_flush_invalidate_as(struct kbase_device *kbdev, struct kbase_as
mutex_lock(&kbdev->mmu_hw_mutex);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
- if (kbdev->pm.backend.gpu_powered && (kbase_mmu_hw_do_flush_locked(kbdev, as, op_param)))
+ if (kbdev->pm.backend.gpu_ready && (kbase_mmu_hw_do_flush_locked(kbdev, as, op_param)))
dev_err(kbdev->dev, "Flush for GPU page table update did not complete");
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
@@ -389,7 +395,7 @@ static bool kbase_mmu_handle_isolated_pgd_page(struct kbase_device *kbdev,
lockdep_assert_held(&mmut->mmu_lock);
- if (!kbase_page_migration_enabled)
+ if (!kbase_is_page_migration_enabled())
return false;
spin_lock(&page_md->migrate_lock);
@@ -404,8 +410,10 @@ static bool kbase_mmu_handle_isolated_pgd_page(struct kbase_device *kbdev,
page_md->status =
PAGE_STATUS_SET(page_md->status, FREE_IN_PROGRESS);
}
+ } else if ((PAGE_STATUS_GET(page_md->status) == FREE_IN_PROGRESS) ||
+ (PAGE_STATUS_GET(page_md->status) == ALLOCATE_IN_PROGRESS)) {
+ /* Nothing to do - fall through */
} else {
- WARN_ON_ONCE(mmut->kctx);
WARN_ON_ONCE(PAGE_STATUS_GET(page_md->status) != NOT_MOVABLE);
}
spin_unlock(&page_md->migrate_lock);
@@ -431,7 +439,7 @@ static bool kbase_mmu_handle_isolated_pgd_page(struct kbase_device *kbdev,
* @pgd: Physical address of page directory to be freed.
*
* This function is supposed to be called with mmu_lock held and after
- * ensuring that GPU won't be able to access the page.
+ * ensuring that the GPU won't be able to access the page.
*/
static void kbase_mmu_free_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
phys_addr_t pgd)
@@ -727,7 +735,7 @@ static void kbase_gpu_mmu_handle_permission_fault(struct kbase_context *kctx,
case AS_FAULTSTATUS_ACCESS_TYPE_WRITE:
kbase_gpu_mmu_handle_write_fault(kctx, faulting_as);
break;
- case AS_FAULTSTATUS_ACCESS_TYPE_EX:
+ case AS_FAULTSTATUS_ACCESS_TYPE_EXECUTE:
kbase_mmu_report_fault_and_kill(kctx, faulting_as,
"Execute Permission fault", fault);
break;
@@ -1293,10 +1301,11 @@ page_fault_retry:
* 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(
- kbdev, &kctx->mmu, region->start_pfn + pfn_offset,
- &kbase_get_gpu_phy_pages(region)[pfn_offset], new_pages, region->flags,
- region->gpu_alloc->group_id, &dirty_pgds, region, false);
+ err = mmu_insert_pages_no_flush(kbdev, &kctx->mmu, region->start_pfn + pfn_offset,
+ &kbase_get_gpu_phy_pages(region)[pfn_offset],
+ new_pages, region->flags,
+ region->gpu_alloc->group_id, &dirty_pgds, region,
+ false);
if (err) {
kbase_free_phy_pages_helper(region->gpu_alloc,
new_pages);
@@ -1480,7 +1489,8 @@ static phys_addr_t kbase_mmu_alloc_pgd(struct kbase_device *kbdev,
if (!p)
return KBASE_MMU_INVALID_PGD_ADDRESS;
- page = kmap(p);
+ page = kbase_kmap(p);
+
if (page == NULL)
goto alloc_free;
@@ -1513,7 +1523,7 @@ static phys_addr_t kbase_mmu_alloc_pgd(struct kbase_device *kbdev,
*/
kbase_mmu_sync_pgd_cpu(kbdev, kbase_dma_addr(p), PAGE_SIZE);
- kunmap(p);
+ kbase_kunmap(p, page);
return pgd;
alloc_free:
@@ -1553,7 +1563,7 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *
vpfn &= 0x1FF;
p = pfn_to_page(PFN_DOWN(*pgd));
- page = kmap(p);
+ page = kbase_kmap(p);
if (page == NULL) {
dev_err(kbdev->dev, "%s: kmap failure", __func__);
return -EINVAL;
@@ -1562,7 +1572,7 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *
if (!kbdev->mmu_mode->pte_is_valid(page[vpfn], level)) {
dev_dbg(kbdev->dev, "%s: invalid PTE at level %d vpfn 0x%llx", __func__, level,
vpfn);
- kunmap(p);
+ kbase_kunmap(p, page);
return -EFAULT;
} else {
target_pgd = kbdev->mmu_mode->pte_to_phy_addr(
@@ -1570,7 +1580,7 @@ static int mmu_get_next_pgd(struct kbase_device *kbdev, struct kbase_mmu_table *
kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[vpfn]));
}
- kunmap(p);
+ kbase_kunmap(p, page);
*pgd = target_pgd;
return 0;
@@ -1700,10 +1710,10 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev,
level <= MIDGARD_MMU_BOTTOMLEVEL; level++) {
idx = (vpfn >> ((3 - level) * 9)) & 0x1FF;
pgds[level] = pgd;
- page = kmap(p);
+ page = kbase_kmap(p);
if (mmu_mode->ate_is_valid(page[idx], level))
break; /* keep the mapping */
- kunmap(p);
+ kbase_kunmap(p, page);
pgd = mmu_mode->pte_to_phy_addr(kbdev->mgm_dev->ops.mgm_pte_to_original_pte(
kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[idx]));
p = phys_to_page(pgd);
@@ -1736,7 +1746,7 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev,
mmu_mode->entries_invalidate(&page[idx], pcount);
if (!num_of_valid_entries) {
- kunmap(p);
+ kbase_kunmap(p, page);
kbase_mmu_add_to_free_pgds_list(mmut, p);
@@ -1754,7 +1764,7 @@ static void mmu_insert_pages_failure_recovery(struct kbase_device *kbdev,
kbase_mmu_sync_pgd(kbdev, mmut->kctx, pgd + (idx * sizeof(u64)),
kbase_dma_addr(p) + sizeof(u64) * idx, sizeof(u64) * pcount,
KBASE_MMU_OP_NONE);
- kunmap(p);
+ kbase_kunmap(p, page);
next:
vpfn += count;
}
@@ -1764,7 +1774,7 @@ next:
* going to happen to these pages at this stage. They might return
* movable once they are returned to a memory pool.
*/
- if (kbase_page_migration_enabled && !ignore_page_migration && phys) {
+ if (kbase_is_page_migration_enabled() && !ignore_page_migration && phys) {
const u64 num_pages = to_vpfn - from_vpfn + 1;
u64 i;
@@ -1831,7 +1841,6 @@ static void mmu_flush_invalidate_insert_pages(struct kbase_device *kbdev,
* The bottom PGD level.
* @insert_level: The level of MMU page table where the chain of newly allocated
* PGDs needs to be linked-in/inserted.
- * The top-most PDG level to be updated.
* @insert_vpfn: The virtual page frame number for the ATE.
* @pgds_to_insert: Ptr to an array (size MIDGARD_MMU_BOTTOMLEVEL+1) that contains
* the physical addresses of newly allocated PGDs from index
@@ -1839,7 +1848,7 @@ static void mmu_flush_invalidate_insert_pages(struct kbase_device *kbdev,
* insert_level.
*
* The newly allocated PGDs are linked from the bottom level up and inserted into the PGD
- * at insert_level which already exists in the MMU Page Tables.Migration status is also
+ * at insert_level which already exists in the MMU Page Tables. Migration status is also
* updated for all the newly allocated PGD pages.
*
* Return:
@@ -1873,7 +1882,8 @@ static int update_parent_pgds(struct kbase_device *kbdev, struct kbase_mmu_table
goto failure_recovery;
}
- parent_page_va = kmap(parent_page);
+ parent_page_va = kbase_kmap(parent_page);
+
if (unlikely(parent_page_va == NULL)) {
dev_err(kbdev->dev, "%s: kmap failure", __func__);
err = -EINVAL;
@@ -1886,7 +1896,7 @@ static int update_parent_pgds(struct kbase_device *kbdev, struct kbase_mmu_table
parent_page_va[parent_vpfn] = kbdev->mgm_dev->ops.mgm_update_gpu_pte(
kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, parent_index, pte);
kbdev->mmu_mode->set_num_valid_entries(parent_page_va, current_valid_entries + 1);
- kunmap(parent_page);
+ kbase_kunmap(parent_page, parent_page_va);
if (parent_index != insert_level) {
/* Newly allocated PGDs */
@@ -1905,7 +1915,7 @@ static int update_parent_pgds(struct kbase_device *kbdev, struct kbase_mmu_table
}
/* Update the new target_pgd page to its stable state */
- if (kbase_page_migration_enabled) {
+ if (kbase_is_page_migration_enabled()) {
struct kbase_page_metadata *page_md =
kbase_page_private(phys_to_page(target_pgd));
@@ -1934,11 +1944,11 @@ failure_recovery:
for (; pgd_index < cur_level; pgd_index++) {
phys_addr_t pgd = pgds_to_insert[pgd_index];
struct page *pgd_page = pfn_to_page(PFN_DOWN(pgd));
- u64 *pgd_page_va = kmap(pgd_page);
+ u64 *pgd_page_va = kbase_kmap(pgd_page);
u64 vpfn = (insert_vpfn >> ((3 - pgd_index) * 9)) & 0x1FF;
kbdev->mmu_mode->entries_invalidate(&pgd_page_va[vpfn], 1);
- kunmap(pgd_page);
+ kbase_kunmap(pgd_page, pgd_page_va);
}
return err;
@@ -2001,10 +2011,11 @@ static int mmu_insert_alloc_pgds(struct kbase_device *kbdev, struct kbase_mmu_ta
return 0;
}
-int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn,
- struct tagged_addr phys, size_t nr, unsigned long flags,
- int const group_id, enum kbase_caller_mmu_sync_info mmu_sync_info,
- bool ignore_page_migration)
+static int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn,
+ struct tagged_addr phys, size_t nr, unsigned long flags,
+ int const group_id,
+ enum kbase_caller_mmu_sync_info mmu_sync_info,
+ bool ignore_page_migration)
{
phys_addr_t pgd;
u64 *pgd_page;
@@ -2034,7 +2045,7 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn,
/* If page migration is enabled, pages involved in multiple GPU mappings
* are always treated as not movable.
*/
- if (kbase_page_migration_enabled && !ignore_page_migration) {
+ if (kbase_is_page_migration_enabled() && !ignore_page_migration) {
struct page *phys_page = as_page(phys);
struct kbase_page_metadata *page_md = kbase_page_private(phys_page);
@@ -2099,7 +2110,8 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn,
}
p = pfn_to_page(PFN_DOWN(pgd));
- pgd_page = kmap(p);
+
+ pgd_page = kbase_kmap(p);
if (!pgd_page) {
dev_err(kbdev->dev, "%s: kmap failure", __func__);
err = -ENOMEM;
@@ -2147,14 +2159,14 @@ int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 start_vpfn,
kbdev->mmu_mode->entries_invalidate(&pgd_page[vindex], count);
- kunmap(p);
+ kbase_kunmap(p, pgd_page);
goto fail_unlock_free_pgds;
}
}
insert_vpfn += count;
remain -= count;
- kunmap(p);
+ kbase_kunmap(p, pgd_page);
}
rt_mutex_unlock(&mmut->mmu_lock);
@@ -2211,6 +2223,9 @@ static void kbase_mmu_progress_migration_on_insert(struct tagged_addr phys,
struct page *phys_page = as_page(phys);
struct kbase_page_metadata *page_md = kbase_page_private(phys_page);
+ if (!IS_ENABLED(CONFIG_PAGE_MIGRATION_SUPPORT))
+ return;
+
spin_lock(&page_md->migrate_lock);
/* If no GPU va region is given: the metadata provided are
@@ -2245,6 +2260,9 @@ static void kbase_mmu_progress_migration_on_teardown(struct kbase_device *kbdev,
{
size_t i;
+ if (!IS_ENABLED(CONFIG_PAGE_MIGRATION_SUPPORT))
+ return;
+
for (i = 0; i < requested_nr; i++) {
struct page *phys_page = as_page(phys[i]);
struct kbase_page_metadata *page_md = kbase_page_private(phys_page);
@@ -2294,10 +2312,10 @@ u64 kbase_mmu_create_ate(struct kbase_device *const kbdev,
group_id, level, entry);
}
-int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
- const u64 start_vpfn, struct tagged_addr *phys, size_t nr,
- unsigned long flags, int const group_id, u64 *dirty_pgds,
- struct kbase_va_region *reg, bool ignore_page_migration)
+static int mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
+ const u64 start_vpfn, struct tagged_addr *phys, size_t nr,
+ unsigned long flags, int const group_id, u64 *dirty_pgds,
+ struct kbase_va_region *reg, bool ignore_page_migration)
{
phys_addr_t pgd;
u64 *pgd_page;
@@ -2378,7 +2396,8 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
}
p = pfn_to_page(PFN_DOWN(pgd));
- pgd_page = kmap(p);
+ pgd_page = kbase_kmap(p);
+
if (!pgd_page) {
dev_err(kbdev->dev, "%s: kmap failure", __func__);
err = -ENOMEM;
@@ -2415,7 +2434,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
/* If page migration is enabled, this is the right time
* to update the status of the page.
*/
- if (kbase_page_migration_enabled && !ignore_page_migration &&
+ if (kbase_is_page_migration_enabled() && !ignore_page_migration &&
!is_huge(phys[i]) && !is_partial(phys[i]))
kbase_mmu_progress_migration_on_insert(phys[i], reg, mmut,
insert_vpfn + i);
@@ -2450,7 +2469,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
kbdev->mmu_mode->entries_invalidate(&pgd_page[vindex], count);
- kunmap(p);
+ kbase_kunmap(p, pgd_page);
goto fail_unlock_free_pgds;
}
}
@@ -2458,7 +2477,7 @@ int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
phys += count;
insert_vpfn += count;
remain -= count;
- kunmap(p);
+ kbase_kunmap(p, pgd_page);
}
rt_mutex_unlock(&mmut->mmu_lock);
@@ -2485,6 +2504,23 @@ fail_unlock:
return err;
}
+int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
+ const u64 start_vpfn, struct tagged_addr *phys, size_t nr,
+ unsigned long flags, int const group_id, u64 *dirty_pgds,
+ struct kbase_va_region *reg)
+{
+ int err;
+
+ /* Early out if there is nothing to do */
+ if (nr == 0)
+ return 0;
+
+ err = mmu_insert_pages_no_flush(kbdev, mmut, start_vpfn, phys, nr, flags, group_id,
+ dirty_pgds, reg, false);
+
+ return err;
+}
+
/*
* Map 'nr' pages pointed to by 'phys' at GPU PFN 'vpfn' for GPU address space
* number 'as_nr'.
@@ -2492,7 +2528,7 @@ fail_unlock:
int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
struct tagged_addr *phys, size_t nr, unsigned long flags, int as_nr,
int const group_id, enum kbase_caller_mmu_sync_info mmu_sync_info,
- struct kbase_va_region *reg, bool ignore_page_migration)
+ struct kbase_va_region *reg)
{
int err;
u64 dirty_pgds = 0;
@@ -2501,8 +2537,8 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *m
if (nr == 0)
return 0;
- err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id,
- &dirty_pgds, reg, ignore_page_migration);
+ err = mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, &dirty_pgds,
+ reg, false);
if (err)
return err;
@@ -2513,11 +2549,12 @@ int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *m
KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages);
-int kbase_mmu_insert_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
- u64 vpfn, struct tagged_addr *phys, size_t nr,
- unsigned long flags, int as_nr, int const group_id,
- enum kbase_caller_mmu_sync_info mmu_sync_info,
- struct kbase_va_region *reg)
+int kbase_mmu_insert_pages_skip_status_update(struct kbase_device *kbdev,
+ struct kbase_mmu_table *mmut, u64 vpfn,
+ struct tagged_addr *phys, size_t nr,
+ unsigned long flags, int as_nr, int const group_id,
+ enum kbase_caller_mmu_sync_info mmu_sync_info,
+ struct kbase_va_region *reg)
{
int err;
u64 dirty_pgds = 0;
@@ -2529,8 +2566,8 @@ int kbase_mmu_insert_imported_pages(struct kbase_device *kbdev, struct kbase_mmu
/* Imported allocations don't have metadata and therefore always ignore the
* page migration logic.
*/
- err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id,
- &dirty_pgds, reg, true);
+ err = mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, &dirty_pgds,
+ reg, true);
if (err)
return err;
@@ -2555,8 +2592,8 @@ int kbase_mmu_insert_aliased_pages(struct kbase_device *kbdev, struct kbase_mmu_
/* Memory aliases are always built on top of existing allocations,
* therefore the state of physical pages shall be updated.
*/
- err = kbase_mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id,
- &dirty_pgds, reg, false);
+ err = mmu_insert_pages_no_flush(kbdev, mmut, vpfn, phys, nr, flags, group_id, &dirty_pgds,
+ reg, false);
if (err)
return err;
@@ -2771,7 +2808,8 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev,
current_level--) {
phys_addr_t current_pgd = pgds[current_level];
struct page *p = phys_to_page(current_pgd);
- u64 *current_page = kmap(p);
+
+ u64 *current_page = kbase_kmap(p);
unsigned int current_valid_entries =
kbdev->mmu_mode->get_num_valid_entries(current_page);
int index = (vpfn >> ((3 - current_level) * 9)) & 0x1FF;
@@ -2783,7 +2821,7 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev,
kbdev->mmu_mode->entries_invalidate(&current_page[index], 1);
if (current_valid_entries == 1 &&
current_level != MIDGARD_MMU_LEVEL(0)) {
- kunmap(p);
+ kbase_kunmap(p, current_page);
/* Ensure the cacheline containing the last valid entry
* of PGD is invalidated from the GPU cache, before the
@@ -2800,7 +2838,7 @@ static void kbase_mmu_update_and_free_parent_pgds(struct kbase_device *kbdev,
kbdev->mmu_mode->set_num_valid_entries(
current_page, current_valid_entries);
- kunmap(p);
+ kbase_kunmap(p, current_page);
kbase_mmu_sync_pgd(kbdev, mmut->kctx, current_pgd + (index * sizeof(u64)),
kbase_dma_addr(p) + (index * sizeof(u64)), sizeof(u64),
@@ -2856,7 +2894,7 @@ static void mmu_flush_invalidate_teardown_pages(struct kbase_device *kbdev,
for (i = 0; !flush_done && i < phys_page_nr; i++) {
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
- if (kbdev->pm.backend.gpu_powered && (!kctx || kctx->as_nr >= 0))
+ if (kbdev->pm.backend.gpu_ready && (!kctx || kctx->as_nr >= 0))
mmu_flush_pa_range(kbdev, as_phys_addr_t(phys[i]), PAGE_SIZE,
KBASE_MMU_OP_FLUSH_MEM);
else
@@ -2897,7 +2935,7 @@ static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase
phys_addr_t next_pgd;
index = (vpfn >> ((3 - level) * 9)) & 0x1FF;
- page = kmap(p);
+ page = kbase_kmap(p);
if (mmu_mode->ate_is_valid(page[index], level))
break; /* keep the mapping */
else if (!mmu_mode->pte_is_valid(page[index], level)) {
@@ -2923,7 +2961,7 @@ static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase
next_pgd = mmu_mode->pte_to_phy_addr(
kbdev->mgm_dev->ops.mgm_pte_to_original_pte(
kbdev->mgm_dev, MGM_DEFAULT_PTE_GROUP, level, page[index]));
- kunmap(p);
+ kbase_kunmap(p, page);
pgds[level] = pgd;
pgd = next_pgd;
p = phys_to_page(pgd);
@@ -2934,7 +2972,7 @@ static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase
case MIDGARD_MMU_LEVEL(1):
dev_warn(kbdev->dev, "%s: No support for ATEs at level %d", __func__,
level);
- kunmap(p);
+ kbase_kunmap(p, page);
goto out;
case MIDGARD_MMU_LEVEL(2):
/* can only teardown if count >= 512 */
@@ -2972,7 +3010,7 @@ static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase
mmu_mode->entries_invalidate(&page[index], pcount);
if (!num_of_valid_entries) {
- kunmap(p);
+ kbase_kunmap(p, page);
/* Ensure the cacheline(s) containing the last valid entries
* of PGD is invalidated from the GPU cache, before the
@@ -2998,17 +3036,48 @@ static int kbase_mmu_teardown_pgd_pages(struct kbase_device *kbdev, struct kbase
kbase_dma_addr(p) + (index * sizeof(u64)), pcount * sizeof(u64),
flush_op);
next:
- kunmap(p);
- vpfn += count;
- nr -= count;
+ kbase_kunmap(p, page);
+ vpfn += count;
+ nr -= count;
}
out:
return 0;
}
-int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
- struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages,
- int as_nr, bool ignore_page_migration)
+/**
+ * mmu_teardown_pages - Remove GPU virtual addresses from the MMU page table
+ *
+ * @kbdev: Pointer to kbase device.
+ * @mmut: Pointer to GPU MMU page table.
+ * @vpfn: Start page frame number of the GPU virtual pages to unmap.
+ * @phys: Array of physical pages currently mapped to the virtual
+ * pages to unmap, or NULL. This is used for GPU cache maintenance
+ * and page migration support.
+ * @nr_phys_pages: Number of physical pages to flush.
+ * @nr_virt_pages: Number of virtual pages whose PTEs should be destroyed.
+ * @as_nr: Address space number, for GPU cache maintenance operations
+ * that happen outside a specific kbase context.
+ * @ignore_page_migration: Whether page migration metadata should be ignored.
+ *
+ * We actually discard the ATE and free the page table pages if no valid entries
+ * exist in the PGD.
+ *
+ * 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.
+ *
+ * The @p phys pointer to physical pages is not necessary for unmapping virtual memory,
+ * but it is used for fine-grained GPU cache maintenance. If @p phys is NULL,
+ * GPU cache maintenance will be done as usual; that is, invalidating the whole GPU caches
+ * instead of specific physical address ranges.
+ *
+ * Return: 0 on success, otherwise an error code.
+ */
+static int mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
+ struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages,
+ int as_nr, bool ignore_page_migration)
{
u64 start_vpfn = vpfn;
enum kbase_mmu_op_type flush_op = KBASE_MMU_OP_NONE;
@@ -3089,7 +3158,7 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table
* updated before releasing the lock to protect against concurrent
* requests to migrate the pages, if they have been isolated.
*/
- if (kbase_page_migration_enabled && phys && !ignore_page_migration)
+ if (kbase_is_page_migration_enabled() && phys && !ignore_page_migration)
kbase_mmu_progress_migration_on_teardown(kbdev, phys, nr_phys_pages);
kbase_mmu_free_pgds_list(kbdev, mmut);
@@ -3098,7 +3167,22 @@ int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table
return err;
}
-KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages);
+
+int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
+ struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages,
+ int as_nr)
+{
+ return mmu_teardown_pages(kbdev, mmut, vpfn, phys, nr_phys_pages, nr_virt_pages, as_nr,
+ false);
+}
+
+int kbase_mmu_teardown_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
+ u64 vpfn, struct tagged_addr *phys, size_t nr_phys_pages,
+ size_t nr_virt_pages, int as_nr)
+{
+ return mmu_teardown_pages(kbdev, mmut, vpfn, phys, nr_phys_pages, nr_virt_pages, as_nr,
+ true);
+}
/**
* kbase_mmu_update_pages_no_flush() - Update phy pages and attributes data in GPU
@@ -3162,7 +3246,7 @@ int kbase_mmu_update_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
goto fail_unlock;
p = pfn_to_page(PFN_DOWN(pgd));
- pgd_page = kmap(p);
+ pgd_page = kbase_kmap(p);
if (!pgd_page) {
dev_warn(kbdev->dev, "kmap failure on update_pages");
err = -ENOMEM;
@@ -3217,7 +3301,7 @@ int kbase_mmu_update_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu
vpfn += count;
nr -= count;
- kunmap(p);
+ kbase_kunmap(p, pgd_page);
}
rt_mutex_unlock(&mmut->mmu_lock);
@@ -3339,6 +3423,9 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
unsigned int num_of_valid_entries;
u8 vmap_count = 0;
+ /* If page migration support is not compiled in, return with fault */
+ if (!IS_ENABLED(CONFIG_PAGE_MIGRATION_SUPPORT))
+ return -EINVAL;
/* Due to the hard binding of mmu_command_instr with kctx_id via kbase_mmu_hw_op_param,
* here we skip the no kctx case, which is only used with MCU's mmut.
*/
@@ -3356,21 +3443,21 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
index = (vpfn >> ((3 - level) * 9)) & 0x1FF;
/* Create all mappings before copying content.
- * This is done as early as possible because is the only operation that may
+ * This is done as early as possible because it is the only operation that may
* fail. It is possible to do this before taking any locks because the
* pages to migrate are not going to change and even the parent PGD is not
* going to be affected by any other concurrent operation, since the page
* has been isolated before migration and therefore it cannot disappear in
* the middle of this function.
*/
- old_page = kmap(as_page(old_phys));
+ old_page = kbase_kmap(as_page(old_phys));
if (!old_page) {
dev_warn(kbdev->dev, "%s: kmap failure for old page.", __func__);
ret = -EINVAL;
goto old_page_map_error;
}
- new_page = kmap(as_page(new_phys));
+ new_page = kbase_kmap(as_page(new_phys));
if (!new_page) {
dev_warn(kbdev->dev, "%s: kmap failure for new page.", __func__);
ret = -EINVAL;
@@ -3457,14 +3544,13 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
goto get_pgd_at_level_error;
}
- pgd_page = kmap(phys_to_page(pgd));
+ pgd_page = kbase_kmap(phys_to_page(pgd));
if (!pgd_page) {
dev_warn(kbdev->dev, "%s: kmap failure for PGD page.", __func__);
ret = -EINVAL;
goto pgd_page_map_error;
}
- rt_mutex_lock(&kbdev->pm.lock);
mutex_lock(&kbdev->mmu_hw_mutex);
/* Lock MMU region and flush GPU cache by using GPU control,
@@ -3475,14 +3561,13 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
/* Defer the migration as L2 is in a transitional phase */
spin_unlock_irqrestore(&kbdev->hwaccess_lock, hwaccess_flags);
mutex_unlock(&kbdev->mmu_hw_mutex);
- rt_mutex_unlock(&kbdev->pm.lock);
dev_dbg(kbdev->dev, "%s: L2 in transtion, abort PGD page migration", __func__);
ret = -EAGAIN;
goto l2_state_defer_out;
}
/* Prevent transitional phases in L2 by starting the transaction */
mmu_page_migration_transaction_begin(kbdev);
- if (kbdev->pm.backend.gpu_powered && mmut->kctx->as_nr >= 0) {
+ if (kbdev->pm.backend.gpu_ready && mmut->kctx->as_nr >= 0) {
int as_nr = mmut->kctx->as_nr;
struct kbase_as *as = &kbdev->as[as_nr];
@@ -3498,7 +3583,6 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
if (ret < 0) {
mutex_unlock(&kbdev->mmu_hw_mutex);
- rt_mutex_unlock(&kbdev->pm.lock);
dev_err(kbdev->dev, "%s: failed to lock MMU region or flush GPU cache", __func__);
goto undo_mappings;
}
@@ -3574,7 +3658,7 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
* won't have any effect on them.
*/
spin_lock_irqsave(&kbdev->hwaccess_lock, hwaccess_flags);
- if (kbdev->pm.backend.gpu_powered && mmut->kctx->as_nr >= 0) {
+ if (kbdev->pm.backend.gpu_ready && mmut->kctx->as_nr >= 0) {
int as_nr = mmut->kctx->as_nr;
struct kbase_as *as = &kbdev->as[as_nr];
@@ -3590,7 +3674,6 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
spin_unlock_irqrestore(&kbdev->hwaccess_lock, hwaccess_flags);
/* Releasing locks before checking the migration transaction error state */
mutex_unlock(&kbdev->mmu_hw_mutex);
- rt_mutex_unlock(&kbdev->pm.lock);
spin_lock_irqsave(&kbdev->hwaccess_lock, hwaccess_flags);
/* Release the transition prevention in L2 by ending the transaction */
@@ -3623,24 +3706,24 @@ int kbase_mmu_migrate_page(struct tagged_addr old_phys, struct tagged_addr new_p
set_page_private(as_page(old_phys), 0);
l2_state_defer_out:
- kunmap(phys_to_page(pgd));
+ kbase_kunmap(phys_to_page(pgd), pgd_page);
pgd_page_map_error:
get_pgd_at_level_error:
page_state_change_out:
rt_mutex_unlock(&mmut->mmu_lock);
- kunmap(as_page(new_phys));
+ kbase_kunmap(as_page(new_phys), new_page);
new_page_map_error:
- kunmap(as_page(old_phys));
+ kbase_kunmap(as_page(old_phys), old_page);
old_page_map_error:
return ret;
undo_mappings:
/* Unlock the MMU table and undo mappings. */
rt_mutex_unlock(&mmut->mmu_lock);
- kunmap(phys_to_page(pgd));
- kunmap(as_page(new_phys));
- kunmap(as_page(old_phys));
+ kbase_kunmap(phys_to_page(pgd), pgd_page);
+ kbase_kunmap(as_page(new_phys), new_page);
+ kbase_kunmap(as_page(old_phys), old_page);
return ret;
}
@@ -3657,7 +3740,7 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl
lockdep_assert_held(&mmut->mmu_lock);
- pgd_page = kmap_atomic(p);
+ pgd_page = kbase_kmap_atomic(p);
/* kmap_atomic should NEVER fail. */
if (WARN_ON_ONCE(pgd_page == NULL))
return;
@@ -3673,11 +3756,11 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl
* there are no pages left mapped on the GPU for a context. Hence the count
* of valid entries is expected to be zero here.
*/
- if (kbase_page_migration_enabled && mmut->kctx)
+ if (kbase_is_page_migration_enabled() && mmut->kctx)
WARN_ON_ONCE(kbdev->mmu_mode->get_num_valid_entries(pgd_page));
/* Invalidate page after copying */
mmu_mode->entries_invalidate(pgd_page, KBASE_MMU_PAGE_ENTRIES);
- kunmap_atomic(pgd_page);
+ kbase_kunmap_atomic(pgd_page);
pgd_page = pgd_page_buffer;
if (level < MIDGARD_MMU_BOTTOMLEVEL) {
@@ -3696,6 +3779,24 @@ static void mmu_teardown_level(struct kbase_device *kbdev, struct kbase_mmu_tabl
kbase_mmu_free_pgd(kbdev, mmut, pgd);
}
+static void kbase_mmu_mark_non_movable(struct page *page)
+{
+ struct kbase_page_metadata *page_md;
+
+ if (!kbase_is_page_migration_enabled())
+ return;
+
+ page_md = kbase_page_private(page);
+
+ spin_lock(&page_md->migrate_lock);
+ page_md->status = PAGE_STATUS_SET(page_md->status, NOT_MOVABLE);
+
+ if (IS_PAGE_MOVABLE(page_md->status))
+ page_md->status = PAGE_MOVABLE_CLEAR(page_md->status);
+
+ spin_unlock(&page_md->migrate_lock);
+}
+
int kbase_mmu_init(struct kbase_device *const kbdev,
struct kbase_mmu_table *const mmut, struct kbase_context *const kctx,
int const group_id)
@@ -3729,11 +3830,10 @@ int kbase_mmu_init(struct kbase_device *const kbdev,
return -ENOMEM;
}
- rt_mutex_lock(&mmut->mmu_lock);
mmut->pgd = kbase_mmu_alloc_pgd(kbdev, mmut);
- rt_mutex_unlock(&mmut->mmu_lock);
}
+ kbase_mmu_mark_non_movable(pfn_to_page(PFN_DOWN(mmut->pgd)));
return 0;
}
@@ -3769,7 +3869,7 @@ void kbase_mmu_flush_pa_range(struct kbase_device *kbdev, struct kbase_context *
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
if (mmu_flush_cache_on_gpu_ctrl(kbdev) && (flush_op != KBASE_MMU_OP_NONE) &&
- kbdev->pm.backend.gpu_powered && (!kctx || kctx->as_nr >= 0))
+ kbdev->pm.backend.gpu_ready && (!kctx || kctx->as_nr >= 0))
mmu_flush_pa_range(kbdev, phys, size, KBASE_MMU_OP_FLUSH_PT);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags);
#endif
@@ -3794,7 +3894,7 @@ static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd,
kbdev = kctx->kbdev;
mmu_mode = kbdev->mmu_mode;
- pgd_page = kmap(pfn_to_page(PFN_DOWN(pgd)));
+ pgd_page = kbase_kmap(pfn_to_page(PFN_DOWN(pgd)));
if (!pgd_page) {
dev_warn(kbdev->dev, "%s: kmap failure", __func__);
return 0;
@@ -3829,7 +3929,7 @@ static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd,
target_pgd, level + 1,
buffer, size_left);
if (!dump_size) {
- kunmap(pfn_to_page(PFN_DOWN(pgd)));
+ kbase_kunmap(pfn_to_page(PFN_DOWN(pgd)), pgd_page);
return 0;
}
size += dump_size;
@@ -3837,7 +3937,7 @@ static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd,
}
}
- kunmap(pfn_to_page(PFN_DOWN(pgd)));
+ kbase_kunmap(pfn_to_page(PFN_DOWN(pgd)), pgd_page);
return size;
}
diff --git a/mali_kbase/mmu/mali_kbase_mmu.h b/mali_kbase/mmu/mali_kbase_mmu.h
index 861a5f4..e13e9b9 100644
--- a/mali_kbase/mmu/mali_kbase_mmu.h
+++ b/mali_kbase/mmu/mali_kbase_mmu.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
*
- * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2019-2023 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
@@ -36,8 +36,8 @@ struct kbase_va_region;
* A pointer to this type is passed down from the outer-most callers in the kbase
* module - where the information resides as to the synchronous / asynchronous
* nature of the call flow, with respect to MMU operations. ie - does the call flow relate to
- * existing GPU work does it come from requests (like ioctl) from user-space, power management,
- * etc.
+ * existing GPU work or does it come from requests (like ioctl) from user-space, power
+ * management, etc.
*
* @CALLER_MMU_UNSET_SYNCHRONICITY: default value must be invalid to avoid accidental choice
* of a 'valid' value
@@ -154,25 +154,43 @@ u64 kbase_mmu_create_ate(struct kbase_device *kbdev,
int kbase_mmu_insert_pages_no_flush(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
u64 vpfn, struct tagged_addr *phys, size_t nr,
unsigned long flags, int group_id, u64 *dirty_pgds,
- struct kbase_va_region *reg, bool ignore_page_migration);
+ struct kbase_va_region *reg);
int kbase_mmu_insert_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
struct tagged_addr *phys, size_t nr, unsigned long flags, int as_nr,
int group_id, enum kbase_caller_mmu_sync_info mmu_sync_info,
- struct kbase_va_region *reg, bool ignore_page_migration);
-int kbase_mmu_insert_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
- u64 vpfn, struct tagged_addr *phys, size_t nr,
- unsigned long flags, int as_nr, int group_id,
- enum kbase_caller_mmu_sync_info mmu_sync_info,
- struct kbase_va_region *reg);
+ struct kbase_va_region *reg);
+
+/**
+ * kbase_mmu_insert_pages_skip_status_update - Map 'nr' pages pointed to by 'phys'
+ * at GPU PFN 'vpfn' for GPU address space number 'as_nr'.
+ *
+ * @kbdev: Instance of GPU platform device, allocated from the probe method.
+ * @mmut: GPU page tables.
+ * @vpfn: Start page frame number of the GPU virtual pages to map.
+ * @phys: Physical address of the page to be mapped.
+ * @nr: The number of pages to map.
+ * @flags: Bitmask of attributes of the GPU memory region being mapped.
+ * @as_nr: The GPU address space number.
+ * @group_id: The physical memory group in which the page was allocated.
+ * @mmu_sync_info: MMU-synchronous caller info.
+ * @reg: The region whose physical allocation is to be mapped.
+ *
+ * Similar to kbase_mmu_insert_pages() but skips updating each pages metadata
+ * for page migration.
+ *
+ * Return: 0 if successful, otherwise a negative error code.
+ */
+int kbase_mmu_insert_pages_skip_status_update(struct kbase_device *kbdev,
+ struct kbase_mmu_table *mmut, u64 vpfn,
+ struct tagged_addr *phys, size_t nr,
+ unsigned long flags, int as_nr, int group_id,
+ enum kbase_caller_mmu_sync_info mmu_sync_info,
+ struct kbase_va_region *reg);
int kbase_mmu_insert_aliased_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
u64 vpfn, struct tagged_addr *phys, size_t nr,
unsigned long flags, int as_nr, int group_id,
enum kbase_caller_mmu_sync_info mmu_sync_info,
struct kbase_va_region *reg);
-int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, struct tagged_addr phys,
- size_t nr, unsigned long flags, int group_id,
- enum kbase_caller_mmu_sync_info mmu_sync_info,
- bool ignore_page_migration);
int kbase_mmu_insert_single_imported_page(struct kbase_context *kctx, u64 vpfn,
struct tagged_addr phys, size_t nr, unsigned long flags,
int group_id,
@@ -182,40 +200,16 @@ int kbase_mmu_insert_single_aliased_page(struct kbase_context *kctx, u64 vpfn,
int group_id,
enum kbase_caller_mmu_sync_info mmu_sync_info);
-/**
- * kbase_mmu_teardown_pages - Remove GPU virtual addresses from the MMU page table
- *
- * @kbdev: Pointer to kbase device.
- * @mmut: Pointer to GPU MMU page table.
- * @vpfn: Start page frame number of the GPU virtual pages to unmap.
- * @phys: Array of physical pages currently mapped to the virtual
- * pages to unmap, or NULL. This is used for GPU cache maintenance
- * and page migration support.
- * @nr_phys_pages: Number of physical pages to flush.
- * @nr_virt_pages: Number of virtual pages whose PTEs should be destroyed.
- * @as_nr: Address space number, for GPU cache maintenance operations
- * that happen outside a specific kbase context.
- * @ignore_page_migration: Whether page migration metadata should be ignored.
- *
- * We actually discard the ATE and free the page table pages if no valid entries
- * exist in PGD.
- *
- * 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.
- *
- * The @p phys pointer to physical pages is not necessary for unmapping virtual memory,
- * but it is used for fine-grained GPU cache maintenance. If @p phys is NULL,
- * GPU cache maintenance will be done as usual, that is invalidating the whole GPU caches
- * instead of specific physical address ranges.
- *
- * Return: 0 on success, otherwise an error code.
- */
int kbase_mmu_teardown_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut, u64 vpfn,
struct tagged_addr *phys, size_t nr_phys_pages, size_t nr_virt_pages,
- int as_nr, bool ignore_page_migration);
+ int as_nr);
+int kbase_mmu_teardown_imported_pages(struct kbase_device *kbdev, struct kbase_mmu_table *mmut,
+ u64 vpfn, struct tagged_addr *phys, size_t nr_phys_pages,
+ size_t nr_virt_pages, int as_nr);
+#define kbase_mmu_teardown_firmware_pages(kbdev, mmut, vpfn, phys, nr_phys_pages, nr_virt_pages, \
+ as_nr) \
+ kbase_mmu_teardown_imported_pages(kbdev, mmut, vpfn, phys, nr_phys_pages, nr_virt_pages, \
+ as_nr)
int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn,
struct tagged_addr *phys, size_t nr,
diff --git a/mali_kbase/mmu/mali_kbase_mmu_hw.h b/mali_kbase/mmu/mali_kbase_mmu_hw.h
index d53f928..49e050e 100644
--- a/mali_kbase/mmu/mali_kbase_mmu_hw.h
+++ b/mali_kbase/mmu/mali_kbase_mmu_hw.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
*
- * (C) COPYRIGHT 2014-2015, 2018-2022 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2014-2023 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
@@ -58,7 +58,7 @@ enum kbase_mmu_fault_type {
* struct kbase_mmu_hw_op_param - parameters for kbase_mmu_hw_do_* functions
* @vpfn: MMU Virtual Page Frame Number to start the operation on.
* @nr: Number of pages to work on.
- * @op: Operation type (written to ASn_COMMAND).
+ * @op: Operation type (written to AS_COMMAND).
* @kctx_id: Kernel context ID for MMU command tracepoint.
* @mmu_sync_info: Indicates whether this call is synchronous wrt MMU ops.
* @flush_skip_levels: Page table levels to skip flushing. (Only
diff --git a/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c b/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
index ecfa23d..ca9f060 100644
--- a/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
+++ b/mali_kbase/mmu/mali_kbase_mmu_hw_direct.c
@@ -170,10 +170,10 @@ static int lock_region(struct kbase_gpu_props const *gpu_props, u64 *lockaddr,
static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr)
{
const ktime_t wait_loop_start = ktime_get_raw();
- const u32 mmu_as_inactive_wait_time_ms = kbdev->mmu_as_inactive_wait_time_ms;
+ const u32 mmu_as_inactive_wait_time_ms = kbdev->mmu_or_gpu_cache_op_wait_time_ms;
s64 diff;
- if (unlikely(kbdev->as[as_nr].is_unresponsive))
+ if (unlikely(kbdev->mmu_unresponsive))
return -EBUSY;
do {
@@ -181,7 +181,7 @@ static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr)
for (i = 0; i < 1000; i++) {
/* Wait for the MMU status to indicate there is no active command */
- if (!(kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS)) &
+ if (!(kbase_reg_read(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_nr, AS_STATUS))) &
AS_STATUS_AS_ACTIVE))
return 0;
}
@@ -192,7 +192,7 @@ static int wait_ready(struct kbase_device *kbdev, unsigned int as_nr)
dev_err(kbdev->dev,
"AS_ACTIVE bit stuck for as %u. Might be caused by unstable GPU clk/pwr or faulty system",
as_nr);
- kbdev->as[as_nr].is_unresponsive = true;
+ kbdev->mmu_unresponsive = true;
if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_HWC_UNRECOVERABLE_ERROR))
kbase_reset_gpu_locked(kbdev);
@@ -205,7 +205,7 @@ static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd)
const int status = wait_ready(kbdev, as_nr);
if (likely(status == 0))
- kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_COMMAND), cmd);
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_nr, AS_COMMAND)), cmd);
else if (status == -EBUSY) {
dev_dbg(kbdev->dev,
"Skipped the wait for AS_ACTIVE bit for as %u, before sending MMU command %u",
@@ -277,9 +277,8 @@ static int apply_hw_issue_GPU2019_3901_wa(struct kbase_device *kbdev, u32 *mmu_c
* the workaround can be safely skipped.
*/
if (kbdev->pm.backend.l2_state != KBASE_L2_OFF) {
- if (*mmu_cmd != AS_COMMAND_FLUSH_MEM) {
- dev_warn(kbdev->dev,
- "Unexpected mmu command received");
+ if (unlikely(*mmu_cmd != AS_COMMAND_FLUSH_MEM)) {
+ dev_warn(kbdev->dev, "Unexpected MMU command(%u) received", *mmu_cmd);
return -EINVAL;
}
@@ -341,19 +340,18 @@ void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as)
transcfg = (transcfg | AS_TRANSCFG_PTW_SH_OS);
}
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSCFG_LO),
- transcfg);
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSCFG_HI),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_TRANSCFG_LO)), transcfg);
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_TRANSCFG_HI)),
(transcfg >> 32) & 0xFFFFFFFFUL);
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_LO),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_TRANSTAB_LO)),
current_setup->transtab & 0xFFFFFFFFUL);
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_HI),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_TRANSTAB_HI)),
(current_setup->transtab >> 32) & 0xFFFFFFFFUL);
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_LO),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_MEMATTR_LO)),
current_setup->memattr & 0xFFFFFFFFUL);
- kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_HI),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_MEMATTR_HI)),
(current_setup->memattr >> 32) & 0xFFFFFFFFUL);
KBASE_TLSTREAM_TL_ATTRIB_AS_CONFIG(kbdev, as,
@@ -401,9 +399,9 @@ static int mmu_hw_set_lock_addr(struct kbase_device *kbdev, int as_nr, u64 *lock
if (!ret) {
/* Set the region that needs to be updated */
- kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_LOCKADDR_LO),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_nr, AS_LOCKADDR_LO)),
*lock_addr & 0xFFFFFFFFUL);
- kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_LOCKADDR_HI),
+ kbase_reg_write(kbdev, MMU_STAGE1_REG(MMU_AS_REG(as_nr, AS_LOCKADDR_HI)),
(*lock_addr >> 32) & 0xFFFFFFFFUL);
}
return ret;
@@ -490,9 +488,11 @@ int kbase_mmu_hw_do_unlock_no_addr(struct kbase_device *kbdev, struct kbase_as *
if (likely(!ret)) {
u64 lock_addr = 0x0;
/* read MMU_AS_CONTROL.LOCKADDR register */
- lock_addr |= (u64)kbase_reg_read(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_HI))
+ lock_addr |= (u64)kbase_reg_read(
+ kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_LOCKADDR_HI)))
<< 32;
- lock_addr |= (u64)kbase_reg_read(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_LO));
+ lock_addr |= (u64)kbase_reg_read(
+ kbdev, MMU_STAGE1_REG(MMU_AS_REG(as->number, AS_LOCKADDR_LO)));
mmu_command_instr(kbdev, op_param->kctx_id, AS_COMMAND_UNLOCK,
lock_addr, op_param->mmu_sync_info);
@@ -572,8 +572,14 @@ static int mmu_hw_do_flush(struct kbase_device *kbdev, struct kbase_as *as,
ret = apply_hw_issue_GPU2019_3901_wa(kbdev, &mmu_cmd, as->number);
}
- if (ret)
- return ret;
+ if (ret) {
+ dev_warn(
+ kbdev->dev,
+ "Failed to apply WA for HW issue when doing MMU flush op on VA range %llx-%llx for AS %u",
+ op_param->vpfn << PAGE_SHIFT,
+ ((op_param->vpfn + op_param->nr) << PAGE_SHIFT) - 1, as->number);
+ /* Continue with the MMU flush operation */
+ }
}
#endif
@@ -664,7 +670,7 @@ void kbase_mmu_hw_clear_fault(struct kbase_device *kbdev, struct kbase_as *as,
type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED)
pf_bf_mask |= MMU_BUS_ERROR(as->number);
#endif
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), pf_bf_mask);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_CLEAR), pf_bf_mask);
unlock:
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
@@ -688,15 +694,15 @@ void kbase_mmu_hw_enable_fault(struct kbase_device *kbdev, struct kbase_as *as,
if (kbdev->irq_reset_flush)
goto unlock;
- irq_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK)) |
- MMU_PAGE_FAULT(as->number);
+ irq_mask =
+ kbase_reg_read(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK)) | MMU_PAGE_FAULT(as->number);
#if !MALI_USE_CSF
if (type == KBASE_MMU_FAULT_TYPE_BUS ||
type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED)
irq_mask |= MMU_BUS_ERROR(as->number);
#endif
- kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), irq_mask);
+ kbase_reg_write(kbdev, MMU_CONTROL_REG(MMU_IRQ_MASK), irq_mask);
unlock:
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);