/* * Copyright 2022 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *
*/
for (i = 0; i < adev->sdma.num_instances; i++) {
val = RREG32_SDMA(i, regSDMA_GB_ADDR_CONFIG);
val = REG_SET_FIELD(val, SDMA_GB_ADDR_CONFIG, NUM_BANKS, 4);
val = REG_SET_FIELD(val, SDMA_GB_ADDR_CONFIG,
PIPE_INTERLEAVE_SIZE, 0);
WREG32_SDMA(i, regSDMA_GB_ADDR_CONFIG, val);
val = RREG32_SDMA(i, regSDMA_GB_ADDR_CONFIG_READ);
val = REG_SET_FIELD(val, SDMA_GB_ADDR_CONFIG_READ, NUM_BANKS,
4);
val = REG_SET_FIELD(val, SDMA_GB_ADDR_CONFIG_READ,
PIPE_INTERLEAVE_SIZE, 0);
WREG32_SDMA(i, regSDMA_GB_ADDR_CONFIG_READ, val);
}
}
/** * sdma_v4_4_2_init_microcode - load ucode images from disk * * @adev: amdgpu_device pointer * * Use the firmware interface to load the ucode images into * the driver (not loaded into hw). * Returns 0 on success, error on failure.
*/ staticint sdma_v4_4_2_init_microcode(struct amdgpu_device *adev)
{ int ret, i;
for (i = 0; i < adev->sdma.num_instances; i++) { if (amdgpu_ip_version(adev, SDMA0_HWIP, 0) == IP_VERSION(4, 4, 2) ||
amdgpu_ip_version(adev, SDMA0_HWIP, 0) == IP_VERSION(4, 4, 4) ||
amdgpu_ip_version(adev, SDMA0_HWIP, 0) == IP_VERSION(4, 4, 5)) {
ret = amdgpu_sdma_init_microcode(adev, 0, true); break;
} else {
ret = amdgpu_sdma_init_microcode(adev, i, false); if (ret) return ret;
}
}
return ret;
}
/** * sdma_v4_4_2_ring_get_rptr - get the current read pointer * * @ring: amdgpu ring pointer * * Get the current rptr from the hardware.
*/ static uint64_t sdma_v4_4_2_ring_get_rptr(struct amdgpu_ring *ring)
{
u64 rptr;
/* XXX check if swapping is necessary on BE */
rptr = READ_ONCE(*((u64 *)&ring->adev->wb.wb[ring->rptr_offs]));
/** * sdma_v4_4_2_ring_get_wptr - get the current write pointer * * @ring: amdgpu ring pointer * * Get the current wptr from the hardware.
*/ static uint64_t sdma_v4_4_2_ring_get_wptr(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev;
u64 wptr;
if (ring->use_doorbell) { /* XXX check if swapping is necessary on BE */
wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr);
} else {
wptr = RREG32_SDMA(ring->me, regSDMA_GFX_RB_WPTR_HI);
wptr = wptr << 32;
wptr |= RREG32_SDMA(ring->me, regSDMA_GFX_RB_WPTR);
DRM_DEBUG("wptr before shift [%i] wptr == 0x%016llx\n",
ring->me, wptr);
}
return wptr >> 2;
}
/** * sdma_v4_4_2_ring_set_wptr - commit the write pointer * * @ring: amdgpu ring pointer * * Write the wptr back to the hardware.
*/ staticvoid sdma_v4_4_2_ring_set_wptr(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev;
/** * sdma_v4_4_2_page_ring_get_wptr - get the current write pointer * * @ring: amdgpu ring pointer * * Get the current wptr from the hardware.
*/ static uint64_t sdma_v4_4_2_page_ring_get_wptr(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev;
u64 wptr;
if (ring->use_doorbell) { /* XXX check if swapping is necessary on BE */
wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
} else {
wptr = RREG32_SDMA(ring->me, regSDMA_PAGE_RB_WPTR_HI);
wptr = wptr << 32;
wptr |= RREG32_SDMA(ring->me, regSDMA_PAGE_RB_WPTR);
}
return wptr >> 2;
}
/** * sdma_v4_4_2_page_ring_set_wptr - commit the write pointer * * @ring: amdgpu ring pointer * * Write the wptr back to the hardware.
*/ staticvoid sdma_v4_4_2_page_ring_set_wptr(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev;
if (ring->use_doorbell) {
u64 *wb = (u64 *)&adev->wb.wb[ring->wptr_offs];
/* XXX check if swapping is necessary on BE */
WRITE_ONCE(*wb, (ring->wptr << 2));
WDOORBELL64(ring->doorbell_index, ring->wptr << 2);
} else {
uint64_t wptr = ring->wptr << 2;
/** * sdma_v4_4_2_ring_emit_fence - emit a fence on the DMA ring * * @ring: amdgpu ring pointer * @addr: address * @seq: sequence number * @flags: fence related flags * * Add a DMA fence packet to the ring to write * the fence seq number and DMA trap packet to generate * an interrupt if needed.
*/ staticvoid sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, unsigned flags)
{ bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT; /* write the fence */
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); /* zero in first two bits */
BUG_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, lower_32_bits(seq));
/* optionally write high bits as well */ if (write64bit) {
addr += 4;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); /* zero in first two bits */
BUG_ON(addr & 0x3);
amdgpu_ring_write(ring, lower_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(addr));
amdgpu_ring_write(ring, upper_32_bits(seq));
}
/* generate an interrupt */
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_TRAP));
amdgpu_ring_write(ring, SDMA_PKT_TRAP_INT_CONTEXT_INT_CONTEXT(0));
}
/** * sdma_v4_4_2_inst_gfx_stop - stop the gfx async dma engines * * @adev: amdgpu_device pointer * @inst_mask: mask of dma engine instances to be disabled * * Stop the gfx async dma ring buffers.
*/ staticvoid sdma_v4_4_2_inst_gfx_stop(struct amdgpu_device *adev,
uint32_t inst_mask)
{ struct amdgpu_ring *sdma[AMDGPU_MAX_SDMA_INSTANCES];
u32 doorbell_offset, doorbell;
u32 rb_cntl, ib_cntl, sdma_cntl; int i;
/** * sdma_v4_4_2_inst_enable - stop the async dma engines * * @adev: amdgpu_device pointer * @enable: enable/disable the DMA MEs. * @inst_mask: mask of dma engine instances to be enabled * * Halt or unhalt the async dma engines.
*/ staticvoid sdma_v4_4_2_inst_enable(struct amdgpu_device *adev, bool enable,
uint32_t inst_mask)
{
u32 f32_cntl; int i;
if (!enable) {
sdma_v4_4_2_inst_gfx_stop(adev, inst_mask);
sdma_v4_4_2_inst_rlc_stop(adev, inst_mask); if (adev->sdma.has_page_queue)
sdma_v4_4_2_inst_page_stop(adev, inst_mask);
/* SDMA FW needs to respond to FREEZE requests during reset.
* Keep it running during reset */ if (!amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) return;
}
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) return;
/* before programing wptr to a less value, need set minor_ptr_update first */
WREG32_SDMA(i, regSDMA_GFX_MINOR_PTR_UPDATE, 1);
/* For the guilty queue, set RPTR to the current wptr to skip bad commands, * It is not a guilty queue, restore cache_rptr and continue execution.
*/ if (adev->sdma.instance[i].gfx_guilty)
rwptr = ring->wptr; else
rwptr = ring->cached_rptr;
/* For the guilty queue, set RPTR to the current wptr to skip bad commands, * It is not a guilty queue, restore cache_rptr and continue execution.
*/ if (adev->sdma.instance[i].page_guilty)
rwptr = ring->wptr; else
rwptr = ring->cached_rptr;
/** * sdma_v4_4_2_inst_rlc_resume - setup and start the async dma engines * * @adev: amdgpu_device pointer * @inst_mask: mask of dma engine instances to be enabled * * Set up the compute DMA queues and enable them. * Returns 0 for success, error for failure.
*/ staticint sdma_v4_4_2_inst_rlc_resume(struct amdgpu_device *adev,
uint32_t inst_mask)
{
sdma_v4_4_2_init_pg(adev);
return 0;
}
/** * sdma_v4_4_2_inst_load_microcode - load the sDMA ME ucode * * @adev: amdgpu_device pointer * @inst_mask: mask of dma engine instances to be enabled * * Loads the sDMA0/1 ucode. * Returns 0 for success, -EINVAL if the ucode is not available.
*/ staticint sdma_v4_4_2_inst_load_microcode(struct amdgpu_device *adev,
uint32_t inst_mask)
{ conststruct sdma_firmware_header_v1_0 *hdr; const __le32 *fw_data;
u32 fw_size; int i, j;
/* halt the MEs */
sdma_v4_4_2_inst_enable(adev, false, inst_mask);
for_each_inst(i, inst_mask) { if (!adev->sdma.instance[i].fw) return -EINVAL;
/** * sdma_v4_4_2_inst_start - setup and start the async dma engines * * @adev: amdgpu_device pointer * @inst_mask: mask of dma engine instances to be enabled * @restore: boolean to say restore needed or not * * Set up the DMA engines and enable them. * Returns 0 for success, error for failure.
*/ staticint sdma_v4_4_2_inst_start(struct amdgpu_device *adev,
uint32_t inst_mask, bool restore)
{ struct amdgpu_ring *ring;
uint32_t tmp_mask; int i, r = 0;
if (amdgpu_sriov_vf(adev)) {
sdma_v4_4_2_inst_ctx_switch_enable(adev, false, inst_mask);
sdma_v4_4_2_inst_enable(adev, false, inst_mask);
} else { /* bypass sdma microcode loading on Gopher */ if (!restore && adev->firmware.load_type != AMDGPU_FW_LOAD_PSP &&
adev->sdma.instance[0].fw) {
r = sdma_v4_4_2_inst_load_microcode(adev, inst_mask); if (r) return r;
}
/* unhalt the MEs */
sdma_v4_4_2_inst_enable(adev, true, inst_mask); /* enable sdma ring preemption */
sdma_v4_4_2_inst_ctx_switch_enable(adev, true, inst_mask);
}
/* start the gfx rings and rlc compute queues */
tmp_mask = inst_mask;
for_each_inst(i, tmp_mask) {
uint32_t temp;
WREG32_SDMA(i, regSDMA_SEM_WAIT_FAIL_TIMER_CNTL, 0);
sdma_v4_4_2_gfx_resume(adev, i, restore); if (adev->sdma.has_page_queue)
sdma_v4_4_2_page_resume(adev, i, restore);
/* set utc l1 enable flag always to 1 */
temp = RREG32_SDMA(i, regSDMA_CNTL);
temp = REG_SET_FIELD(temp, SDMA_CNTL, UTC_L1_ENABLE, 1);
WREG32_SDMA(i, regSDMA_CNTL, temp);
if (amdgpu_sriov_vf(adev)) {
sdma_v4_4_2_inst_ctx_switch_enable(adev, true, inst_mask);
sdma_v4_4_2_inst_enable(adev, true, inst_mask);
} else {
r = sdma_v4_4_2_inst_rlc_resume(adev, inst_mask); if (r) return r;
}
tmp_mask = inst_mask;
for_each_inst(i, tmp_mask) {
ring = &adev->sdma.instance[i].ring;
r = amdgpu_ring_test_helper(ring); if (r) return r;
if (adev->sdma.has_page_queue) { struct amdgpu_ring *page = &adev->sdma.instance[i].page;
r = amdgpu_ring_test_helper(page); if (r) return r;
}
}
return r;
}
/** * sdma_v4_4_2_ring_test_ring - simple async dma engine test * * @ring: amdgpu_ring structure holding ring information * * Test the DMA engine by writing using it to write an * value to memory. * Returns 0 for success, error for failure.
*/ staticint sdma_v4_4_2_ring_test_ring(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev; unsigned i; unsigned index; int r;
u32 tmp;
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index); if (r) return r;
/** * sdma_v4_4_2_ring_test_ib - test an IB on the DMA engine * * @ring: amdgpu_ring structure holding ring information * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT * * Test a simple IB in the DMA ring. * Returns 0 on success, error on failure.
*/ staticint sdma_v4_4_2_ring_test_ib(struct amdgpu_ring *ring, long timeout)
{ struct amdgpu_device *adev = ring->adev; struct amdgpu_ib ib; struct dma_fence *f = NULL; unsigned index; long r;
u32 tmp = 0;
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index); if (r) return r;
/** * sdma_v4_4_2_vm_copy_pte - update PTEs by copying them from the GART * * @ib: indirect buffer to fill with commands * @pe: addr of the page entry * @src: src addr to copy from * @count: number of page entries to update * * Update PTEs by copying them from the GART using sDMA.
*/ staticvoid sdma_v4_4_2_vm_copy_pte(struct amdgpu_ib *ib,
uint64_t pe, uint64_t src, unsigned count)
{ unsigned bytes = count * 8;
/** * sdma_v4_4_2_vm_write_pte - update PTEs by writing them manually * * @ib: indirect buffer to fill with commands * @pe: addr of the page entry * @value: dst addr to write into pe * @count: number of page entries to update * @incr: increase next addr by incr bytes * * Update PTEs by writing them manually using sDMA.
*/ staticvoid sdma_v4_4_2_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe,
uint64_t value, unsigned count,
uint32_t incr)
{ unsigned ndw = count * 2;
/** * sdma_v4_4_2_vm_set_pte_pde - update the page tables using sDMA * * @ib: indirect buffer to fill with commands * @pe: addr of the page entry * @addr: dst addr to write into pe * @count: number of page entries to update * @incr: increase next addr by incr bytes * @flags: access flags * * Update the page tables using sDMA.
*/ staticvoid sdma_v4_4_2_vm_set_pte_pde(struct amdgpu_ib *ib,
uint64_t pe,
uint64_t addr, unsigned count,
uint32_t incr, uint64_t flags)
{ /* for physically contiguous pages (vram) */
ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_PTEPDE);
ib->ptr[ib->length_dw++] = lower_32_bits(pe); /* dst addr */
ib->ptr[ib->length_dw++] = upper_32_bits(pe);
ib->ptr[ib->length_dw++] = lower_32_bits(flags); /* mask */
ib->ptr[ib->length_dw++] = upper_32_bits(flags);
ib->ptr[ib->length_dw++] = lower_32_bits(addr); /* value */
ib->ptr[ib->length_dw++] = upper_32_bits(addr);
ib->ptr[ib->length_dw++] = incr; /* increment size */
ib->ptr[ib->length_dw++] = 0;
ib->ptr[ib->length_dw++] = count - 1; /* number of entries */
}
/** * sdma_v4_4_2_ring_pad_ib - pad the IB to the required number of dw * * @ring: amdgpu_ring structure holding ring information * @ib: indirect buffer to fill with padding
*/ staticvoid sdma_v4_4_2_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
u32 pad_count; int i;
pad_count = (-ib->length_dw) & 7; for (i = 0; i < pad_count; i++) if (sdma && sdma->burst_nop && (i == 0))
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP) |
SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1); else
ib->ptr[ib->length_dw++] =
SDMA_PKT_HEADER_OP(SDMA_OP_NOP);
}
/** * sdma_v4_4_2_ring_emit_pipeline_sync - sync the pipeline * * @ring: amdgpu_ring pointer * * Make sure all previous operations are completed (CIK).
*/ staticvoid sdma_v4_4_2_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
{
uint32_t seq = ring->fence_drv.sync_seq;
uint64_t addr = ring->fence_drv.gpu_addr;
/** * sdma_v4_4_2_ring_emit_vm_flush - vm flush using sDMA * * @ring: amdgpu_ring pointer * @vmid: vmid number to use * @pd_addr: address * * Update the page table base and flush the VM TLB * using sDMA.
*/ staticvoid sdma_v4_4_2_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr)
{
amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr);
}
/* The initialization is done in the late_init stage to ensure that the SMU * initialization and capability setup are completed before we check the SDMA * reset capability
*/
sdma_v4_4_2_update_reset_mask(adev);
/* SDMA trap event */ for (i = 0; i < adev->sdma.num_inst_per_aid; i++) {
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_TRAP,
&adev->sdma.trap_irq); if (r) return r;
}
/* SDMA SRAM ECC event */ for (i = 0; i < adev->sdma.num_inst_per_aid; i++) {
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_SRAM_ECC,
&adev->sdma.ecc_irq); if (r) return r;
}
/* SDMA VM_HOLE/DOORBELL_INV/POLL_TIMEOUT/SRBM_WRITE_PROTECTION event*/ for (i = 0; i < adev->sdma.num_inst_per_aid; i++) {
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_VM_HOLE,
&adev->sdma.vm_hole_irq); if (r) return r;
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_DOORBELL_INVALID,
&adev->sdma.doorbell_invalid_irq); if (r) return r;
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_POLL_TIMEOUT,
&adev->sdma.pool_timeout_irq); if (r) return r;
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_SRBMWRITE,
&adev->sdma.srbm_write_irq); if (r) return r;
r = amdgpu_irq_add_id(adev, sdma_v4_4_2_seq_to_irq_id(i),
SDMA0_4_0__SRCID__SDMA_CTXEMPTY,
&adev->sdma.ctxt_empty_irq); if (r) return r;
}
for (i = 0; i < adev->sdma.num_instances; i++) {
mutex_init(&adev->sdma.instance[i].engine_reset_mutex); /* Initialize guilty flags for GFX and PAGE queues */
adev->sdma.instance[i].gfx_guilty = false;
adev->sdma.instance[i].page_guilty = false;
adev->sdma.instance[i].funcs = &sdma_v4_4_2_sdma_funcs;
DRM_DEBUG("SDMA %d use_doorbell being set to: [%s]\n", i,
ring->use_doorbell?"true":"false");
/* doorbell size is 2 dwords, get DWORD offset */
ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1;
ring->vm_hub = AMDGPU_MMHUB0(aid_id);
sprintf(ring->name, "sdma%d.%d", aid_id,
i % adev->sdma.num_inst_per_aid);
r = amdgpu_ring_init(adev, ring, 1024, &adev->sdma.trap_irq,
AMDGPU_SDMA_IRQ_INSTANCE0 + i,
AMDGPU_RING_PRIO_DEFAULT, NULL); if (r) return r;
if (adev->sdma.has_page_queue) {
ring = &adev->sdma.instance[i].page;
ring->ring_obj = NULL;
ring->use_doorbell = true;
/* doorbell index of page queue is assigned right after * gfx queue on the same instance
*/
ring->doorbell_index =
(adev->doorbell_index.sdma_engine[i] + 1) << 1;
ring->vm_hub = AMDGPU_MMHUB0(aid_id);
sprintf(ring->name, "page%d.%d", aid_id,
i % adev->sdma.num_inst_per_aid);
r = amdgpu_ring_init(adev, ring, 1024,
&adev->sdma.trap_irq,
AMDGPU_SDMA_IRQ_INSTANCE0 + i,
AMDGPU_RING_PRIO_DEFAULT, NULL); if (r) return r;
}
}
if (amdgpu_sdma_ras_sw_init(adev)) {
dev_err(adev->dev, "fail to initialize sdma ras block\n"); return -EINVAL;
}
/* Allocate memory for SDMA IP Dump buffer */
ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL); if (ptr)
adev->sdma.ip_dump = ptr; else
DRM_ERROR("Failed to allocated memory for SDMA IP Dump\n");
r = amdgpu_sdma_sysfs_reset_mask_init(adev); if (r) return r;
for (i = 0; i < adev->sdma.num_instances; i++) {
amdgpu_ring_fini(&adev->sdma.instance[i].ring); if (adev->sdma.has_page_queue)
amdgpu_ring_fini(&adev->sdma.instance[i].page);
}
/* Check if this queue is the guilty one */
adev->sdma.instance[instance_id].gfx_guilty =
sdma_v4_4_2_is_queue_selected(adev, instance_id, false); if (adev->sdma.has_page_queue)
adev->sdma.instance[instance_id].page_guilty =
sdma_v4_4_2_is_queue_selected(adev, instance_id, true);
/* Cache the rptr before reset, after the reset, * all of the registers will be reset to 0
*/
rptr = amdgpu_ring_get_rptr(ring);
ring->cached_rptr = rptr; /* Cache the rptr for the page queue if it exists */ if (adev->sdma.has_page_queue) { struct amdgpu_ring *page_ring = &adev->sdma.instance[instance_id].page;
rptr = amdgpu_ring_get_rptr(page_ring);
page_ring->cached_rptr = rptr;
}
staticint sdma_v4_4_2_restore_queue(struct amdgpu_ring *ring)
{ struct amdgpu_device *adev = ring->adev;
u32 inst_mask; int i, r;
inst_mask = 1 << ring->me;
udelay(50);
for (i = 0; i < adev->usec_timeout; i++) { if (!REG_GET_FIELD(RREG32_SDMA(ring->me, regSDMA_F32_CNTL), SDMA_F32_CNTL, HALT)) break;
udelay(1);
}
if (i == adev->usec_timeout) {
dev_err(adev->dev, "timed out waiting for SDMA%d unhalt after reset\n",
ring->me); return -ETIMEDOUT;
}
r = sdma_v4_4_2_inst_start(adev, inst_mask, true);
return r;
}
staticint sdma_v4_4_2_soft_reset_engine(struct amdgpu_device *adev,
u32 instance_id)
{ /* For SDMA 4.x, use the existing DPM interface for backward compatibility * we need to convert the logical instance ID to physical instance ID before reset.
*/ return amdgpu_dpm_reset_sdma(adev, 1 << GET_INST(SDMA0, instance_id));
}
/* Client id gives the SDMA instance in AID. To know the exact SDMA * instance, interrupt entry gives the node id which corresponds to the AID instance.
* Match node id with the AID id associated with the SDMA instance. */ for (i = instance; i < adev->sdma.num_instances;
i += adev->sdma.num_inst_per_aid) { if (adev->sdma.instance[i].aid_id ==
node_id_to_phys_map[entry->node_id]) break;
}
if (i >= adev->sdma.num_instances) {
dev_WARN_ONCE(
adev->dev, 1, "Couldn't find the right sdma instance in trap handler"); return 0;
}
switch (entry->ring_id) { case 0:
amdgpu_fence_process(&adev->sdma.instance[i].ring); break; case 1:
amdgpu_fence_process(&adev->sdma.instance[i].page); break; default: break;
} return 0;
}
/* When “Full RAS” is enabled, the per-IP interrupt sources should * be disabled and the driver should only look for the aggregated * interrupt via sync flood
*/ if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) goto out;
instance = sdma_v4_4_2_irq_id_to_seq(adev, entry->client_id); if (instance < 0) goto out;
drm_printf(p, "num_instances:%d\n", adev->sdma.num_instances); for (i = 0; i < adev->sdma.num_instances; i++) {
instance_offset = i * reg_count;
drm_printf(p, "\nInstance:%d\n", i);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.