| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2018-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 |
|---|
| .. | .. |
|---|
| 27 | 27 | #include "mali_kbase_reset_gpu.h" |
|---|
| 28 | 28 | #include "mali_kbase_ctx_sched.h" |
|---|
| 29 | 29 | #include "device/mali_kbase_device.h" |
|---|
| 30 | +#include <mali_kbase_hwaccess_time.h> |
|---|
| 30 | 31 | #include "backend/gpu/mali_kbase_pm_internal.h" |
|---|
| 31 | 32 | #include "mali_kbase_csf_scheduler.h" |
|---|
| 32 | 33 | #include "mmu/mali_kbase_mmu.h" |
|---|
| 33 | 34 | #include "backend/gpu/mali_kbase_clk_rate_trace_mgr.h" |
|---|
| 35 | +#include <backend/gpu/mali_kbase_model_linux.h> |
|---|
| 36 | +#include <csf/mali_kbase_csf_registers.h> |
|---|
| 34 | 37 | |
|---|
| 35 | 38 | #include <linux/list.h> |
|---|
| 36 | 39 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 100 | 103 | |
|---|
| 101 | 104 | #define CSF_GLB_REQ_CFG_MASK \ |
|---|
| 102 | 105 | (GLB_REQ_CFG_ALLOC_EN_MASK | GLB_REQ_CFG_PROGRESS_TIMER_MASK | \ |
|---|
| 103 | | - GLB_REQ_CFG_PWROFF_TIMER_MASK) |
|---|
| 106 | + GLB_REQ_CFG_PWROFF_TIMER_MASK | GLB_REQ_IDLE_ENABLE_MASK) |
|---|
| 104 | 107 | |
|---|
| 105 | 108 | static inline u32 input_page_read(const u32 *const input, const u32 offset) |
|---|
| 106 | 109 | { |
|---|
| .. | .. |
|---|
| 115 | 118 | WARN_ON(offset % sizeof(u32)); |
|---|
| 116 | 119 | |
|---|
| 117 | 120 | input[offset / sizeof(u32)] = value; |
|---|
| 118 | | -} |
|---|
| 119 | | - |
|---|
| 120 | | -static inline void input_page_partial_write(u32 *const input, const u32 offset, |
|---|
| 121 | | - u32 value, u32 mask) |
|---|
| 122 | | -{ |
|---|
| 123 | | - WARN_ON(offset % sizeof(u32)); |
|---|
| 124 | | - |
|---|
| 125 | | - input[offset / sizeof(u32)] = |
|---|
| 126 | | - (input_page_read(input, offset) & ~mask) | (value & mask); |
|---|
| 127 | 121 | } |
|---|
| 128 | 122 | |
|---|
| 129 | 123 | static inline u32 output_page_read(const u32 *const output, const u32 offset) |
|---|
| .. | .. |
|---|
| 144 | 138 | /** |
|---|
| 145 | 139 | * invent_memory_setup_entry() - Invent an "interface memory setup" section |
|---|
| 146 | 140 | * |
|---|
| 141 | + * @kbdev: Kbase device structure |
|---|
| 142 | + * |
|---|
| 147 | 143 | * Invent an "interface memory setup" section similar to one from a firmware |
|---|
| 148 | 144 | * image. If successful the interface will be added to the |
|---|
| 149 | 145 | * kbase_device:csf.firmware_interfaces list. |
|---|
| 150 | 146 | * |
|---|
| 151 | 147 | * Return: 0 if successful, negative error code on failure |
|---|
| 152 | | - * |
|---|
| 153 | | - * @kbdev: Kbase device structure |
|---|
| 154 | 148 | */ |
|---|
| 155 | 149 | static int invent_memory_setup_entry(struct kbase_device *kbdev) |
|---|
| 156 | 150 | { |
|---|
| .. | .. |
|---|
| 201 | 195 | ginfo->stream_stride = 0; |
|---|
| 202 | 196 | |
|---|
| 203 | 197 | ginfo->streams = kcalloc(ginfo->stream_num, sizeof(*ginfo->streams), GFP_KERNEL); |
|---|
| 204 | | - if (ginfo->streams == NULL) { |
|---|
| 198 | + if (ginfo->streams == NULL) |
|---|
| 205 | 199 | return -ENOMEM; |
|---|
| 206 | | - } |
|---|
| 207 | 200 | |
|---|
| 208 | 201 | for (sid = 0; sid < ginfo->stream_num; ++sid) { |
|---|
| 209 | 202 | struct kbase_csf_cmd_stream_info *stream = &ginfo->streams[sid]; |
|---|
| .. | .. |
|---|
| 236 | 229 | iface->version = 1; |
|---|
| 237 | 230 | iface->kbdev = kbdev; |
|---|
| 238 | 231 | iface->features = 0; |
|---|
| 239 | | - iface->prfcnt_size = 64; |
|---|
| 232 | + iface->prfcnt_size = |
|---|
| 233 | + GLB_PRFCNT_SIZE_HARDWARE_SIZE_SET(0, KBASE_DUMMY_MODEL_MAX_SAMPLE_SIZE); |
|---|
| 240 | 234 | |
|---|
| 241 | 235 | if (iface->version >= kbase_csf_interface_version(1, 1, 0)) { |
|---|
| 242 | 236 | /* update rate=1, max event size = 1<<8 = 256 */ |
|---|
| .. | .. |
|---|
| 249 | 243 | iface->group_stride = 0; |
|---|
| 250 | 244 | |
|---|
| 251 | 245 | iface->groups = kcalloc(iface->group_num, sizeof(*iface->groups), GFP_KERNEL); |
|---|
| 252 | | - if (iface->groups == NULL) { |
|---|
| 246 | + if (iface->groups == NULL) |
|---|
| 253 | 247 | return -ENOMEM; |
|---|
| 254 | | - } |
|---|
| 255 | 248 | |
|---|
| 256 | 249 | for (gid = 0; gid < iface->group_num; ++gid) { |
|---|
| 257 | 250 | int err; |
|---|
| .. | .. |
|---|
| 275 | 268 | |
|---|
| 276 | 269 | |
|---|
| 277 | 270 | void kbase_csf_update_firmware_memory(struct kbase_device *kbdev, |
|---|
| 271 | + u32 gpu_addr, u32 value) |
|---|
| 272 | +{ |
|---|
| 273 | + /* NO_MALI: Nothing to do here */ |
|---|
| 274 | +} |
|---|
| 275 | + |
|---|
| 276 | +void kbase_csf_read_firmware_memory_exe(struct kbase_device *kbdev, |
|---|
| 277 | + u32 gpu_addr, u32 *value) |
|---|
| 278 | +{ |
|---|
| 279 | + /* NO_MALI: Nothing to do here */ |
|---|
| 280 | +} |
|---|
| 281 | + |
|---|
| 282 | +void kbase_csf_update_firmware_memory_exe(struct kbase_device *kbdev, |
|---|
| 278 | 283 | u32 gpu_addr, u32 value) |
|---|
| 279 | 284 | { |
|---|
| 280 | 285 | /* NO_MALI: Nothing to do here */ |
|---|
| .. | .. |
|---|
| 379 | 384 | dev_dbg(kbdev->dev, "csg output r: reg %08x val %08x\n", offset, val); |
|---|
| 380 | 385 | return val; |
|---|
| 381 | 386 | } |
|---|
| 382 | | - |
|---|
| 383 | | -static void |
|---|
| 384 | | -csf_firmware_prfcnt_process(const struct kbase_csf_global_iface *const iface, |
|---|
| 385 | | - const u32 glb_req) |
|---|
| 386 | | -{ |
|---|
| 387 | | - struct kbase_device *kbdev = iface->kbdev; |
|---|
| 388 | | - u32 glb_ack = output_page_read(iface->output, GLB_ACK); |
|---|
| 389 | | - /* If the value of GLB_REQ.PRFCNT_SAMPLE is different from the value of |
|---|
| 390 | | - * GLB_ACK.PRFCNT_SAMPLE, the CSF will sample the performance counters. |
|---|
| 391 | | - */ |
|---|
| 392 | | - if ((glb_req ^ glb_ack) & GLB_REQ_PRFCNT_SAMPLE_MASK) { |
|---|
| 393 | | - /* NO_MALI only uses the first buffer in the ring buffer. */ |
|---|
| 394 | | - input_page_write(iface->input, GLB_PRFCNT_EXTRACT, 0); |
|---|
| 395 | | - output_page_write(iface->output, GLB_PRFCNT_INSERT, 1); |
|---|
| 396 | | - kbase_reg_write(kbdev, GPU_COMMAND, GPU_COMMAND_PRFCNT_SAMPLE); |
|---|
| 397 | | - } |
|---|
| 398 | | - |
|---|
| 399 | | - /* Propagate enable masks to model if request to enable. */ |
|---|
| 400 | | - if (glb_req & GLB_REQ_PRFCNT_ENABLE_MASK) { |
|---|
| 401 | | - u32 tiler_en, l2_en, sc_en; |
|---|
| 402 | | - |
|---|
| 403 | | - tiler_en = input_page_read(iface->input, GLB_PRFCNT_TILER_EN); |
|---|
| 404 | | - l2_en = input_page_read(iface->input, GLB_PRFCNT_MMU_L2_EN); |
|---|
| 405 | | - sc_en = input_page_read(iface->input, GLB_PRFCNT_SHADER_EN); |
|---|
| 406 | | - |
|---|
| 407 | | - /* NO_MALI platform enabled all CSHW counters by default. */ |
|---|
| 408 | | - kbase_reg_write(kbdev, PRFCNT_TILER_EN, tiler_en); |
|---|
| 409 | | - kbase_reg_write(kbdev, PRFCNT_MMU_L2_EN, l2_en); |
|---|
| 410 | | - kbase_reg_write(kbdev, PRFCNT_SHADER_EN, sc_en); |
|---|
| 411 | | - } |
|---|
| 412 | | -} |
|---|
| 387 | +KBASE_EXPORT_TEST_API(kbase_csf_firmware_csg_output); |
|---|
| 413 | 388 | |
|---|
| 414 | 389 | void kbase_csf_firmware_global_input( |
|---|
| 415 | 390 | const struct kbase_csf_global_iface *const iface, const u32 offset, |
|---|
| .. | .. |
|---|
| 421 | 396 | input_page_write(iface->input, offset, value); |
|---|
| 422 | 397 | |
|---|
| 423 | 398 | if (offset == GLB_REQ) { |
|---|
| 424 | | - csf_firmware_prfcnt_process(iface, value); |
|---|
| 425 | | - /* NO_MALI: Immediately acknowledge requests */ |
|---|
| 426 | | - output_page_write(iface->output, GLB_ACK, value); |
|---|
| 399 | + /* NO_MALI: Immediately acknowledge requests - except for PRFCNT_ENABLE |
|---|
| 400 | + * and PRFCNT_SAMPLE. These will be processed along with the |
|---|
| 401 | + * corresponding performance counter registers when the global doorbell |
|---|
| 402 | + * is rung in order to emulate the performance counter sampling behavior |
|---|
| 403 | + * of the real firmware. |
|---|
| 404 | + */ |
|---|
| 405 | + const u32 ack = output_page_read(iface->output, GLB_ACK); |
|---|
| 406 | + const u32 req_mask = ~(GLB_REQ_PRFCNT_ENABLE_MASK | GLB_REQ_PRFCNT_SAMPLE_MASK); |
|---|
| 407 | + const u32 toggled = (value ^ ack) & req_mask; |
|---|
| 408 | + |
|---|
| 409 | + output_page_write(iface->output, GLB_ACK, ack ^ toggled); |
|---|
| 427 | 410 | } |
|---|
| 428 | 411 | } |
|---|
| 412 | +KBASE_EXPORT_TEST_API(kbase_csf_firmware_global_input); |
|---|
| 429 | 413 | |
|---|
| 430 | 414 | void kbase_csf_firmware_global_input_mask( |
|---|
| 431 | 415 | const struct kbase_csf_global_iface *const iface, const u32 offset, |
|---|
| .. | .. |
|---|
| 439 | 423 | /* NO_MALI: Go through kbase_csf_firmware_global_input to capture writes */ |
|---|
| 440 | 424 | kbase_csf_firmware_global_input(iface, offset, (input_page_read(iface->input, offset) & ~mask) | (value & mask)); |
|---|
| 441 | 425 | } |
|---|
| 426 | +KBASE_EXPORT_TEST_API(kbase_csf_firmware_global_input_mask); |
|---|
| 442 | 427 | |
|---|
| 443 | 428 | u32 kbase_csf_firmware_global_input_read( |
|---|
| 444 | 429 | const struct kbase_csf_global_iface *const iface, const u32 offset) |
|---|
| .. | .. |
|---|
| 459 | 444 | dev_dbg(kbdev->dev, "glob output r: reg %08x val %08x\n", offset, val); |
|---|
| 460 | 445 | return val; |
|---|
| 461 | 446 | } |
|---|
| 447 | +KBASE_EXPORT_TEST_API(kbase_csf_firmware_global_output); |
|---|
| 448 | + |
|---|
| 449 | +/** |
|---|
| 450 | + * csf_doorbell_prfcnt() - Process CSF performance counter doorbell request |
|---|
| 451 | + * |
|---|
| 452 | + * @kbdev: An instance of the GPU platform device |
|---|
| 453 | + */ |
|---|
| 454 | +static void csf_doorbell_prfcnt(struct kbase_device *kbdev) |
|---|
| 455 | +{ |
|---|
| 456 | + struct kbase_csf_global_iface *iface; |
|---|
| 457 | + u32 req; |
|---|
| 458 | + u32 ack; |
|---|
| 459 | + u32 extract_index; |
|---|
| 460 | + |
|---|
| 461 | + if (WARN_ON(!kbdev)) |
|---|
| 462 | + return; |
|---|
| 463 | + |
|---|
| 464 | + iface = &kbdev->csf.global_iface; |
|---|
| 465 | + |
|---|
| 466 | + req = input_page_read(iface->input, GLB_REQ); |
|---|
| 467 | + ack = output_page_read(iface->output, GLB_ACK); |
|---|
| 468 | + extract_index = input_page_read(iface->input, GLB_PRFCNT_EXTRACT); |
|---|
| 469 | + |
|---|
| 470 | + /* Process enable bit toggle */ |
|---|
| 471 | + if ((req ^ ack) & GLB_REQ_PRFCNT_ENABLE_MASK) { |
|---|
| 472 | + if (req & GLB_REQ_PRFCNT_ENABLE_MASK) { |
|---|
| 473 | + /* Reset insert index to zero on enable bit set */ |
|---|
| 474 | + output_page_write(iface->output, GLB_PRFCNT_INSERT, 0); |
|---|
| 475 | + WARN_ON(extract_index != 0); |
|---|
| 476 | + } |
|---|
| 477 | + ack ^= GLB_REQ_PRFCNT_ENABLE_MASK; |
|---|
| 478 | + } |
|---|
| 479 | + |
|---|
| 480 | + /* Process sample request */ |
|---|
| 481 | + if ((req ^ ack) & GLB_REQ_PRFCNT_SAMPLE_MASK) { |
|---|
| 482 | + const u32 ring_size = GLB_PRFCNT_CONFIG_SIZE_GET( |
|---|
| 483 | + input_page_read(iface->input, GLB_PRFCNT_CONFIG)); |
|---|
| 484 | + u32 insert_index = output_page_read(iface->output, GLB_PRFCNT_INSERT); |
|---|
| 485 | + |
|---|
| 486 | + const bool prev_overflow = (req ^ ack) & GLB_ACK_IRQ_MASK_PRFCNT_OVERFLOW_MASK; |
|---|
| 487 | + const bool prev_threshold = (req ^ ack) & GLB_ACK_IRQ_MASK_PRFCNT_THRESHOLD_MASK; |
|---|
| 488 | + |
|---|
| 489 | + /* If ringbuffer is full toggle PRFCNT_OVERFLOW and skip sample */ |
|---|
| 490 | + if (insert_index - extract_index >= ring_size) { |
|---|
| 491 | + WARN_ON(insert_index - extract_index > ring_size); |
|---|
| 492 | + if (!prev_overflow) |
|---|
| 493 | + ack ^= GLB_ACK_IRQ_MASK_PRFCNT_OVERFLOW_MASK; |
|---|
| 494 | + } else { |
|---|
| 495 | + struct gpu_model_prfcnt_en enable_maps = { |
|---|
| 496 | + .fe = input_page_read(iface->input, GLB_PRFCNT_CSF_EN), |
|---|
| 497 | + .tiler = input_page_read(iface->input, GLB_PRFCNT_TILER_EN), |
|---|
| 498 | + .l2 = input_page_read(iface->input, GLB_PRFCNT_MMU_L2_EN), |
|---|
| 499 | + .shader = input_page_read(iface->input, GLB_PRFCNT_SHADER_EN), |
|---|
| 500 | + }; |
|---|
| 501 | + |
|---|
| 502 | + const u64 prfcnt_base = |
|---|
| 503 | + input_page_read(iface->input, GLB_PRFCNT_BASE_LO) + |
|---|
| 504 | + ((u64)input_page_read(iface->input, GLB_PRFCNT_BASE_HI) << 32); |
|---|
| 505 | + |
|---|
| 506 | + u32 *sample_base = (u32 *)(uintptr_t)prfcnt_base + |
|---|
| 507 | + (KBASE_DUMMY_MODEL_MAX_VALUES_PER_SAMPLE * |
|---|
| 508 | + (insert_index % ring_size)); |
|---|
| 509 | + |
|---|
| 510 | + /* trigger sample dump in the dummy model */ |
|---|
| 511 | + gpu_model_prfcnt_dump_request(sample_base, enable_maps); |
|---|
| 512 | + |
|---|
| 513 | + /* increment insert index and toggle PRFCNT_SAMPLE bit in ACK */ |
|---|
| 514 | + output_page_write(iface->output, GLB_PRFCNT_INSERT, ++insert_index); |
|---|
| 515 | + ack ^= GLB_ACK_IRQ_MASK_PRFCNT_SAMPLE_MASK; |
|---|
| 516 | + } |
|---|
| 517 | + |
|---|
| 518 | + /* When the ringbuffer reaches 50% capacity toggle PRFCNT_THRESHOLD */ |
|---|
| 519 | + if (!prev_threshold && (insert_index - extract_index >= (ring_size / 2))) |
|---|
| 520 | + ack ^= GLB_ACK_IRQ_MASK_PRFCNT_THRESHOLD_MASK; |
|---|
| 521 | + } |
|---|
| 522 | + |
|---|
| 523 | + /* Update GLB_ACK */ |
|---|
| 524 | + output_page_write(iface->output, GLB_ACK, ack); |
|---|
| 525 | +} |
|---|
| 526 | + |
|---|
| 527 | +void kbase_csf_ring_doorbell(struct kbase_device *kbdev, int doorbell_nr) |
|---|
| 528 | +{ |
|---|
| 529 | + WARN_ON(doorbell_nr < 0); |
|---|
| 530 | + WARN_ON(doorbell_nr >= CSF_NUM_DOORBELL); |
|---|
| 531 | + |
|---|
| 532 | + if (WARN_ON(!kbdev)) |
|---|
| 533 | + return; |
|---|
| 534 | + |
|---|
| 535 | + if (doorbell_nr == CSF_KERNEL_DOORBELL_NR) { |
|---|
| 536 | + csf_doorbell_prfcnt(kbdev); |
|---|
| 537 | + gpu_model_glb_request_job_irq(kbdev->model); |
|---|
| 538 | + } |
|---|
| 539 | +} |
|---|
| 540 | +EXPORT_SYMBOL(kbase_csf_ring_doorbell); |
|---|
| 462 | 541 | |
|---|
| 463 | 542 | /** |
|---|
| 464 | 543 | * handle_internal_firmware_fatal - Handler for CS internal firmware fault. |
|---|
| .. | .. |
|---|
| 560 | 639 | dev_warn(kbdev->dev, "Timed out waiting for global request %x to complete", |
|---|
| 561 | 640 | req_mask); |
|---|
| 562 | 641 | err = -ETIMEDOUT; |
|---|
| 642 | + |
|---|
| 643 | + |
|---|
| 563 | 644 | } |
|---|
| 564 | 645 | |
|---|
| 565 | 646 | return err; |
|---|
| .. | .. |
|---|
| 621 | 702 | set_global_request(global_iface, GLB_REQ_CFG_PROGRESS_TIMER_MASK); |
|---|
| 622 | 703 | } |
|---|
| 623 | 704 | |
|---|
| 705 | +static void enable_gpu_idle_timer(struct kbase_device *const kbdev) |
|---|
| 706 | +{ |
|---|
| 707 | + struct kbase_csf_global_iface *global_iface = &kbdev->csf.global_iface; |
|---|
| 708 | + |
|---|
| 709 | + kbase_csf_scheduler_spin_lock_assert_held(kbdev); |
|---|
| 710 | + |
|---|
| 711 | + kbase_csf_firmware_global_input(global_iface, GLB_IDLE_TIMER, |
|---|
| 712 | + kbdev->csf.gpu_idle_dur_count); |
|---|
| 713 | + kbase_csf_firmware_global_input_mask(global_iface, GLB_REQ, GLB_REQ_REQ_IDLE_ENABLE, |
|---|
| 714 | + GLB_REQ_IDLE_ENABLE_MASK); |
|---|
| 715 | + dev_dbg(kbdev->dev, "Enabling GPU idle timer with count-value: 0x%.8x", |
|---|
| 716 | + kbdev->csf.gpu_idle_dur_count); |
|---|
| 717 | +} |
|---|
| 718 | + |
|---|
| 719 | +static bool global_debug_request_complete(struct kbase_device *const kbdev, u32 const req_mask) |
|---|
| 720 | +{ |
|---|
| 721 | + struct kbase_csf_global_iface *global_iface = &kbdev->csf.global_iface; |
|---|
| 722 | + bool complete = false; |
|---|
| 723 | + unsigned long flags; |
|---|
| 724 | + |
|---|
| 725 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 726 | + |
|---|
| 727 | + if ((kbase_csf_firmware_global_output(global_iface, GLB_DEBUG_ACK) & req_mask) == |
|---|
| 728 | + (kbase_csf_firmware_global_input_read(global_iface, GLB_DEBUG_REQ) & req_mask)) |
|---|
| 729 | + complete = true; |
|---|
| 730 | + |
|---|
| 731 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 732 | + |
|---|
| 733 | + return complete; |
|---|
| 734 | +} |
|---|
| 735 | + |
|---|
| 736 | +static void set_global_debug_request(const struct kbase_csf_global_iface *const global_iface, |
|---|
| 737 | + u32 const req_mask) |
|---|
| 738 | +{ |
|---|
| 739 | + u32 glb_debug_req; |
|---|
| 740 | + |
|---|
| 741 | + kbase_csf_scheduler_spin_lock_assert_held(global_iface->kbdev); |
|---|
| 742 | + |
|---|
| 743 | + glb_debug_req = kbase_csf_firmware_global_output(global_iface, GLB_DEBUG_ACK); |
|---|
| 744 | + glb_debug_req ^= req_mask; |
|---|
| 745 | + |
|---|
| 746 | + kbase_csf_firmware_global_input_mask(global_iface, GLB_DEBUG_REQ, glb_debug_req, req_mask); |
|---|
| 747 | +} |
|---|
| 748 | + |
|---|
| 749 | +static void request_fw_core_dump( |
|---|
| 750 | + const struct kbase_csf_global_iface *const global_iface) |
|---|
| 751 | +{ |
|---|
| 752 | + uint32_t run_mode = GLB_DEBUG_REQ_RUN_MODE_SET(0, GLB_DEBUG_RUN_MODE_TYPE_CORE_DUMP); |
|---|
| 753 | + |
|---|
| 754 | + set_global_debug_request(global_iface, GLB_DEBUG_REQ_DEBUG_RUN_MASK | run_mode); |
|---|
| 755 | + |
|---|
| 756 | + set_global_request(global_iface, GLB_REQ_DEBUG_CSF_REQ_MASK); |
|---|
| 757 | +} |
|---|
| 758 | + |
|---|
| 759 | +int kbase_csf_firmware_req_core_dump(struct kbase_device *const kbdev) |
|---|
| 760 | +{ |
|---|
| 761 | + const struct kbase_csf_global_iface *const global_iface = |
|---|
| 762 | + &kbdev->csf.global_iface; |
|---|
| 763 | + unsigned long flags; |
|---|
| 764 | + int ret; |
|---|
| 765 | + |
|---|
| 766 | + /* Serialize CORE_DUMP requests. */ |
|---|
| 767 | + mutex_lock(&kbdev->csf.reg_lock); |
|---|
| 768 | + |
|---|
| 769 | + /* Update GLB_REQ with CORE_DUMP request and make firmware act on it. */ |
|---|
| 770 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 771 | + request_fw_core_dump(global_iface); |
|---|
| 772 | + kbase_csf_ring_doorbell(kbdev, CSF_KERNEL_DOORBELL_NR); |
|---|
| 773 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 774 | + |
|---|
| 775 | + /* Wait for firmware to acknowledge completion of the CORE_DUMP request. */ |
|---|
| 776 | + ret = wait_for_global_request(kbdev, GLB_REQ_DEBUG_CSF_REQ_MASK); |
|---|
| 777 | + if (!ret) |
|---|
| 778 | + WARN_ON(!global_debug_request_complete(kbdev, GLB_DEBUG_REQ_DEBUG_RUN_MASK)); |
|---|
| 779 | + |
|---|
| 780 | + mutex_unlock(&kbdev->csf.reg_lock); |
|---|
| 781 | + |
|---|
| 782 | + return ret; |
|---|
| 783 | +} |
|---|
| 784 | + |
|---|
| 624 | 785 | static void global_init(struct kbase_device *const kbdev, u64 core_mask) |
|---|
| 625 | 786 | { |
|---|
| 626 | | - u32 const ack_irq_mask = GLB_ACK_IRQ_MASK_CFG_ALLOC_EN_MASK | |
|---|
| 627 | | - GLB_ACK_IRQ_MASK_PING_MASK | |
|---|
| 628 | | - GLB_ACK_IRQ_MASK_CFG_PROGRESS_TIMER_MASK | |
|---|
| 629 | | - GLB_ACK_IRQ_MASK_PROTM_ENTER_MASK | |
|---|
| 630 | | - GLB_ACK_IRQ_MASK_FIRMWARE_CONFIG_UPDATE_MASK | |
|---|
| 631 | | - GLB_ACK_IRQ_MASK_PROTM_EXIT_MASK | |
|---|
| 632 | | - GLB_ACK_IRQ_MASK_CFG_PWROFF_TIMER_MASK | |
|---|
| 633 | | - GLB_ACK_IRQ_MASK_IDLE_EVENT_MASK; |
|---|
| 787 | + u32 const ack_irq_mask = |
|---|
| 788 | + GLB_ACK_IRQ_MASK_CFG_ALLOC_EN_MASK | GLB_ACK_IRQ_MASK_PING_MASK | |
|---|
| 789 | + GLB_ACK_IRQ_MASK_CFG_PROGRESS_TIMER_MASK | GLB_ACK_IRQ_MASK_PROTM_ENTER_MASK | |
|---|
| 790 | + GLB_ACK_IRQ_MASK_PROTM_EXIT_MASK | GLB_ACK_IRQ_MASK_FIRMWARE_CONFIG_UPDATE_MASK | |
|---|
| 791 | + GLB_ACK_IRQ_MASK_CFG_PWROFF_TIMER_MASK | GLB_ACK_IRQ_MASK_IDLE_EVENT_MASK | |
|---|
| 792 | + GLB_ACK_IRQ_MASK_IDLE_ENABLE_MASK | GLB_REQ_DEBUG_CSF_REQ_MASK; |
|---|
| 634 | 793 | |
|---|
| 635 | 794 | const struct kbase_csf_global_iface *const global_iface = |
|---|
| 636 | 795 | &kbdev->csf.global_iface; |
|---|
| .. | .. |
|---|
| 643 | 802 | enable_shader_poweroff_timer(kbdev, global_iface); |
|---|
| 644 | 803 | |
|---|
| 645 | 804 | set_timeout_global(global_iface, kbase_csf_timeout_get(kbdev)); |
|---|
| 805 | + |
|---|
| 806 | + /* The GPU idle timer is always enabled for simplicity. Checks will be |
|---|
| 807 | + * done before scheduling the GPU idle worker to see if it is |
|---|
| 808 | + * appropriate for the current power policy. |
|---|
| 809 | + */ |
|---|
| 810 | + enable_gpu_idle_timer(kbdev); |
|---|
| 646 | 811 | |
|---|
| 647 | 812 | /* Unmask the interrupts */ |
|---|
| 648 | 813 | kbase_csf_firmware_global_input(global_iface, |
|---|
| .. | .. |
|---|
| 786 | 951 | dev_warn(kbdev->dev, "No GPU clock, unexpected intregration issue!"); |
|---|
| 787 | 952 | spin_unlock(&kbdev->pm.clk_rtm.lock); |
|---|
| 788 | 953 | |
|---|
| 789 | | - dev_info(kbdev->dev, "Can't get the timestamp frequency, " |
|---|
| 790 | | - "use cycle counter format with firmware idle hysteresis!"); |
|---|
| 954 | + dev_info( |
|---|
| 955 | + kbdev->dev, |
|---|
| 956 | + "Can't get the timestamp frequency, use cycle counter format with firmware idle hysteresis!"); |
|---|
| 791 | 957 | } |
|---|
| 792 | 958 | |
|---|
| 793 | 959 | /* Formula for dur_val = ((dur_ms/1000) * freq_HZ) >> 10) */ |
|---|
| .. | .. |
|---|
| 811 | 977 | |
|---|
| 812 | 978 | u32 kbase_csf_firmware_get_gpu_idle_hysteresis_time(struct kbase_device *kbdev) |
|---|
| 813 | 979 | { |
|---|
| 814 | | - return kbdev->csf.gpu_idle_hysteresis_ms; |
|---|
| 980 | + unsigned long flags; |
|---|
| 981 | + u32 dur; |
|---|
| 982 | + |
|---|
| 983 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 984 | + dur = kbdev->csf.gpu_idle_hysteresis_us; |
|---|
| 985 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 986 | + |
|---|
| 987 | + return dur; |
|---|
| 815 | 988 | } |
|---|
| 816 | 989 | |
|---|
| 817 | 990 | u32 kbase_csf_firmware_set_gpu_idle_hysteresis_time(struct kbase_device *kbdev, u32 dur) |
|---|
| .. | .. |
|---|
| 819 | 992 | unsigned long flags; |
|---|
| 820 | 993 | const u32 hysteresis_val = convert_dur_to_idle_count(kbdev, dur); |
|---|
| 821 | 994 | |
|---|
| 822 | | - kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 823 | | - kbdev->csf.gpu_idle_hysteresis_ms = dur; |
|---|
| 824 | | - kbdev->csf.gpu_idle_dur_count = hysteresis_val; |
|---|
| 825 | | - kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 995 | + /* The 'fw_load_lock' is taken to synchronize against the deferred |
|---|
| 996 | + * loading of FW, where the idle timer will be enabled. |
|---|
| 997 | + */ |
|---|
| 998 | + mutex_lock(&kbdev->fw_load_lock); |
|---|
| 999 | + if (unlikely(!kbdev->csf.firmware_inited)) { |
|---|
| 1000 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1001 | + kbdev->csf.gpu_idle_hysteresis_us = dur; |
|---|
| 1002 | + kbdev->csf.gpu_idle_dur_count = hysteresis_val; |
|---|
| 1003 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1004 | + mutex_unlock(&kbdev->fw_load_lock); |
|---|
| 1005 | + goto end; |
|---|
| 1006 | + } |
|---|
| 1007 | + mutex_unlock(&kbdev->fw_load_lock); |
|---|
| 826 | 1008 | |
|---|
| 1009 | + kbase_csf_scheduler_pm_active(kbdev); |
|---|
| 1010 | + if (kbase_csf_scheduler_wait_mcu_active(kbdev)) { |
|---|
| 1011 | + dev_err(kbdev->dev, |
|---|
| 1012 | + "Unable to activate the MCU, the idle hysteresis value shall remain unchanged"); |
|---|
| 1013 | + kbase_csf_scheduler_pm_idle(kbdev); |
|---|
| 1014 | + return kbdev->csf.gpu_idle_dur_count; |
|---|
| 1015 | + } |
|---|
| 1016 | + |
|---|
| 1017 | + /* The 'reg_lock' is also taken and is held till the update is not |
|---|
| 1018 | + * complete, to ensure the update of idle timer value by multiple Users |
|---|
| 1019 | + * gets serialized. |
|---|
| 1020 | + */ |
|---|
| 1021 | + mutex_lock(&kbdev->csf.reg_lock); |
|---|
| 1022 | + /* The firmware only reads the new idle timer value when the timer is |
|---|
| 1023 | + * disabled. |
|---|
| 1024 | + */ |
|---|
| 1025 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1026 | + kbase_csf_firmware_disable_gpu_idle_timer(kbdev); |
|---|
| 1027 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1028 | + /* Ensure that the request has taken effect */ |
|---|
| 1029 | + wait_for_global_request(kbdev, GLB_REQ_IDLE_DISABLE_MASK); |
|---|
| 1030 | + |
|---|
| 1031 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1032 | + kbdev->csf.gpu_idle_hysteresis_us = dur; |
|---|
| 1033 | + kbdev->csf.gpu_idle_dur_count = hysteresis_val; |
|---|
| 1034 | + kbase_csf_firmware_enable_gpu_idle_timer(kbdev); |
|---|
| 1035 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1036 | + wait_for_global_request(kbdev, GLB_REQ_IDLE_ENABLE_MASK); |
|---|
| 1037 | + mutex_unlock(&kbdev->csf.reg_lock); |
|---|
| 1038 | + |
|---|
| 1039 | + kbase_csf_scheduler_pm_idle(kbdev); |
|---|
| 1040 | + |
|---|
| 1041 | +end: |
|---|
| 827 | 1042 | dev_dbg(kbdev->dev, "CSF set firmware idle hysteresis count-value: 0x%.8x", |
|---|
| 828 | 1043 | hysteresis_val); |
|---|
| 829 | 1044 | |
|---|
| .. | .. |
|---|
| 832 | 1047 | |
|---|
| 833 | 1048 | static u32 convert_dur_to_core_pwroff_count(struct kbase_device *kbdev, const u32 dur_us) |
|---|
| 834 | 1049 | { |
|---|
| 835 | | -#define PWROFF_VAL_UNIT_SHIFT (10) |
|---|
| 836 | 1050 | /* Get the cntfreq_el0 value, which drives the SYSTEM_TIMESTAMP */ |
|---|
| 837 | 1051 | u64 freq = arch_timer_get_cntfrq(); |
|---|
| 838 | 1052 | u64 dur_val = dur_us; |
|---|
| .. | .. |
|---|
| 848 | 1062 | dev_warn(kbdev->dev, "No GPU clock, unexpected integration issue!"); |
|---|
| 849 | 1063 | spin_unlock(&kbdev->pm.clk_rtm.lock); |
|---|
| 850 | 1064 | |
|---|
| 851 | | - dev_info(kbdev->dev, "Can't get the timestamp frequency, " |
|---|
| 852 | | - "use cycle counter with MCU Core Poweroff timer!"); |
|---|
| 1065 | + dev_info( |
|---|
| 1066 | + kbdev->dev, |
|---|
| 1067 | + "Can't get the timestamp frequency, use cycle counter with MCU shader Core Poweroff timer!"); |
|---|
| 853 | 1068 | } |
|---|
| 854 | 1069 | |
|---|
| 855 | 1070 | /* Formula for dur_val = ((dur_us/1e6) * freq_HZ) >> 10) */ |
|---|
| .. | .. |
|---|
| 873 | 1088 | |
|---|
| 874 | 1089 | u32 kbase_csf_firmware_get_mcu_core_pwroff_time(struct kbase_device *kbdev) |
|---|
| 875 | 1090 | { |
|---|
| 876 | | - return kbdev->csf.mcu_core_pwroff_dur_us; |
|---|
| 1091 | + u32 pwroff; |
|---|
| 1092 | + unsigned long flags; |
|---|
| 1093 | + |
|---|
| 1094 | + spin_lock_irqsave(&kbdev->hwaccess_lock, flags); |
|---|
| 1095 | + pwroff = kbdev->csf.mcu_core_pwroff_dur_us; |
|---|
| 1096 | + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
|---|
| 1097 | + |
|---|
| 1098 | + return pwroff; |
|---|
| 877 | 1099 | } |
|---|
| 878 | 1100 | |
|---|
| 879 | 1101 | u32 kbase_csf_firmware_set_mcu_core_pwroff_time(struct kbase_device *kbdev, u32 dur) |
|---|
| .. | .. |
|---|
| 886 | 1108 | kbdev->csf.mcu_core_pwroff_dur_count = pwroff; |
|---|
| 887 | 1109 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
|---|
| 888 | 1110 | |
|---|
| 889 | | - dev_dbg(kbdev->dev, "MCU Core Poweroff input update: 0x%.8x", pwroff); |
|---|
| 1111 | + dev_dbg(kbdev->dev, "MCU shader Core Poweroff input update: 0x%.8x", pwroff); |
|---|
| 890 | 1112 | |
|---|
| 891 | 1113 | return pwroff; |
|---|
| 892 | 1114 | } |
|---|
| .. | .. |
|---|
| 895 | 1117 | { |
|---|
| 896 | 1118 | init_waitqueue_head(&kbdev->csf.event_wait); |
|---|
| 897 | 1119 | kbdev->csf.interrupt_received = false; |
|---|
| 898 | | - kbdev->csf.fw_timeout_ms = CSF_FIRMWARE_TIMEOUT_MS; |
|---|
| 1120 | + |
|---|
| 1121 | + kbdev->csf.fw_timeout_ms = |
|---|
| 1122 | + kbase_get_timeout_ms(kbdev, CSF_FIRMWARE_TIMEOUT); |
|---|
| 899 | 1123 | |
|---|
| 900 | 1124 | INIT_LIST_HEAD(&kbdev->csf.firmware_interfaces); |
|---|
| 901 | 1125 | INIT_LIST_HEAD(&kbdev->csf.firmware_config); |
|---|
| 902 | 1126 | INIT_LIST_HEAD(&kbdev->csf.firmware_trace_buffers.list); |
|---|
| 1127 | + INIT_LIST_HEAD(&kbdev->csf.user_reg.list); |
|---|
| 903 | 1128 | INIT_WORK(&kbdev->csf.firmware_reload_work, |
|---|
| 904 | 1129 | kbase_csf_firmware_reload_worker); |
|---|
| 905 | 1130 | INIT_WORK(&kbdev->csf.fw_error_work, firmware_error_worker); |
|---|
| .. | .. |
|---|
| 909 | 1134 | return 0; |
|---|
| 910 | 1135 | } |
|---|
| 911 | 1136 | |
|---|
| 912 | | -int kbase_csf_firmware_init(struct kbase_device *kbdev) |
|---|
| 1137 | +void kbase_csf_firmware_early_term(struct kbase_device *kbdev) |
|---|
| 1138 | +{ |
|---|
| 1139 | + mutex_destroy(&kbdev->csf.reg_lock); |
|---|
| 1140 | +} |
|---|
| 1141 | + |
|---|
| 1142 | +int kbase_csf_firmware_late_init(struct kbase_device *kbdev) |
|---|
| 1143 | +{ |
|---|
| 1144 | + kbdev->csf.gpu_idle_hysteresis_us = FIRMWARE_IDLE_HYSTERESIS_TIME_USEC; |
|---|
| 1145 | +#ifdef KBASE_PM_RUNTIME |
|---|
| 1146 | + if (kbase_pm_gpu_sleep_allowed(kbdev)) |
|---|
| 1147 | + kbdev->csf.gpu_idle_hysteresis_us /= FIRMWARE_IDLE_HYSTERESIS_GPU_SLEEP_SCALER; |
|---|
| 1148 | +#endif |
|---|
| 1149 | + WARN_ON(!kbdev->csf.gpu_idle_hysteresis_us); |
|---|
| 1150 | + kbdev->csf.gpu_idle_dur_count = |
|---|
| 1151 | + convert_dur_to_idle_count(kbdev, kbdev->csf.gpu_idle_hysteresis_us); |
|---|
| 1152 | + |
|---|
| 1153 | + return 0; |
|---|
| 1154 | +} |
|---|
| 1155 | + |
|---|
| 1156 | +int kbase_csf_firmware_load_init(struct kbase_device *kbdev) |
|---|
| 913 | 1157 | { |
|---|
| 914 | 1158 | int ret; |
|---|
| 915 | 1159 | |
|---|
| .. | .. |
|---|
| 927 | 1171 | kbdev->as_free |= MCU_AS_BITMASK; |
|---|
| 928 | 1172 | return ret; |
|---|
| 929 | 1173 | } |
|---|
| 930 | | - |
|---|
| 931 | | - kbdev->csf.gpu_idle_hysteresis_ms = FIRMWARE_IDLE_HYSTERESIS_TIME_MS; |
|---|
| 932 | | - kbdev->csf.gpu_idle_dur_count = convert_dur_to_idle_count( |
|---|
| 933 | | - kbdev, FIRMWARE_IDLE_HYSTERESIS_TIME_MS); |
|---|
| 934 | 1174 | |
|---|
| 935 | 1175 | ret = kbase_mcu_shared_interface_region_tracker_init(kbdev); |
|---|
| 936 | 1176 | if (ret != 0) { |
|---|
| .. | .. |
|---|
| 979 | 1219 | return 0; |
|---|
| 980 | 1220 | |
|---|
| 981 | 1221 | error: |
|---|
| 982 | | - kbase_csf_firmware_term(kbdev); |
|---|
| 1222 | + kbase_csf_firmware_unload_term(kbdev); |
|---|
| 983 | 1223 | return ret; |
|---|
| 984 | 1224 | } |
|---|
| 985 | 1225 | |
|---|
| 986 | | -void kbase_csf_firmware_term(struct kbase_device *kbdev) |
|---|
| 1226 | +void kbase_csf_firmware_unload_term(struct kbase_device *kbdev) |
|---|
| 987 | 1227 | { |
|---|
| 988 | 1228 | cancel_work_sync(&kbdev->csf.fw_error_work); |
|---|
| 989 | 1229 | |
|---|
| 990 | 1230 | kbase_csf_timeout_term(kbdev); |
|---|
| 991 | 1231 | |
|---|
| 992 | 1232 | /* NO_MALI: Don't stop firmware or unload MMU tables */ |
|---|
| 993 | | - |
|---|
| 994 | | - kbase_mmu_term(kbdev, &kbdev->csf.mcu_mmu); |
|---|
| 995 | 1233 | |
|---|
| 996 | 1234 | kbase_csf_scheduler_term(kbdev); |
|---|
| 997 | 1235 | |
|---|
| .. | .. |
|---|
| 1018 | 1256 | |
|---|
| 1019 | 1257 | /* NO_MALI: No trace buffers to terminate */ |
|---|
| 1020 | 1258 | |
|---|
| 1021 | | -#ifndef MALI_KBASE_BUILD |
|---|
| 1022 | | - mali_kutf_fw_utf_entry_cleanup(kbdev); |
|---|
| 1023 | | -#endif |
|---|
| 1024 | | - |
|---|
| 1025 | | - mutex_destroy(&kbdev->csf.reg_lock); |
|---|
| 1026 | | - |
|---|
| 1027 | 1259 | /* This will also free up the region allocated for the shared interface |
|---|
| 1028 | 1260 | * entry parsed from the firmware image. |
|---|
| 1029 | 1261 | */ |
|---|
| 1030 | 1262 | kbase_mcu_shared_interface_region_tracker_term(kbdev); |
|---|
| 1263 | + |
|---|
| 1264 | + kbase_mmu_term(kbdev, &kbdev->csf.mcu_mmu); |
|---|
| 1031 | 1265 | } |
|---|
| 1032 | 1266 | |
|---|
| 1033 | 1267 | void kbase_csf_firmware_enable_gpu_idle_timer(struct kbase_device *kbdev) |
|---|
| 1034 | 1268 | { |
|---|
| 1035 | 1269 | struct kbase_csf_global_iface *global_iface = &kbdev->csf.global_iface; |
|---|
| 1036 | | - u32 glb_req; |
|---|
| 1270 | + const u32 glb_req = kbase_csf_firmware_global_input_read(global_iface, GLB_REQ); |
|---|
| 1037 | 1271 | |
|---|
| 1038 | 1272 | kbase_csf_scheduler_spin_lock_assert_held(kbdev); |
|---|
| 1039 | | - |
|---|
| 1040 | 1273 | /* The scheduler is assumed to only call the enable when its internal |
|---|
| 1041 | 1274 | * state indicates that the idle timer has previously been disabled. So |
|---|
| 1042 | 1275 | * on entry the expected field values are: |
|---|
| 1043 | 1276 | * 1. GLOBAL_INPUT_BLOCK.GLB_REQ.IDLE_ENABLE: 0 |
|---|
| 1044 | 1277 | * 2. GLOBAL_OUTPUT_BLOCK.GLB_ACK.IDLE_ENABLE: 0, or, on 1 -> 0 |
|---|
| 1045 | 1278 | */ |
|---|
| 1046 | | - |
|---|
| 1047 | | - glb_req = kbase_csf_firmware_global_input_read(global_iface, GLB_REQ); |
|---|
| 1048 | 1279 | if (glb_req & GLB_REQ_IDLE_ENABLE_MASK) |
|---|
| 1049 | 1280 | dev_err(kbdev->dev, "Incoherent scheduler state on REQ_IDLE_ENABLE!"); |
|---|
| 1050 | 1281 | |
|---|
| 1051 | | - kbase_csf_firmware_global_input(global_iface, GLB_IDLE_TIMER, |
|---|
| 1052 | | - kbdev->csf.gpu_idle_dur_count); |
|---|
| 1053 | | - |
|---|
| 1054 | | - kbase_csf_firmware_global_input_mask(global_iface, GLB_REQ, |
|---|
| 1055 | | - GLB_REQ_REQ_IDLE_ENABLE, GLB_REQ_IDLE_ENABLE_MASK); |
|---|
| 1056 | | - |
|---|
| 1057 | | - dev_dbg(kbdev->dev, "Enabling GPU idle timer with count-value: 0x%.8x", |
|---|
| 1058 | | - kbdev->csf.gpu_idle_dur_count); |
|---|
| 1282 | + enable_gpu_idle_timer(kbdev); |
|---|
| 1059 | 1283 | kbase_csf_ring_doorbell(kbdev, CSF_KERNEL_DOORBELL_NR); |
|---|
| 1060 | 1284 | } |
|---|
| 1061 | 1285 | |
|---|
| .. | .. |
|---|
| 1086 | 1310 | kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1087 | 1311 | } |
|---|
| 1088 | 1312 | |
|---|
| 1089 | | -int kbase_csf_firmware_ping_wait(struct kbase_device *const kbdev) |
|---|
| 1313 | +int kbase_csf_firmware_ping_wait(struct kbase_device *const kbdev, unsigned int wait_timeout_ms) |
|---|
| 1090 | 1314 | { |
|---|
| 1315 | + CSTD_UNUSED(wait_timeout_ms); |
|---|
| 1091 | 1316 | kbase_csf_firmware_ping(kbdev); |
|---|
| 1092 | 1317 | return wait_for_global_request(kbdev, GLB_REQ_PING_MASK); |
|---|
| 1093 | 1318 | } |
|---|
| .. | .. |
|---|
| 1119 | 1344 | void kbase_csf_enter_protected_mode(struct kbase_device *kbdev) |
|---|
| 1120 | 1345 | { |
|---|
| 1121 | 1346 | struct kbase_csf_global_iface *global_iface = &kbdev->csf.global_iface; |
|---|
| 1122 | | - unsigned long flags; |
|---|
| 1123 | 1347 | |
|---|
| 1124 | | - kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1348 | + kbase_csf_scheduler_spin_lock_assert_held(kbdev); |
|---|
| 1125 | 1349 | set_global_request(global_iface, GLB_REQ_PROTM_ENTER_MASK); |
|---|
| 1126 | 1350 | dev_dbg(kbdev->dev, "Sending request to enter protected mode"); |
|---|
| 1127 | 1351 | kbase_csf_ring_doorbell(kbdev, CSF_KERNEL_DOORBELL_NR); |
|---|
| 1128 | | - kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1352 | +} |
|---|
| 1129 | 1353 | |
|---|
| 1130 | | - wait_for_global_request(kbdev, GLB_REQ_PROTM_ENTER_MASK); |
|---|
| 1354 | +int kbase_csf_wait_protected_mode_enter(struct kbase_device *kbdev) |
|---|
| 1355 | +{ |
|---|
| 1356 | + int err = wait_for_global_request(kbdev, GLB_REQ_PROTM_ENTER_MASK); |
|---|
| 1357 | + |
|---|
| 1358 | + if (err) { |
|---|
| 1359 | + if (kbase_prepare_to_reset_gpu(kbdev, RESET_FLAGS_NONE)) |
|---|
| 1360 | + kbase_reset_gpu(kbdev); |
|---|
| 1361 | + } |
|---|
| 1362 | + |
|---|
| 1363 | + return err; |
|---|
| 1131 | 1364 | } |
|---|
| 1132 | 1365 | |
|---|
| 1133 | 1366 | void kbase_csf_firmware_trigger_mcu_halt(struct kbase_device *kbdev) |
|---|
| .. | .. |
|---|
| 1136 | 1369 | unsigned long flags; |
|---|
| 1137 | 1370 | |
|---|
| 1138 | 1371 | kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1372 | + /* Validate there are no on-slot groups when sending the |
|---|
| 1373 | + * halt request to firmware. |
|---|
| 1374 | + */ |
|---|
| 1375 | + WARN_ON(kbase_csf_scheduler_get_nr_active_csgs_locked(kbdev)); |
|---|
| 1139 | 1376 | set_global_request(global_iface, GLB_REQ_HALT_MASK); |
|---|
| 1140 | 1377 | dev_dbg(kbdev->dev, "Sending request to HALT MCU"); |
|---|
| 1141 | 1378 | kbase_csf_ring_doorbell(kbdev, CSF_KERNEL_DOORBELL_NR); |
|---|
| 1142 | 1379 | kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1143 | 1380 | } |
|---|
| 1381 | + |
|---|
| 1382 | +void kbase_csf_firmware_enable_mcu(struct kbase_device *kbdev) |
|---|
| 1383 | +{ |
|---|
| 1384 | + /* Trigger the boot of MCU firmware, Use the AUTO mode as |
|---|
| 1385 | + * otherwise on fast reset, to exit protected mode, MCU will |
|---|
| 1386 | + * not reboot by itself to enter normal mode. |
|---|
| 1387 | + */ |
|---|
| 1388 | + kbase_reg_write(kbdev, GPU_CONTROL_REG(MCU_CONTROL), MCU_CNTRL_AUTO); |
|---|
| 1389 | +} |
|---|
| 1390 | + |
|---|
| 1391 | +#ifdef KBASE_PM_RUNTIME |
|---|
| 1392 | +void kbase_csf_firmware_trigger_mcu_sleep(struct kbase_device *kbdev) |
|---|
| 1393 | +{ |
|---|
| 1394 | + struct kbase_csf_global_iface *global_iface = &kbdev->csf.global_iface; |
|---|
| 1395 | + unsigned long flags; |
|---|
| 1396 | + |
|---|
| 1397 | + kbase_csf_scheduler_spin_lock(kbdev, &flags); |
|---|
| 1398 | + set_global_request(global_iface, GLB_REQ_SLEEP_MASK); |
|---|
| 1399 | + dev_dbg(kbdev->dev, "Sending sleep request to MCU"); |
|---|
| 1400 | + kbase_csf_ring_doorbell(kbdev, CSF_KERNEL_DOORBELL_NR); |
|---|
| 1401 | + kbase_csf_scheduler_spin_unlock(kbdev, flags); |
|---|
| 1402 | +} |
|---|
| 1403 | + |
|---|
| 1404 | +bool kbase_csf_firmware_is_mcu_in_sleep(struct kbase_device *kbdev) |
|---|
| 1405 | +{ |
|---|
| 1406 | + lockdep_assert_held(&kbdev->hwaccess_lock); |
|---|
| 1407 | + |
|---|
| 1408 | + return (global_request_complete(kbdev, GLB_REQ_SLEEP_MASK) && |
|---|
| 1409 | + kbase_csf_firmware_mcu_halted(kbdev)); |
|---|
| 1410 | +} |
|---|
| 1411 | +#endif |
|---|
| 1144 | 1412 | |
|---|
| 1145 | 1413 | int kbase_csf_trigger_firmware_config_update(struct kbase_device *kbdev) |
|---|
| 1146 | 1414 | { |
|---|
| .. | .. |
|---|
| 1256 | 1524 | return NULL; |
|---|
| 1257 | 1525 | } |
|---|
| 1258 | 1526 | |
|---|
| 1527 | +void kbase_csf_firmware_disable_mcu(struct kbase_device *kbdev) |
|---|
| 1528 | +{ |
|---|
| 1529 | + kbase_reg_write(kbdev, GPU_CONTROL_REG(MCU_CONTROL), MCU_CNTRL_DISABLE); |
|---|
| 1530 | +} |
|---|
| 1531 | + |
|---|
| 1259 | 1532 | void kbase_csf_firmware_disable_mcu_wait(struct kbase_device *kbdev) |
|---|
| 1260 | 1533 | { |
|---|
| 1261 | 1534 | /* NO_MALI: Nothing to do here */ |
|---|
| .. | .. |
|---|
| 1286 | 1559 | gpu_map_prot = |
|---|
| 1287 | 1560 | KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_NON_CACHEABLE); |
|---|
| 1288 | 1561 | cpu_map_prot = pgprot_writecombine(cpu_map_prot); |
|---|
| 1289 | | - }; |
|---|
| 1562 | + } |
|---|
| 1290 | 1563 | |
|---|
| 1291 | 1564 | phys = kmalloc_array(num_pages, sizeof(*phys), GFP_KERNEL); |
|---|
| 1292 | 1565 | if (!phys) |
|---|
| .. | .. |
|---|
| 1296 | 1569 | if (!page_list) |
|---|
| 1297 | 1570 | goto page_list_alloc_error; |
|---|
| 1298 | 1571 | |
|---|
| 1299 | | - ret = kbase_mem_pool_alloc_pages( |
|---|
| 1300 | | - &kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], |
|---|
| 1301 | | - num_pages, phys, false); |
|---|
| 1572 | + ret = kbase_mem_pool_alloc_pages(&kbdev->mem_pools.small[KBASE_MEM_GROUP_CSF_FW], num_pages, |
|---|
| 1573 | + phys, false, NULL); |
|---|
| 1302 | 1574 | if (ret <= 0) |
|---|
| 1303 | 1575 | goto phys_mem_pool_alloc_error; |
|---|
| 1304 | 1576 | |
|---|
| .. | .. |
|---|
| 1309 | 1581 | if (!cpu_addr) |
|---|
| 1310 | 1582 | goto vmap_error; |
|---|
| 1311 | 1583 | |
|---|
| 1312 | | - va_reg = kbase_alloc_free_region(&kbdev->csf.shared_reg_rbtree, 0, |
|---|
| 1313 | | - num_pages, KBASE_REG_ZONE_MCU_SHARED); |
|---|
| 1584 | + va_reg = kbase_alloc_free_region(kbdev, &kbdev->csf.shared_reg_rbtree, 0, num_pages, |
|---|
| 1585 | + KBASE_REG_ZONE_MCU_SHARED); |
|---|
| 1314 | 1586 | if (!va_reg) |
|---|
| 1315 | 1587 | goto va_region_alloc_error; |
|---|
| 1316 | 1588 | |
|---|
| .. | .. |
|---|
| 1324 | 1596 | gpu_map_properties &= (KBASE_REG_GPU_RD | KBASE_REG_GPU_WR); |
|---|
| 1325 | 1597 | gpu_map_properties |= gpu_map_prot; |
|---|
| 1326 | 1598 | |
|---|
| 1327 | | - ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, |
|---|
| 1328 | | - va_reg->start_pfn, &phys[0], num_pages, |
|---|
| 1329 | | - gpu_map_properties, KBASE_MEM_GROUP_CSF_FW); |
|---|
| 1599 | + ret = kbase_mmu_insert_pages_no_flush(kbdev, &kbdev->csf.mcu_mmu, va_reg->start_pfn, |
|---|
| 1600 | + &phys[0], num_pages, gpu_map_properties, |
|---|
| 1601 | + KBASE_MEM_GROUP_CSF_FW, NULL, NULL, false); |
|---|
| 1330 | 1602 | if (ret) |
|---|
| 1331 | 1603 | goto mmu_insert_pages_error; |
|---|
| 1332 | 1604 | |
|---|
| .. | .. |
|---|
| 1340 | 1612 | |
|---|
| 1341 | 1613 | mmu_insert_pages_error: |
|---|
| 1342 | 1614 | mutex_lock(&kbdev->csf.reg_lock); |
|---|
| 1343 | | - kbase_remove_va_region(va_reg); |
|---|
| 1615 | + kbase_remove_va_region(kbdev, va_reg); |
|---|
| 1344 | 1616 | va_region_add_error: |
|---|
| 1345 | 1617 | kbase_free_alloced_region(va_reg); |
|---|
| 1346 | 1618 | mutex_unlock(&kbdev->csf.reg_lock); |
|---|
| .. | .. |
|---|
| 1372 | 1644 | { |
|---|
| 1373 | 1645 | if (csf_mapping->va_reg) { |
|---|
| 1374 | 1646 | mutex_lock(&kbdev->csf.reg_lock); |
|---|
| 1375 | | - kbase_remove_va_region(csf_mapping->va_reg); |
|---|
| 1647 | + kbase_remove_va_region(kbdev, csf_mapping->va_reg); |
|---|
| 1376 | 1648 | kbase_free_alloced_region(csf_mapping->va_reg); |
|---|
| 1377 | 1649 | mutex_unlock(&kbdev->csf.reg_lock); |
|---|
| 1378 | 1650 | } |
|---|