diff options
author | Jörg Wagner <jorwag@google.com> | 2023-08-31 19:15:13 +0000 |
---|---|---|
committer | Jörg Wagner <jorwag@google.com> | 2023-09-01 09:13:55 +0000 |
commit | b6fd708b3a4da86a196a61592ea3585f1aca7313 (patch) | |
tree | 1cbe3029a45bf9869c17a5b6954e5ae074b44ac8 /mali_kbase/mmu | |
parent | 46edf1b5965d872c5f8a09c6dc3dcbff58f78a92 (diff) | |
parent | e61eb93296e9f940b32d4ad4b0c3a5557cbeaf17 (diff) | |
download | gpu-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.c | 48 | ||||
-rw-r--r-- | mali_kbase/mmu/backend/mali_kbase_mmu_jm.c | 31 | ||||
-rw-r--r-- | mali_kbase/mmu/mali_kbase_mmu.c | 294 | ||||
-rw-r--r-- | mali_kbase/mmu/mali_kbase_mmu.h | 86 | ||||
-rw-r--r-- | mali_kbase/mmu/mali_kbase_mmu_hw.h | 4 | ||||
-rw-r--r-- | mali_kbase/mmu/mali_kbase_mmu_hw_direct.c | 56 |
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(¤t_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); |