cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

a5xx_gpu.h (5370B)


      1/* SPDX-License-Identifier: GPL-2.0-only */
      2/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
      3 */
      4#ifndef __A5XX_GPU_H__
      5#define __A5XX_GPU_H__
      6
      7#include "adreno_gpu.h"
      8
      9/* Bringing over the hack from the previous targets */
     10#undef ROP_COPY
     11#undef ROP_XOR
     12
     13#include "a5xx.xml.h"
     14
     15struct a5xx_gpu {
     16	struct adreno_gpu base;
     17
     18	struct drm_gem_object *pm4_bo;
     19	uint64_t pm4_iova;
     20
     21	struct drm_gem_object *pfp_bo;
     22	uint64_t pfp_iova;
     23
     24	struct drm_gem_object *gpmu_bo;
     25	uint64_t gpmu_iova;
     26	uint32_t gpmu_dwords;
     27
     28	uint32_t lm_leakage;
     29
     30	struct msm_ringbuffer *cur_ring;
     31	struct msm_ringbuffer *next_ring;
     32
     33	struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS];
     34	struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS];
     35	struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS];
     36	uint64_t preempt_iova[MSM_GPU_MAX_RINGS];
     37
     38	atomic_t preempt_state;
     39	struct timer_list preempt_timer;
     40
     41	struct drm_gem_object *shadow_bo;
     42	uint64_t shadow_iova;
     43	uint32_t *shadow;
     44
     45	/* True if the microcode supports the WHERE_AM_I opcode */
     46	bool has_whereami;
     47};
     48
     49#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
     50
     51#ifdef CONFIG_DEBUG_FS
     52void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor);
     53#endif
     54
     55/*
     56 * In order to do lockless preemption we use a simple state machine to progress
     57 * through the process.
     58 *
     59 * PREEMPT_NONE - no preemption in progress.  Next state START.
     60 * PREEMPT_START - The trigger is evaulating if preemption is possible. Next
     61 * states: TRIGGERED, NONE
     62 * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next
     63 * state: NONE.
     64 * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next
     65 * states: FAULTED, PENDING
     66 * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger
     67 * recovery.  Next state: N/A
     68 * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is
     69 * checking the success of the operation. Next state: FAULTED, NONE.
     70 */
     71
     72enum preempt_state {
     73	PREEMPT_NONE = 0,
     74	PREEMPT_START,
     75	PREEMPT_ABORT,
     76	PREEMPT_TRIGGERED,
     77	PREEMPT_FAULTED,
     78	PREEMPT_PENDING,
     79};
     80
     81/*
     82 * struct a5xx_preempt_record is a shared buffer between the microcode and the
     83 * CPU to store the state for preemption. The record itself is much larger
     84 * (64k) but most of that is used by the CP for storage.
     85 *
     86 * There is a preemption record assigned per ringbuffer. When the CPU triggers a
     87 * preemption, it fills out the record with the useful information (wptr, ring
     88 * base, etc) and the microcode uses that information to set up the CP following
     89 * the preemption.  When a ring is switched out, the CP will save the ringbuffer
     90 * state back to the record. In this way, once the records are properly set up
     91 * the CPU can quickly switch back and forth between ringbuffers by only
     92 * updating a few registers (often only the wptr).
     93 *
     94 * These are the CPU aware registers in the record:
     95 * @magic: Must always be 0x27C4BAFC
     96 * @info: Type of the record - written 0 by the CPU, updated by the CP
     97 * @data: Data field from SET_RENDER_MODE or a checkpoint. Written and used by
     98 * the CP
     99 * @cntl: Value of RB_CNTL written by CPU, save/restored by CP
    100 * @rptr: Value of RB_RPTR written by CPU, save/restored by CP
    101 * @wptr: Value of RB_WPTR written by CPU, save/restored by CP
    102 * @rptr_addr: Value of RB_RPTR_ADDR written by CPU, save/restored by CP
    103 * @rbase: Value of RB_BASE written by CPU, save/restored by CP
    104 * @counter: GPU address of the storage area for the performance counters
    105 */
    106struct a5xx_preempt_record {
    107	uint32_t magic;
    108	uint32_t info;
    109	uint32_t data;
    110	uint32_t cntl;
    111	uint32_t rptr;
    112	uint32_t wptr;
    113	uint64_t rptr_addr;
    114	uint64_t rbase;
    115	uint64_t counter;
    116};
    117
    118/* Magic identifier for the preemption record */
    119#define A5XX_PREEMPT_RECORD_MAGIC 0x27C4BAFCUL
    120
    121/*
    122 * Even though the structure above is only a few bytes, we need a full 64k to
    123 * store the entire preemption record from the CP
    124 */
    125#define A5XX_PREEMPT_RECORD_SIZE (64 * 1024)
    126
    127/*
    128 * The preemption counter block is a storage area for the value of the
    129 * preemption counters that are saved immediately before context switch. We
    130 * append it on to the end of the allocation for the preemption record.
    131 */
    132#define A5XX_PREEMPT_COUNTER_SIZE (16 * 4)
    133
    134
    135int a5xx_power_init(struct msm_gpu *gpu);
    136void a5xx_gpmu_ucode_init(struct msm_gpu *gpu);
    137
    138static inline int spin_usecs(struct msm_gpu *gpu, uint32_t usecs,
    139		uint32_t reg, uint32_t mask, uint32_t value)
    140{
    141	while (usecs--) {
    142		udelay(1);
    143		if ((gpu_read(gpu, reg) & mask) == value)
    144			return 0;
    145		cpu_relax();
    146	}
    147
    148	return -ETIMEDOUT;
    149}
    150
    151#define shadowptr(a5xx_gpu, ring) ((a5xx_gpu)->shadow_iova + \
    152		((ring)->id * sizeof(uint32_t)))
    153
    154bool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
    155void a5xx_set_hwcg(struct msm_gpu *gpu, bool state);
    156
    157void a5xx_preempt_init(struct msm_gpu *gpu);
    158void a5xx_preempt_hw_init(struct msm_gpu *gpu);
    159void a5xx_preempt_trigger(struct msm_gpu *gpu);
    160void a5xx_preempt_irq(struct msm_gpu *gpu);
    161void a5xx_preempt_fini(struct msm_gpu *gpu);
    162
    163void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, bool sync);
    164
    165/* Return true if we are in a preempt state */
    166static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu)
    167{
    168	int preempt_state = atomic_read(&a5xx_gpu->preempt_state);
    169
    170	return !(preempt_state == PREEMPT_NONE ||
    171			preempt_state == PREEMPT_ABORT);
    172}
    173
    174#endif /* __A5XX_GPU_H__ */