amd-drm-next-7.3-2026-07-31:

amdgpu:
 - PM sysfs fix for APUs
 - DC pageflip timeout fixes
 - New GFX7 soft reset implementation
 - Misc code cleanup
 
 amdkfd:
 - Remove svm_bo eviction fence
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCamy9NAAKCRC93/aFa7yZ
 2NmJAP9dfXEzqxC4xoozErqmDsAHd5zCYtD80aJSyNfQuZkzhQEAnCogTQDJPK5u
 67LKXehWeCYJBx38gk412ZesZUYoKQE=
 =+H72
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-next-7.3-2026-07-31' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-7.3-2026-07-31:

amdgpu:
- PM sysfs fix for APUs
- DC pageflip timeout fixes
- New GFX7 soft reset implementation
- Misc code cleanup

amdkfd:
- Remove svm_bo eviction fence

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260731153253.1393962-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2026-08-06 12:49:49 +10:00
commit 24893f3f08
17 changed files with 381 additions and 399 deletions

View File

@ -973,24 +973,3 @@ int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev,
return kgd2kfd_reset_mes_queue(adev->kfd.dev, node_id, queue_type,
pipe, queue, db);
}
int amdgpu_amdkfd_evict_svm_bo(struct amdgpu_bo *bo)
{
struct dma_resv_iter cursor;
struct dma_fence *fence;
int r = 0;
dma_resv_iter_begin(&cursor, bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
struct amdgpu_amdkfd_fence *f = to_amdgpu_amdkfd_fence(fence);
if (f && f->svm_bo) {
r = svm_range_evict_svm_bo(f->svm_bo);
if (r)
break;
}
}
dma_resv_iter_end(&cursor);
return r;
}

View File

@ -99,7 +99,6 @@ struct amdgpu_amdkfd_fence {
struct mm_struct *mm;
spinlock_t lock;
char timeline_name[TASK_COMM_LEN];
struct svm_range_bo *svm_bo;
uint16_t context_id;
};
@ -194,7 +193,6 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev,
struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
struct mm_struct *mm,
struct svm_range_bo *svm_bo,
u16 context_id);
int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev);
@ -286,7 +284,6 @@ int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev,
int queue_type,
int pipe, int queue,
unsigned int db);
int amdgpu_amdkfd_evict_svm_bo(struct amdgpu_bo *bo);
/* Read user wptr from a specified user address space with page fault
* disabled. The memory must be pinned and mapped to the hardware when

View File

@ -62,7 +62,6 @@ static atomic_t fence_seq = ATOMIC_INIT(0);
struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
struct mm_struct *mm,
struct svm_range_bo *svm_bo,
u16 context_id)
{
struct amdgpu_amdkfd_fence *fence;
@ -76,7 +75,6 @@ struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
fence->mm = mm;
get_task_comm(fence->timeline_name, current);
spin_lock_init(&fence->lock);
fence->svm_bo = svm_bo;
fence->context_id = context_id;
dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock,
context, atomic_inc_return(&fence_seq));
@ -128,14 +126,8 @@ static bool amdkfd_fence_enable_signaling(struct dma_fence *f)
if (dma_fence_is_signaled(f))
return true;
/* if fence->svm_bo is NULL, means this fence is created through
* init_kfd_vm() or amdgpu_amdkfd_gpuvm_restore_process_bos().
* Therefore, this fence is amdgpu_amdkfd_fence->eviction_fence.
*/
if (!fence->svm_bo) {
if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, fence->context_id, f))
return true;
}
if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, fence->context_id, f))
return true;
return false;
}
@ -169,7 +161,6 @@ static void amdkfd_fence_release(struct dma_fence *f)
*
* Check if @mm is same as that of the fence @f, if same return TRUE else
* return FALSE.
* For svm bo, which support vram overcommitment, always return FALSE.
*/
bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm)
{
@ -177,7 +168,7 @@ bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm)
if (!fence)
return false;
else if (fence->mm == mm && !fence->svm_bo)
else if (fence->mm == mm)
return true;
return false;

View File

