/* * Copyright 2018 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++) if (ring == &adev->sdma.instance[i].ring ||
ring == &adev->sdma.instance[i].page) return &adev->sdma.instance[i];
return NULL;
}
int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index)
{ struct amdgpu_device *adev = ring->adev; int i;
for (i = 0; i < adev->sdma.num_instances; i++) { if (ring == &adev->sdma.instance[i].ring ||
ring == &adev->sdma.instance[i].page) {
*index = i; return 0;
}
}
return -EINVAL;
}
uint64_t amdgpu_sdma_get_csa_mc_addr(struct amdgpu_ring *ring, unsignedint vmid)
{ struct amdgpu_device *adev = ring->adev;
uint64_t csa_mc_addr;
uint32_t index = 0; int r;
/* don't enable OS preemption on SDMA under SRIOV */ if (amdgpu_sriov_vf(adev) || vmid == 0 || !adev->gfx.mcbp) return 0;
r = amdgpu_sdma_get_index_from_ring(ring, &index);
if (r || index > 31)
csa_mc_addr = 0; else
csa_mc_addr = amdgpu_csa_vaddr(adev) +
AMDGPU_CSA_SDMA_OFFSET +
index * AMDGPU_CSA_SDMA_SIZE;
return csa_mc_addr;
}
int amdgpu_sdma_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
{ int r, i;
r = amdgpu_ras_block_late_init(adev, ras_block); if (r) return r;
if (amdgpu_ras_is_supported(adev, ras_block->block)) { for (i = 0; i < adev->sdma.num_instances; i++) {
r = amdgpu_irq_get(adev, &adev->sdma.ecc_irq,
AMDGPU_SDMA_IRQ_INSTANCE0 + i); if (r) goto late_fini;
}
}
err = amdgpu_sdma_init_inst_ctx(&adev->sdma.instance[instance]); if (err) goto out;
if (duplicate) { for (i = 1; i < adev->sdma.num_instances; i++)
memcpy((void *)&adev->sdma.instance[i],
(void *)&adev->sdma.instance[0], sizeof(struct amdgpu_sdma_instance));
}
/* If not define special ras_late_init function, use default ras_late_init */ if (!ras->ras_block.ras_late_init)
ras->ras_block.ras_late_init = amdgpu_sdma_ras_late_init;
/* If not defined special ras_cb function, use default ras_cb */ if (!ras->ras_block.ras_cb)
ras->ras_block.ras_cb = amdgpu_sdma_process_ras_data_cb;
return 0;
}
/* * debugfs for to enable/disable sdma job submission to specific core.
*/ #ifdefined(CONFIG_DEBUG_FS) staticint amdgpu_debugfs_sdma_sched_mask_set(void *data, u64 val)
{ struct amdgpu_device *adev = (struct amdgpu_device *)data;
u64 i, num_ring;
u64 mask = 0; struct amdgpu_ring *ring, *page = NULL;
if (!adev) return -ENODEV;
/* Determine the number of rings per SDMA instance * (1 for sdma gfx ring, 2 if page queue exists)
*/ if (adev->sdma.has_page_queue)
num_ring = 2; else
num_ring = 1;
/* Calculate the maximum possible mask value * based on the number of SDMA instances and rings
*/
mask = BIT_ULL(adev->sdma.num_instances * num_ring) - 1;
if ((val & mask) == 0) return -EINVAL;
for (i = 0; i < adev->sdma.num_instances; ++i) {
ring = &adev->sdma.instance[i].ring; if (adev->sdma.has_page_queue)
page = &adev->sdma.instance[i].page; if (val & BIT_ULL(i * num_ring))
ring->sched.ready = true; else
ring->sched.ready = false;
if (page) { if (val & BIT_ULL(i * num_ring + 1))
page->sched.ready = true; else
page->sched.ready = false;
}
} /* publish sched.ready flag update effective immediately across smp */
smp_rmb(); return 0;
}
/* Determine the number of rings per SDMA instance * (1 for sdma gfx ring, 2 if page queue exists)
*/ if (adev->sdma.has_page_queue)
num_ring = 2; else
num_ring = 1;
for (i = 0; i < adev->sdma.num_instances; ++i) {
ring = &adev->sdma.instance[i].ring; if (adev->sdma.has_page_queue)
page = &adev->sdma.instance[i].page;
/** * amdgpu_sdma_is_shared_inv_eng - Check if a ring is an SDMA ring that shares a VM invalidation engine * @adev: Pointer to the AMDGPU device structure * @ring: Pointer to the ring structure to check * * This function checks if the given ring is an SDMA ring that shares a VM invalidation engine. * It returns true if the ring is such an SDMA ring, false otherwise.
*/ bool amdgpu_sdma_is_shared_inv_eng(struct amdgpu_device *adev, struct amdgpu_ring *ring)
{ int i = ring->me;
if (!adev->sdma.has_page_queue || i >= adev->sdma.num_instances) returnfalse;
if (sdma_instance->funcs->soft_reset_kernel_queue) return sdma_instance->funcs->soft_reset_kernel_queue(adev, instance_id);
return -EOPNOTSUPP;
}
/** * amdgpu_sdma_reset_engine - Reset a specific SDMA engine * @adev: Pointer to the AMDGPU device * @instance_id: Logical ID of the SDMA engine instance to reset * @caller_handles_kernel_queues: Skip kernel queue processing. Caller * will handle it. * * Returns: 0 on success, or a negative error code on failure.
*/ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id, bool caller_handles_kernel_queues)
{ int ret = 0; struct amdgpu_sdma_instance *sdma_instance = &adev->sdma.instance[instance_id]; struct amdgpu_ring *gfx_ring = &sdma_instance->ring; struct amdgpu_ring *page_ring = &sdma_instance->page;
mutex_lock(&sdma_instance->engine_reset_mutex);
if (!caller_handles_kernel_queues) { /* Stop the scheduler's work queue for the GFX and page rings if they are running. * This ensures that no new tasks are submitted to the queues while * the reset is in progress.
*/
drm_sched_wqueue_stop(&gfx_ring->sched);
if (adev->sdma.has_page_queue)
drm_sched_wqueue_stop(&page_ring->sched);
}
if (sdma_instance->funcs->stop_kernel_queue) {
sdma_instance->funcs->stop_kernel_queue(gfx_ring); if (adev->sdma.has_page_queue)
sdma_instance->funcs->stop_kernel_queue(page_ring);
}
/* Perform the SDMA reset for the specified instance */
ret = amdgpu_sdma_soft_reset(adev, instance_id); if (ret) {
dev_err(adev->dev, "Failed to reset SDMA logical instance %u\n", instance_id); gotoexit;
}
if (sdma_instance->funcs->start_kernel_queue) {
sdma_instance->funcs->start_kernel_queue(gfx_ring); if (adev->sdma.has_page_queue)
sdma_instance->funcs->start_kernel_queue(page_ring);
}
exit: if (!caller_handles_kernel_queues) { /* Restart the scheduler's work queue for the GFX and page rings * if they were stopped by this function. This allows new tasks * to be submitted to the queues after the reset is complete.
*/ if (!ret) {
amdgpu_fence_driver_force_completion(gfx_ring);
drm_sched_wqueue_start(&gfx_ring->sched); if (adev->sdma.has_page_queue) {
amdgpu_fence_driver_force_completion(page_ring);
drm_sched_wqueue_start(&page_ring->sched);
}
}
}
mutex_unlock(&sdma_instance->engine_reset_mutex);
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.