| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2019-2023 ARM Limited. All rights reserved. |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This program is free software and is provided to you under the terms of the |
|---|
| 7 | 7 | * GNU General Public License version 2 as published by the Free Software |
|---|
| .. | .. |
|---|
| 88 | 88 | * context's address space, when the page fault occurs for |
|---|
| 89 | 89 | * MCU's address space. |
|---|
| 90 | 90 | */ |
|---|
| 91 | | - if (!queue_work(as->pf_wq, &as->work_pagefault)) |
|---|
| 92 | | - kbase_ctx_sched_release_ctx(kctx); |
|---|
| 93 | | - else { |
|---|
| 91 | + if (!queue_work(as->pf_wq, &as->work_pagefault)) { |
|---|
| 94 | 92 | dev_dbg(kbdev->dev, |
|---|
| 95 | | - "Page fault is already pending for as %u\n", |
|---|
| 96 | | - as_nr); |
|---|
| 93 | + "Page fault is already pending for as %u", as_nr); |
|---|
| 94 | + kbase_ctx_sched_release_ctx(kctx); |
|---|
| 95 | + } else { |
|---|
| 97 | 96 | atomic_inc(&kbdev->faults_pending); |
|---|
| 98 | 97 | } |
|---|
| 99 | 98 | } |
|---|
| .. | .. |
|---|
| 122 | 121 | access_type, kbase_gpu_access_type_name(fault->status), |
|---|
| 123 | 122 | source_id); |
|---|
| 124 | 123 | |
|---|
| 124 | + kbase_debug_csf_fault_notify(kbdev, NULL, DF_GPU_PAGE_FAULT); |
|---|
| 125 | + |
|---|
| 125 | 126 | /* Report MMU fault for all address spaces (except MCU_AS_NR) */ |
|---|
| 126 | 127 | for (as_no = 1; as_no < kbdev->nr_hw_address_spaces; as_no++) |
|---|
| 127 | 128 | submit_work_pagefault(kbdev, as_no, fault); |
|---|
| .. | .. |
|---|
| 130 | 131 | if (kbase_prepare_to_reset_gpu(kbdev, |
|---|
| 131 | 132 | RESET_FLAGS_HWC_UNRECOVERABLE_ERROR)) |
|---|
| 132 | 133 | kbase_reset_gpu(kbdev); |
|---|
| 134 | + |
|---|
| 133 | 135 | } |
|---|
| 134 | 136 | KBASE_EXPORT_TEST_API(kbase_mmu_report_mcu_as_fault_and_reset); |
|---|
| 135 | 137 | |
|---|
| .. | .. |
|---|
| 148 | 150 | "true" : "false"; |
|---|
| 149 | 151 | int as_no = as->number; |
|---|
| 150 | 152 | unsigned long flags; |
|---|
| 153 | + const uintptr_t fault_addr = fault->addr; |
|---|
| 151 | 154 | |
|---|
| 152 | 155 | /* terminal fault, print info about the fault */ |
|---|
| 153 | 156 | dev_err(kbdev->dev, |
|---|
| 154 | | - "GPU bus fault in AS%d at VA 0x%016llX\n" |
|---|
| 155 | | - "VA_VALID: %s\n" |
|---|
| 157 | + "GPU bus fault in AS%d at PA %pK\n" |
|---|
| 158 | + "PA_VALID: %s\n" |
|---|
| 156 | 159 | "raw fault status: 0x%X\n" |
|---|
| 157 | 160 | "exception type 0x%X: %s\n" |
|---|
| 158 | 161 | "access type 0x%X: %s\n" |
|---|
| 159 | 162 | "source id 0x%X\n" |
|---|
| 160 | 163 | "pid: %d\n", |
|---|
| 161 | | - as_no, fault->addr, |
|---|
| 164 | + as_no, (void *)fault_addr, |
|---|
| 162 | 165 | addr_valid, |
|---|
| 163 | 166 | status, |
|---|
| 164 | 167 | exception_type, kbase_gpu_exception_name(exception_type), |
|---|
| .. | .. |
|---|
| 187 | 190 | kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), |
|---|
| 188 | 191 | GPU_COMMAND_CLEAR_FAULT); |
|---|
| 189 | 192 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
|---|
| 193 | + |
|---|
| 190 | 194 | } |
|---|
| 191 | 195 | |
|---|
| 192 | 196 | /* |
|---|
| .. | .. |
|---|
| 248 | 252 | mutex_unlock(&kbdev->mmu_hw_mutex); |
|---|
| 249 | 253 | /* AS transaction end */ |
|---|
| 250 | 254 | |
|---|
| 255 | + kbase_debug_csf_fault_notify(kbdev, kctx, DF_GPU_PAGE_FAULT); |
|---|
| 251 | 256 | /* Switching to UNMAPPED mode above would have enabled the firmware to |
|---|
| 252 | 257 | * recover from the fault (if the memory access was made by firmware) |
|---|
| 253 | 258 | * and it can then respond to CSG termination requests to be sent now. |
|---|
| .. | .. |
|---|
| 261 | 266 | KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); |
|---|
| 262 | 267 | kbase_mmu_hw_enable_fault(kbdev, as, |
|---|
| 263 | 268 | KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); |
|---|
| 269 | + |
|---|
| 264 | 270 | } |
|---|
| 265 | 271 | |
|---|
| 266 | 272 | /** |
|---|
| .. | .. |
|---|
| 482 | 488 | kbase_csf_ctx_handle_fault(kctx, fault); |
|---|
| 483 | 489 | kbase_ctx_sched_release_ctx_lock(kctx); |
|---|
| 484 | 490 | |
|---|
| 485 | | - atomic_dec(&kbdev->faults_pending); |
|---|
| 486 | | - |
|---|
| 487 | 491 | /* A work for GPU fault is complete. |
|---|
| 488 | 492 | * Till reaching here, no further GPU fault will be reported. |
|---|
| 489 | 493 | * Now clear the GPU fault to allow next GPU fault interrupt report. |
|---|
| .. | .. |
|---|
| 492 | 496 | kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), |
|---|
| 493 | 497 | GPU_COMMAND_CLEAR_FAULT); |
|---|
| 494 | 498 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
|---|
| 499 | + |
|---|
| 500 | + atomic_dec(&kbdev->faults_pending); |
|---|
| 495 | 501 | } |
|---|
| 496 | 502 | |
|---|
| 497 | 503 | /** |
|---|
| .. | .. |
|---|
| 546 | 552 | } |
|---|
| 547 | 553 | KBASE_EXPORT_TEST_API(kbase_mmu_gpu_fault_interrupt); |
|---|
| 548 | 554 | |
|---|
| 549 | | -int kbase_mmu_as_init(struct kbase_device *kbdev, int i) |
|---|
| 555 | +int kbase_mmu_as_init(struct kbase_device *kbdev, unsigned int i) |
|---|
| 550 | 556 | { |
|---|
| 551 | 557 | kbdev->as[i].number = i; |
|---|
| 552 | 558 | kbdev->as[i].bf_data.addr = 0ULL; |
|---|
| 553 | 559 | kbdev->as[i].pf_data.addr = 0ULL; |
|---|
| 554 | 560 | kbdev->as[i].gf_data.addr = 0ULL; |
|---|
| 561 | + kbdev->as[i].is_unresponsive = false; |
|---|
| 555 | 562 | |
|---|
| 556 | | - kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", 0, 1, i); |
|---|
| 563 | + kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", WQ_UNBOUND, 1, i); |
|---|
| 557 | 564 | if (!kbdev->as[i].pf_wq) |
|---|
| 558 | 565 | return -ENOMEM; |
|---|
| 559 | 566 | |
|---|