@ -1423,7 +1423,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
info->eviction_fence =
amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1),
current->mm,
NULL, process->context_id);
process->context_id);
if (!info->eviction_fence) {
pr_err("Failed to create eviction fence\n");
ret = -ENOMEM;
@ -3093,7 +3093,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
amdgpu_amdkfd_fence_create(
process_info->eviction_fence->base.context,
process_info->eviction_fence->mm,
NULL, process_info->context_id);
process_info->context_id);
if (!new_fence) {
pr_err("Failed to create eviction fence\n");

View File

@ -34,6 +34,7 @@
#include "amdgpu_xcp.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_mes.h"
#include "amdgpu_userq.h"
#include "mes_userqueue.h"
#include "nvd.h"
@ -419,8 +420,8 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev,
domain |= AMDGPU_GEM_DOMAIN_VRAM;
#endif
/* create MQD for KIQ */
if (!adev->enable_mes_kiq && !ring->mqd_obj) {
/* create MQD for KIQ (on GFX8+ where we use KIQ) */
if (adev->asic_type >= CHIP_TOPAZ && !adev->enable_mes_kiq && !ring->mqd_obj) {
/* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must
* otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD
* deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for
@ -855,6 +856,59 @@ int amdgpu_gfx_enable_kgq(struct amdgpu_device *adev, int xcc_id)
return r;
}
/**
* amdgpu_gfx_handle_priv_fault - Handle privileged instruction fault
*
* @adev: amdgpu_device pointer
* @entry: interrupt vector entry containing fault information
* @me_id: micro-engine ID of the faulty ring
* @pipe_id: pipe ID of the faulty ring
* @queue_id: queue ID of the faulty ring
*
* This function handles privileged instruction faults by identifying
* the faulty ring (gfx or compute) and triggering a scheduler fault
*/
void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry,
u8 me_id, u8 pipe_id, u8 queue_id)
{
struct amdgpu_ring *ring;
u32 doorbell_offset;
int i;
/*
* Try KQ first by ring_id (HW slot is authoritative). The
* KMD compute_hqd_mask contract guarantees KCQ and user queues
* never share a HW slot.
*/
if (!adev->gfx.disable_kq) {
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
}
doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
/* No KQ matched: HW slot is a MES-scheduled user queue. */
if (adev->enable_mes && doorbell_offset)
amdgpu_userq_process_reset_irq(adev, entry->pasid,
doorbell_offset);
}
static void amdgpu_gfx_do_off_ctrl(struct amdgpu_device *adev, bool enable,
bool no_delay)
{

View File

@ -620,6 +620,9 @@ bool amdgpu_gfx_is_high_priority_graphics_queue(struct amdgpu_device *adev,
struct amdgpu_ring *ring);
bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me,
int pipe, int queue);
void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry,
u8 me_id, u8 pipe_id, u8 queue_id);
void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable);
void amdgpu_gfx_off_ctrl_immediate(struct amdgpu_device *adev, bool enable);
int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value);

View File

@ -43,6 +43,7 @@
#include "amdgpu_vram_mgr.h"
#include "amdgpu_vm.h"
#include "amdgpu_dma_buf.h"
#include "kfd_svm.h"
/**
* DOC: amdgpu_object
@ -93,7 +94,8 @@ static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo)
bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
{
if (bo->destroy == &amdgpu_bo_destroy ||
bo->destroy == &amdgpu_bo_user_destroy)
bo->destroy == &amdgpu_bo_user_destroy ||
bo->destroy == &svm_range_bo_destroy)
return true;
return false;

View File

@ -60,6 +60,7 @@
#include "amdgpu_atomfirmware.h"
#include "amdgpu_res_cursor.h"
#include "bif/bif_4_1_d.h"
#include "kfd_svm.h"
MODULE_IMPORT_NS("DMA_BUF");
@ -1499,7 +1500,8 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
return true;
abo = ttm_to_amdgpu_bo(bo);
if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) {
if ((abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) &&
bo->destroy == &svm_range_bo_destroy) {
/*
* SVM BOs are migrated to system memory synchronously in this
* TTM eviction context. The migration needs the owning
@ -1509,7 +1511,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
* if the eviction fails for any reason, we return false so TTM
* skips this BO instead of risking a deadlock.
*/
if (amdgpu_amdkfd_evict_svm_bo(abo) < 0)
if (svm_range_evict_svm_bo(abo) < 0)
return false;
}

View File

