drivers/gpu/drm/msm/adreno/a6xx_preempt.c
Source file repositories/reference/linux-study-clean/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/gpu/drm/msm/adreno/a6xx_preempt.c- Extension
.c- Size
- 11639 bytes
- Lines
- 403
- Domain
- Driver Families
- Bucket
- drivers/gpu
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
msm_gem.ha6xx_gpu.ha6xx_gmu.xml.ha6xx_preempt.hmsm_mmu.hmsm_gpu_trace.h
Detected Declarations
function a6xx_preempt_timerfunction preempt_prepare_postamblefunction preempt_disable_postamblefunction a6xx_irqfunction a6xx_preempt_irqfunction a6xx_preempt_hw_initfunction a6xx_preempt_triggerfunction preempt_init_ringfunction a6xx_preempt_finifunction a6xx_preempt_init
Annotated Snippet
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2023 Collabora, Ltd. */
/* Copyright (c) 2024 Valve Corporation */
#include "msm_gem.h"
#include "a6xx_gpu.h"
#include "a6xx_gmu.xml.h"
#include "a6xx_preempt.h"
#include "msm_mmu.h"
#include "msm_gpu_trace.h"
static void a6xx_preempt_timer(struct timer_list *t)
{
struct a6xx_gpu *a6xx_gpu = timer_container_of(a6xx_gpu, t,
preempt_timer);
struct msm_gpu *gpu = &a6xx_gpu->base.base;
struct drm_device *dev = gpu->dev;
if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED))
return;
dev_err(dev->dev, "%s: preemption timed out\n", gpu->name);
kthread_queue_work(gpu->worker, &gpu->recover_work);
}
static void preempt_prepare_postamble(struct a6xx_gpu *a6xx_gpu)
{
u32 *postamble = a6xx_gpu->preempt_postamble_ptr;
u32 count = 0;
postamble[count++] = PKT7(CP_REG_RMW, 3);
postamble[count++] = REG_A6XX_RBBM_PERFCTR_SRAM_INIT_CMD;
postamble[count++] = 0;
postamble[count++] = 1;
postamble[count++] = PKT7(CP_WAIT_REG_MEM, 6);
postamble[count++] = CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ);
postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_LO(
REG_A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS);
postamble[count++] = CP_WAIT_REG_MEM_POLL_ADDR_HI(0);
postamble[count++] = CP_WAIT_REG_MEM_3_REF(0x1);
postamble[count++] = CP_WAIT_REG_MEM_4_MASK(0x1);
postamble[count++] = CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0);
a6xx_gpu->preempt_postamble_len = count;
a6xx_gpu->postamble_enabled = true;
}
static void preempt_disable_postamble(struct a6xx_gpu *a6xx_gpu)
{
u32 *postamble = a6xx_gpu->preempt_postamble_ptr;
/*
* Disable the postamble by replacing the first packet header with a NOP
* that covers the whole buffer.
*/
*postamble = PKT7(CP_NOP, (a6xx_gpu->preempt_postamble_len - 1));
a6xx_gpu->postamble_enabled = false;
}
/*
* Set preemption keepalive vote. Please note that this vote is different from the one used in
* a6xx_irq()
*/
static void a6xx_preempt_keepalive_vote(struct msm_gpu *gpu, bool on)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
if (adreno_has_gmu_wrapper(adreno_gpu))
return;
gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_PWR_COL_PREEMPT_KEEPALIVE, on);
}
void a6xx_preempt_irq(struct msm_gpu *gpu)
{
uint32_t status;
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
struct drm_device *dev = gpu->dev;
if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING))
return;
/* Delete the preemption watchdog timer */
timer_delete(&a6xx_gpu->preempt_timer);
Annotation
- Immediate include surface: `msm_gem.h`, `a6xx_gpu.h`, `a6xx_gmu.xml.h`, `a6xx_preempt.h`, `msm_mmu.h`, `msm_gpu_trace.h`.
- Detected declarations: `function a6xx_preempt_timer`, `function preempt_prepare_postamble`, `function preempt_disable_postamble`, `function a6xx_irq`, `function a6xx_preempt_irq`, `function a6xx_preempt_hw_init`, `function a6xx_preempt_trigger`, `function preempt_init_ring`, `function a6xx_preempt_fini`, `function a6xx_preempt_init`.
- Atlas domain: Driver Families / drivers/gpu.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.