@ -892,7 +892,12 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
amdgpu_ring_patch_cond_exec(ring, patch);
/* the double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC */
/*
* Sync CE with ME to prevent CE from fetching the next CE IB
* before the context switch is done. This is emitted before
* the first IB of a job submission after a context switch.
* The double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC.
*/
if (ring->funcs->emit_switch_buffer) {
amdgpu_ring_emit_switch_buffer(ring);
amdgpu_ring_emit_switch_buffer(ring);

View File

@ -6714,51 +6714,13 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
u8 me_id, pipe_id, queue_id;
/*
* Try KQ first by ring_id (HW slot is authoritative). The
* KMD compute_hqd_mask contract guarantees KCQ and user queues
* never share a HW slot.
*/
if (!adev->gfx.disable_kq) {
u8 me_id = (entry->ring_id & 0x0c) >> 2;
u8 pipe_id = (entry->ring_id & 0x03) >> 0;
u8 queue_id = (entry->ring_id & 0x70) >> 4;
struct amdgpu_ring *ring;
int i;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
switch (me_id) {
case 0:
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
case 1:
case 2:
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
default:
break;
}
}
/* No KQ matched: HW slot is a MES-scheduled user queue. */
if (adev->enable_mes && doorbell_offset)
amdgpu_userq_process_reset_irq(adev, entry->pasid,
doorbell_offset);
amdgpu_gfx_handle_priv_fault(adev, entry, me_id, pipe_id, queue_id);
}
static int gfx_v11_0_priv_reg_irq(struct amdgpu_device *adev,

View File

@ -5045,52 +5045,13 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
u8 me_id, pipe_id, queue_id;
/*
* Try KQ first by ring_id; UQ as fallback. KCQ and UQ never share
* a HW slot (compute_hqd_mask contract).
*/
if (!adev->gfx.disable_kq) {
u8 me_id, pipe_id, queue_id;
struct amdgpu_ring *ring;
int i;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
me_id = (entry->ring_id & 0x0c) >> 2;
pipe_id = (entry->ring_id & 0x03) >> 0;
queue_id = (entry->ring_id & 0x70) >> 4;
switch (me_id) {
case 0:
for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
ring = &adev->gfx.gfx_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
case 1:
case 2:
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
if (ring->me == me_id && ring->pipe == pipe_id &&
ring->queue == queue_id) {
drm_sched_fault(&ring->sched);
return;
}
}
break;
default:
break;
}
}
/* No KQ matched: HW slot is a MES-scheduled user queue. */
if (adev->enable_mes && doorbell_offset)
amdgpu_userq_process_reset_irq(adev, entry->pasid,
doorbell_offset);
amdgpu_gfx_handle_priv_fault(adev, entry, me_id, pipe_id, queue_id);
}
static int gfx_v12_0_priv_reg_irq(struct amdgpu_device *adev,

View File

@ -2202,12 +2202,6 @@ static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
if (flags & AMDGPU_HAVE_CTX_SWITCH) {
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
if (ib->flags & AMDGPU_IB_FLAG_CE)
header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
else
@ -2259,6 +2253,12 @@ static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, control);
}
static void gfx_v7_0_ring_emit_sb(struct amdgpu_ring *ring)
{
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
static void gfx_v7_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
{
uint32_t dw2 = 0;
@ -2547,8 +2547,12 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmSCRATCH_ADDR, 0);
/* ring 0 - compute and gfx */
/* Set ring buffer size */
ring = &adev->gfx.gfx_ring[0];
*ring->wptr_cpu_addr = 0;
*ring->rptr_cpu_addr = 0;
amdgpu_ring_clear_ring(ring);
/* Set ring buffer size */
rb_bufsz = order_base_2(ring->ring_size / 8);
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
#ifdef __BIG_ENDIAN
@ -2560,6 +2564,7 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB0_CNTL, tmp | CP_RB0_CNTL__RB_RPTR_WR_ENA_MASK);
ring->wptr = 0;
WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr));
WREG32(mmCP_RB0_RPTR, lower_32_bits(ring->wptr));
/* set the wb address whether it's enabled or not */
rptr_addr = ring->rptr_gpu_addr;
@ -2577,7 +2582,10 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB0_BASE_HI, upper_32_bits(rb_addr));
/* start the ring */
gfx_v7_0_cp_gfx_start(adev);
r = gfx_v7_0_cp_gfx_start(adev);
if (r)
return r;
r = amdgpu_ring_test_helper(ring);
if (r)
return r;
@ -2699,25 +2707,6 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
return 0;
}
/**
* gfx_v7_0_cp_compute_fini - stop the compute queues
*
* @adev: amdgpu_device pointer
*
* Stop the compute queues and tear down the driver queue
* info.
*/
static void gfx_v7_0_cp_compute_fini(struct amdgpu_device *adev)
{
int i;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
amdgpu_bo_free_kernel(&ring->mqd_obj, NULL, NULL);
}
}
static void gfx_v7_0_mec_fini(struct amdgpu_device *adev)
{
amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL);
@ -2789,28 +2778,29 @@ static void gfx_v7_0_compute_pipe_init(struct amdgpu_device *adev,
mutex_unlock(&adev->srbm_mutex);
}
static int gfx_v7_0_mqd_deactivate(struct amdgpu_device *adev)
static int gfx_v7_0_deactivate_hqd(struct amdgpu_device *adev, u32 req)
{
int i;
int i, r = 0;
/* disable the queue if it's active */
if (RREG32(mmCP_HQD_ACTIVE) & 1) {
WREG32(mmCP_HQD_DEQUEUE_REQUEST, 1);
if (RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK) {
WREG32_FIELD(CP_HQD_DEQUEUE_REQUEST, DEQUEUE_REQ, req);
for (i = 0; i < adev->usec_timeout; i++) {
if (!(RREG32(mmCP_HQD_ACTIVE) & 1))
if (!(RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK))
break;
udelay(1);
}
if (i == adev->usec_timeout)
return -ETIMEDOUT;
r = -ETIMEDOUT;
WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0);
WREG32(mmCP_HQD_PQ_RPTR, 0);
WREG32(mmCP_HQD_PQ_WPTR, 0);
}
return 0;
WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0);
WREG32(mmCP_HQD_PQ_RPTR, 0);
WREG32(mmCP_HQD_PQ_WPTR, 0);
return r;
}
static void gfx_v7_0_mqd_init(struct amdgpu_device *adev,
@ -2965,31 +2955,42 @@ static int gfx_v7_0_mqd_commit(struct amdgpu_device *adev, struct cik_mqd *mqd)
static int gfx_v7_0_compute_queue_init(struct amdgpu_device *adev, int ring_id)
{
int r;
u64 mqd_gpu_addr;
struct cik_mqd *mqd;
struct amdgpu_ring *ring = &adev->gfx.compute_ring[ring_id];
struct cik_mqd *mqd = ring->mqd_ptr;
int mqd_idx = ring - &adev->gfx.compute_ring[0];
r = amdgpu_bo_create_reserved(adev, sizeof(struct cik_mqd), PAGE_SIZE,
AMDGPU_GEM_DOMAIN_GTT, &ring->mqd_obj,
&mqd_gpu_addr, (void **)&mqd);
if (r) {
dev_warn(adev->dev, "(%d) create MQD bo failed\n", r);
return r;
if (!amdgpu_in_reset(adev) && !adev->in_suspend) {
memset((void *)mqd, 0, ring->mqd_size);
mutex_lock(&adev->srbm_mutex);
cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v7_0_mqd_init(adev, mqd, ring->mqd_gpu_addr, ring);
gfx_v7_0_deactivate_hqd(adev, 1);
gfx_v7_0_mqd_commit(adev, mqd);
cik_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
if (adev->gfx.mec.mqd_backup[mqd_idx])
memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, ring->mqd_size);
} else {
/* restore MQD to a clean status */
if (adev->gfx.mec.mqd_backup[mqd_idx])
memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], ring->mqd_size);
/* Re-commit the restored backup */
mutex_lock(&adev->srbm_mutex);
cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v7_0_deactivate_hqd(adev, 2);
gfx_v7_0_mqd_commit(adev, mqd);
cik_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
/* reset ring buffer */
ring->wptr = 0;
atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0);
atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0);
amdgpu_ring_clear_ring(ring);
}
mutex_lock(&adev->srbm_mutex);
cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v7_0_mqd_init(adev, mqd, mqd_gpu_addr, ring);
gfx_v7_0_mqd_deactivate(adev);
gfx_v7_0_mqd_commit(adev, mqd);
cik_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
amdgpu_bo_kunmap(ring->mqd_obj);
amdgpu_bo_unreserve(ring->mqd_obj);
return 0;
}
@ -3021,20 +3022,20 @@ static int gfx_v7_0_cp_compute_resume(struct amdgpu_device *adev)
/* init the queues */
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
r = gfx_v7_0_compute_queue_init(adev, i);
if (r) {
gfx_v7_0_cp_compute_fini(adev);
if (r)
return r;
}
}
gfx_v7_0_cp_compute_enable(adev, true);
r = 0;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
amdgpu_ring_test_helper(ring);
r |= amdgpu_ring_test_helper(ring);
}
return 0;
return r;
}
static void gfx_v7_0_cp_enable(struct amdgpu_device *adev, bool enable)
@ -3116,14 +3117,6 @@ static void gfx_v7_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
amdgpu_ring_write(ring, seq);
amdgpu_ring_write(ring, 0xffffffff);
amdgpu_ring_write(ring, 4); /* poll interval */
if (usepfp) {
/* sync CE with ME to prevent CE fetch CEIB before context switch done */
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
}
/*
@ -3165,15 +3158,25 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
/* sync PFP to ME, otherwise we might get invalid PFP reads */
amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
amdgpu_ring_write(ring, 0x0);
/* synce CE with ME to prevent CE fetch CEIB before context switch done */
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
amdgpu_ring_write(ring, 0);
}
}
static unsigned int gfx_v7_0_ring_emit_init_cond_exec(struct amdgpu_ring *ring,
uint64_t gpu_addr)
{
unsigned int ret;
/* Discard following DWs after this packet when gpu_addr==0 */
amdgpu_ring_write(ring, PACKET3(PACKET3_COND_EXEC, 3));
amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
amdgpu_ring_write(ring, 0);
ret = ring->wptr & ring->buf_mask;
/* patch dummy value later */
amdgpu_ring_write(ring, 0);
return ret;
}
static void gfx_v7_0_ring_emit_wreg(struct amdgpu_ring *ring,
uint32_t reg, uint32_t val)
{
@ -3614,21 +3617,6 @@ static void gfx_v7_0_enable_mgcg(struct amdgpu_device *adev, bool enable)
}
}
static void gfx_v7_0_update_cg(struct amdgpu_device *adev,
bool enable)
{
gfx_v7_0_enable_gui_idle_interrupt(adev, false);
/* order matters! */
if (enable) {
gfx_v7_0_enable_mgcg(adev, true);
gfx_v7_0_enable_cgcg(adev, true);
} else {
gfx_v7_0_enable_cgcg(adev, false);
gfx_v7_0_enable_mgcg(adev, false);
}
gfx_v7_0_enable_gui_idle_interrupt(adev, true);
}
static void gfx_v7_0_enable_sclk_slowdown_on_pu(struct amdgpu_device *adev,
bool enable)
{
@ -4431,6 +4419,11 @@ static int gfx_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
}
}
/* create MQD for all compute queues */
r = amdgpu_gfx_mqd_sw_init(adev, sizeof(struct cik_mqd), 0);
if (r)
return r;
adev->gfx.ce_ram_size = 0x8000;
gfx_v7_0_gpu_early_init(adev);
@ -4440,6 +4433,11 @@ static int gfx_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
adev->gfx.compute_supported_reset =
amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]);
if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) {
adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
}
return r;
}
@ -4453,7 +4451,7 @@ static int gfx_v7_0_sw_fini(struct amdgpu_ip_block *ip_block)
for (i = 0; i < adev->gfx.num_compute_rings; i++)
amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
gfx_v7_0_cp_compute_fini(adev);
amdgpu_gfx_mqd_sw_fini(adev, 0);
amdgpu_gfx_rlc_fini(adev);
gfx_v7_0_mec_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
@ -4542,80 +4540,99 @@ static int gfx_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
static int gfx_v7_0_soft_reset(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
u32 tmp;
struct amdgpu_device *adev = ip_block->adev;
int i;
int r;
/* GRBM_STATUS */
tmp = RREG32(mmGRBM_STATUS);
if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK |
GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK |
GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK |
GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK |
GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK |
GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK))
grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_CP_MASK |
GRBM_SOFT_RESET__SOFT_RESET_GFX_MASK;
grbm_soft_reset =
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GFX, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPF, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPC, 1) |
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPG, 1);
if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) {
grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_CP_MASK;
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK;
}
srbm_soft_reset =
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) |
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
/* GRBM_STATUS2 */
tmp = RREG32(mmGRBM_STATUS2);
if (tmp & GRBM_STATUS2__RLC_BUSY_MASK)
grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_RLC_MASK;
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
/* SRBM_STATUS */
tmp = RREG32(mmSRBM_STATUS);
if (tmp & SRBM_STATUS__GRBM_RQ_PENDING_MASK)
srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK;
mutex_lock(&adev->srbm_mutex);
cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0);
gfx_v7_0_deactivate_hqd(adev, 2);
cik_srbm_select(adev, 0, 0, 0, 0);
mutex_unlock(&adev->srbm_mutex);
if (grbm_soft_reset || srbm_soft_reset) {
/* disable CG/PG */
gfx_v7_0_fini_pg(adev);
gfx_v7_0_update_cg(adev, false);
/* stop the rlc */
adev->gfx.rlc.funcs->stop(adev);
/* Disable GFX parsing/prefetching */
WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK);
/* Disable MEC parsing/prefetching */
WREG32(mmCP_MEC_CNTL, CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK);
if (grbm_soft_reset) {
tmp = RREG32(mmGRBM_SOFT_RESET);
tmp |= grbm_soft_reset;
dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
udelay(50);
tmp &= ~grbm_soft_reset;
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
}
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(50);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
}
/* Wait a little for things to settle down */
udelay(50);
}
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE);
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE);
ip_block->version->funcs->suspend(ip_block);
if (grbm_soft_reset || srbm_soft_reset) {
tmp = RREG32(mmGMCON_DEBUG);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1);
WREG32(mmGMCON_DEBUG, tmp);
udelay(100);
}
if (grbm_soft_reset) {
tmp = RREG32(mmGRBM_SOFT_RESET);
tmp |= grbm_soft_reset;
dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
udelay(100);
tmp &= ~grbm_soft_reset;
WREG32(mmGRBM_SOFT_RESET, tmp);
tmp = RREG32(mmGRBM_SOFT_RESET);
udelay(100);
}
if (srbm_soft_reset) {
tmp = RREG32(mmSRBM_SOFT_RESET);
tmp |= srbm_soft_reset;
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(100);
tmp &= ~srbm_soft_reset;
WREG32(mmSRBM_SOFT_RESET, tmp);
tmp = RREG32(mmSRBM_SOFT_RESET);
udelay(100);
}
if (grbm_soft_reset || srbm_soft_reset) {
tmp = RREG32(mmGMCON_DEBUG);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0);
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0);
WREG32(mmGMCON_DEBUG, tmp);
}
/* Wait a little for things to settle down */
udelay(100);
r = ip_block->version->funcs->resume(ip_block);
r |= ip_block->version->funcs->late_init(ip_block);
if (r)
return r;
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE);
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE);
return 0;
}
@ -4950,12 +4967,15 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
.get_wptr = gfx_v7_0_ring_get_wptr_gfx,
.set_wptr = gfx_v7_0_ring_set_wptr_gfx,
.emit_frame_size =
5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
20 + /* gfx_v7_0_ring_emit_gds_switch */
7 + /* gfx_v7_0_ring_emit_hdp_flush */
5 + /* hdp invalidate */
12 + 12 + 12 + /* gfx_v7_0_ring_emit_fence_gfx x3 for user fence, vm fence */
7 + 4 + /* gfx_v7_0_ring_emit_pipeline_sync */
CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v7_0_ring_emit_vm_flush */
7 + /* gfx_v7_0_ring_emit_pipeline_sync */
CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v7_0_ring_emit_vm_flush */
3 * 2 + /* gfx_v7_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
3 + 4 + /* gfx_v7_ring_emit_cntxcntl including vgt flush*/
5, /* SURFACE_SYNC */
.emit_ib_size = 4, /* gfx_v7_0_ring_emit_ib_gfx */
@ -4969,7 +4989,9 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
.test_ib = gfx_v7_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib,
.emit_switch_buffer = gfx_v7_0_ring_emit_sb,
.emit_cntxcntl = gfx_v7_ring_emit_cntxcntl,
.init_cond_exec = gfx_v7_0_ring_emit_init_cond_exec,
.emit_wreg = gfx_v7_0_ring_emit_wreg,
.soft_recovery = gfx_v7_0_ring_soft_recovery,
.emit_mem_sync = gfx_v7_0_emit_mem_sync,
@ -4984,6 +5006,8 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
.get_wptr = gfx_v7_0_ring_get_wptr_compute,
.set_wptr = gfx_v7_0_ring_set_wptr_compute,
.emit_frame_size =
5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
20 + /* gfx_v7_0_ring_emit_gds_switch */
7 + /* gfx_v7_0_ring_emit_hdp_flush */
5 + /* hdp invalidate */
@ -5002,6 +5026,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
.test_ib = gfx_v7_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib,
.init_cond_exec = gfx_v7_0_ring_emit_init_cond_exec,
.emit_wreg = gfx_v7_0_ring_emit_wreg,
.soft_recovery = gfx_v7_0_ring_soft_recovery,
.emit_mem_sync = gfx_v7_0_emit_mem_sync_compute,

View File

@ -954,12 +954,12 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf)
pr_debug("failed get device page at addr 0x%lx\n", addr);
return VM_FAULT_SIGBUS;
}
if (!mmget_not_zero(svm_bo->eviction_fence->mm)) {
if (!mmget_not_zero(svm_bo->mm)) {
pr_debug("addr 0x%lx of process mm is destroyed\n", addr);
return VM_FAULT_SIGBUS;
}
mm = svm_bo->eviction_fence->mm;
mm = svm_bo->mm;
if (mm != vmf->vma->vm_mm)
pr_debug("addr 0x%lx is COW mapping in child process\n", addr);

View File

@ -390,8 +390,10 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo)
static void svm_range_bo_release(struct kref *kref)
{
struct svm_range_bo *svm_bo;
struct amdgpu_bo *bo;
svm_bo = container_of(kref, struct svm_range_bo, kref);
bo = &svm_bo->bo;
pr_debug("svm_bo 0x%p\n", svm_bo);
spin_lock(&svm_bo->list_lock);
@ -417,12 +419,12 @@ static void svm_range_bo_release(struct kref *kref)
}
spin_unlock(&svm_bo->list_lock);
if (mmget_not_zero(svm_bo->eviction_fence->mm)) {
if (mmget_not_zero(svm_bo->mm)) {
struct kfd_process_device *pdd;
struct kfd_process *p;
struct mm_struct *mm;
mm = svm_bo->eviction_fence->mm;
mm = svm_bo->mm;
/*
* The forked child process takes svm_bo device pages ref, svm_bo could be
* released after parent process is gone.
@ -431,18 +433,13 @@ static void svm_range_bo_release(struct kref *kref)
if (p) {
pdd = kfd_get_process_device_data(svm_bo->node, p);
if (pdd)
atomic64_sub(amdgpu_bo_size(svm_bo->bo), &pdd->vram_usage);
atomic64_sub(amdgpu_bo_size(bo), &pdd->vram_usage);
kfd_unref_process(p);
}
mmput(mm);
}
if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base))
/* We're not in the eviction worker. Signal the fence. */
dma_fence_signal(&svm_bo->eviction_fence->base);
dma_fence_put(&svm_bo->eviction_fence->base);
amdgpu_bo_unref(&svm_bo->bo);
kfree(svm_bo);
amdgpu_bo_unref(&bo);
}
static void svm_range_bo_wq_release(struct work_struct *work)
@ -504,20 +501,11 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange)
return false;
}
if (READ_ONCE(prange->svm_bo->evicting)) {
struct dma_fence *f;
struct svm_range_bo *svm_bo;
/* The BO is getting evicted,
* we need to get a new one
*/
mutex_unlock(&prange->lock);
svm_bo = prange->svm_bo;
f = dma_fence_get(&svm_bo->eviction_fence->base);
svm_range_bo_unref(prange->svm_bo);
/* wait for the fence to avoid long spin-loop
* at list_empty_careful
*/
dma_fence_wait(f, false);
dma_fence_put(f);
} else {
/* The BO was still around and we got
* a new reference to it
@ -526,7 +514,7 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange)
pr_debug("reuse old bo svms 0x%p [0x%lx 0x%lx]\n",
prange->svms, prange->start, prange->last);
prange->ttm_res = prange->svm_bo->bo->tbo.resource;
prange->ttm_res = prange->svm_bo->bo.tbo.resource;
return true;
}
@ -545,19 +533,22 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange)
return false;
}
static struct svm_range_bo *svm_range_bo_new(void)
#define to_svm_range_bo(bo) container_of((bo), struct svm_range_bo, bo)
void svm_range_bo_destroy(struct ttm_buffer_object *tbo)
{
struct svm_range_bo *svm_bo;
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
struct svm_range_bo *svm_bo = to_svm_range_bo(bo);
svm_bo = kzalloc_obj(*svm_bo);
if (!svm_bo)
return NULL;
kref_init(&svm_bo->kref);
INIT_LIST_HEAD(&svm_bo->range_list);
spin_lock_init(&svm_bo->list_lock);
return svm_bo;
drm_gem_object_release(&bo->tbo.base);
/*
* svm_bo->mm is only set once the BO is fully created. If
* ttm_bo_init_reserved() fails (e.g. no VRAM could be evicted), it
* calls this destroy callback with mm still NULL, so guard the drop.
*/
if (svm_bo->mm)
mmdrop(svm_bo->mm);
kvfree(svm_bo);
}
int
@ -567,7 +558,6 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
struct kfd_process_device *pdd;
struct amdgpu_bo_param bp;
struct svm_range_bo *svm_bo;
struct amdgpu_bo_user *ubo;
struct amdgpu_bo *bo;
struct kfd_process *p;
struct mm_struct *mm;
@ -581,26 +571,16 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
if (svm_range_validate_svm_bo(node, prange))
return 0;
svm_bo = svm_range_bo_new();
if (!svm_bo) {
pr_debug("failed to alloc svm bo\n");
return -ENOMEM;
}
mm = get_task_mm(p->lead_thread);
if (!mm) {
pr_debug("failed to get mm\n");
kfree(svm_bo);
return -ESRCH;
}
svm_bo->node = node;
svm_bo->eviction_fence =
amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1),
mm,
svm_bo, p->context_id);
mmput(mm);
svm_bo->evicting = 0;
memset(&bp, 0, sizeof(bp));
bp.size = prange->npages * PAGE_SIZE;
bp.bo_ptr_size = sizeof(struct svm_range_bo);
bp.destroy = svm_range_bo_destroy;
bp.byte_align = PAGE_SIZE;
bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
bp.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
@ -611,12 +591,23 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
if (node->xcp)
bp.xcp_id_plus1 = node->xcp->id + 1;
r = amdgpu_bo_create_user(node->adev, &bp, &ubo);
r = amdgpu_bo_create(node->adev, &bp, &bo);
if (r) {
pr_debug("failed %d to create bo\n", r);
mmput(mm);
goto create_bo_failed;
}
bo = &ubo->bo;
svm_bo = to_svm_range_bo(bo);
svm_bo->evicting = 0;
kref_init(&svm_bo->kref);
INIT_LIST_HEAD(&svm_bo->range_list);
spin_lock_init(&svm_bo->list_lock);
svm_bo->node = node;
svm_bo->mm = mm;
mmgrab(svm_bo->mm);
mmput(mm);
pr_debug("alloc bo at offset 0x%lx size 0x%lx on partition %d\n",
bo->tbo.resource->start << PAGE_SHIFT, bp.size,
@ -637,16 +628,8 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
}
}
r = dma_resv_reserve_fences(bo->tbo.base.resv, TTM_NUM_MOVE_FENCES);
if (r) {
amdgpu_bo_unreserve(bo);
goto reserve_bo_failed;
}
amdgpu_bo_fence(bo, &svm_bo->eviction_fence->base, true);
amdgpu_bo_unreserve(bo);
svm_bo->bo = bo;
prange->svm_bo = svm_bo;
prange->ttm_res = bo->tbo.resource;
prange->offset = 0;
@ -664,9 +647,6 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
reserve_bo_failed:
amdgpu_bo_unref(&bo);
create_bo_failed:
dma_fence_put(&svm_bo->eviction_fence->base);
kfree(svm_bo);
prange->ttm_res = NULL;
return r;
}
@ -3640,19 +3620,20 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange,
return 0;
}
int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo)
int svm_range_evict_svm_bo(struct amdgpu_bo *bo)
{
struct svm_range_bo *svm_bo = to_svm_range_bo(bo);
struct mm_struct *mm;
int r = 0;
if (!svm_bo_ref_unless_zero(svm_bo))
return 0;
if (!mmget_not_zero(svm_bo->eviction_fence->mm)) {
if (!mmget_not_zero(svm_bo->mm)) {
svm_range_bo_unref(svm_bo);
return 0;
}
mm = svm_bo->eviction_fence->mm;
mm = svm_bo->mm;
/*
* Called with the BO reserved; lock order is mmap_lock -> BO
@ -3721,14 +3702,6 @@ int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo)
/* Defer mmput: exit_mmap() must not run under the BO reservation. */
mmput_async(mm);
/*
* Only signal the eviction fence once the ranges have been processed.
* On -EBUSY we bailed out without migrating; leave the BO in VRAM and
* let TTM retry later.
*/
if (r != -EBUSY)
dma_fence_signal(&svm_bo->eviction_fence->base);
/* This is the last reference to svm_bo, after svm_range_vram_node_free
* has been called in svm_migrate_vram_to_ram
*/

View File

@ -39,11 +39,11 @@
((adev)->hive ? (void *)(adev)->hive : (void *)(adev))
struct svm_range_bo {
struct amdgpu_bo *bo;
struct amdgpu_bo bo;
struct kref kref;
struct list_head range_list; /* all svm ranges shared this bo */
spinlock_t list_lock;
struct amdgpu_amdkfd_fence *eviction_fence;
struct mm_struct *mm;
uint32_t evicting;
struct work_struct release_work;
struct kfd_node *node;
@ -168,13 +168,14 @@ struct svm_range *svm_range_from_addr(struct svm_range_list *svms,
struct svm_range **parent);
struct kfd_node *svm_range_get_node_by_id(struct svm_range *prange,
uint32_t gpu_id);
void svm_range_bo_destroy(struct ttm_buffer_object *tbo);
int svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange,
bool clear);
void svm_range_vram_node_free(struct svm_range *prange);
int svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
uint32_t vmid, uint32_t node_id, uint64_t addr, uint64_t ts,
bool write_fault);
int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo);
int svm_range_evict_svm_bo(struct amdgpu_bo *bo);
void svm_range_add_list_work(struct svm_range_list *svms,
struct svm_range *prange, struct mm_struct *mm,
@ -229,7 +230,11 @@ static inline int svm_range_restore_pages(struct amdgpu_device *adev,
return -EFAULT;
}
static inline int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo)
static inline void svm_range_bo_destroy(struct ttm_buffer_object *tbo)
{
}
static inline int svm_range_evict_svm_bo(struct amdgpu_bo *bo)
{
return 0;
}

View File

@ -3576,25 +3576,6 @@ static void remove_stream(struct amdgpu_device *adev,
acrtc->enabled = false;
}
static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
{
assert_spin_locked(&acrtc->base.dev->event_lock);
WARN_ON(acrtc->event);
acrtc->event = acrtc->base.state->event;
/* Set the flip status */
acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
/* Mark this event as consumed */
acrtc->base.state->event = NULL;
drm_dbg_state(acrtc->base.dev,
"crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
acrtc->crtc_id);
}
static void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state)
{
struct drm_plane *plane;
@ -3740,17 +3721,47 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
return;
if (pflip_update) {
drm_crtc_vblank_get(&acrtc->base);
WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
/* Arm flip completion handling and event delivery after programming. */
prepare_flip_isr(acrtc);
WARN_ON(acrtc->event);
acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
acrtc->event = acrtc->base.state->event;
acrtc->base.state->event = NULL;
drm_dbg_state(acrtc->base.dev,
"crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
acrtc->crtc_id);
} else if (cursor_update) {
drm_crtc_vblank_get(&acrtc->base);
acrtc->event = acrtc->base.state->event;
acrtc->base.state->event = NULL;
}
}
/**
* dm_arm_vblank_event_pre_programming - Prepare for programming
* @acrtc: The amdgpu CRTC to prepare
* @acrtc_state: The new CRTC state
* @pflip_update: Whether a page flip is being programmed
* @cursor_update: Whether a cursor update is being programmed
*
* Grab a reference on the vblank counter if a page flip or cursor update is to
* be programmed. Do this before programming so the HW is not in any
* idle-optimized state (such as PSR).
*/
static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc,
struct dm_crtc_state *acrtc_state,
bool pflip_update,
bool cursor_update)
{
assert_spin_locked(&acrtc->base.dev->event_lock);
if (!acrtc->base.state->event || acrtc_state->active_planes == 0)
return;
if (pflip_update || cursor_update)
drm_crtc_vblank_get(&acrtc->base);
}
static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
struct drm_device *dev,
struct amdgpu_display_manager *dm,
@ -4013,16 +4024,19 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
}
/*
* DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for
* event delivery. Only GRPH_FLIP handler can send pflip events, and it
* only fires if HW latched to the flip. Maintain legacy behavior by
* arming event before programming.
*/
if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
dm_arm_vblank_event_pre_programming(acrtc_attach, acrtc_state,
pflip_present,
cursor_update);
/*
* DCE depends on a combination of GRPH_FLIP, VLINE0, and
* VUPDATE for event delivery. Only GRPH_FLIP handler can send
* pflip events, and it only fires if HW latched to the flip.
* Maintain legacy behavior by arming event before programming.
*/
if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
dm_arm_vblank_event(acrtc_attach, acrtc_state,
pflip_present, cursor_update);
pflip_present, cursor_update);
}
}

View File

@ -1183,6 +1183,13 @@ int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
return ret;
}
static bool amdgpu_dpm_is_pp_table_allowed(struct amdgpu_device *adev)
{
return !amdgpu_sriov_vf(adev) &&
!(adev->flags & AMD_IS_APU) &&
!adev->scpm_enabled;
}
int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
size_t size)
{
@ -1193,7 +1200,8 @@ int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
if ((!table && size) || (table && !size))
return -EINVAL;
if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
!pp_funcs->get_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
@ -1717,7 +1725,8 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
if (!buf || !size)
return -EINVAL;
if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)
if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
!pp_funcs->set_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);