/* * Copyright 2019 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. *
*/
num_pipes = adev->gfx.me.num_pipe_per_me * adev->gfx.me.num_me; if (num_pipes > AMDGPU_MES_MAX_GFX_PIPES)
dev_warn(adev->dev, "more gfx pipes than supported by MES! (%d vs %d)\n",
num_pipes, AMDGPU_MES_MAX_GFX_PIPES);
for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) { if (i >= num_pipes) break; if (amdgpu_ip_version(adev, GC_HWIP, 0) >=
IP_VERSION(12, 0, 0)) /* * GFX V12 has only one GFX pipe, but 8 queues in it. * GFX pipe 0 queue 0 is being used by Kernel queue. * Set GFX pipe 0 queue 1-7 for MES scheduling * mask = 1111 1110b
*/
adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0xFF : 0xFE; else /* * GFX pipe 0 queue 0 is being used by Kernel queue. * Set GFX pipe 0 queue 1 for MES scheduling * mask = 10b
*/
adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0x3 : 0x2;
}
num_pipes = adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_mec; if (num_pipes > AMDGPU_MES_MAX_COMPUTE_PIPES)
dev_warn(adev->dev, "more compute pipes than supported by MES! (%d vs %d)\n",
num_pipes, AMDGPU_MES_MAX_COMPUTE_PIPES);
for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) { if (i >= num_pipes) break;
adev->mes.compute_hqd_mask[i] = adev->gfx.disable_kq ? 0xF : 0xC;
}
num_pipes = adev->sdma.num_instances; if (num_pipes > AMDGPU_MES_MAX_SDMA_PIPES)
dev_warn(adev->dev, "more SDMA pipes than supported by MES! (%d vs %d)\n",
num_pipes, AMDGPU_MES_MAX_SDMA_PIPES);
for (i = 0; i < AMDGPU_MES_MAX_SDMA_PIPES; i++) { if (i >= num_pipes) break;
adev->mes.sdma_hqd_mask[i] = 0xfc;
}
for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs[i]); if (r) {
dev_err(adev->dev, "(%d) ring trail_fence_offs wb alloc failed\n",
r); goto error;
}
adev->mes.sch_ctx_gpu_addr[i] =
adev->wb.gpu_addr + (adev->mes.sch_ctx_offs[i] * 4);
adev->mes.sch_ctx_ptr[i] =
(uint64_t *)&adev->wb.wb[adev->mes.sch_ctx_offs[i]];
r = amdgpu_mes_doorbell_init(adev); if (r) goto error;
r = amdgpu_mes_event_log_init(adev); if (r) goto error_doorbell;
return 0;
error_doorbell:
amdgpu_mes_doorbell_free(adev);
error: for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) { if (adev->mes.sch_ctx_ptr[i])
amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs[i]); if (adev->mes.query_status_fence_ptr[i])
amdgpu_device_wb_free(adev,
adev->mes.query_status_fence_offs[i]);
}
for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) { if (adev->mes.sch_ctx_ptr[i])
amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs[i]); if (adev->mes.query_status_fence_ptr[i])
amdgpu_device_wb_free(adev,
adev->mes.query_status_fence_offs[i]);
}
/* * Avoid taking any other locks under MES lock to avoid circular * lock dependencies.
*/
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->suspend_gang(&adev->mes, &input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to suspend all gangs");
return r;
}
int amdgpu_mes_resume(struct amdgpu_device *adev)
{ struct mes_resume_gang_input input; int r;
if (!amdgpu_mes_suspend_resume_all_supported(adev)) return 0;
/* * Avoid taking any other locks under MES lock to avoid circular * lock dependencies.
*/
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->resume_gang(&adev->mes, &input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to resume all gangs");
return r;
}
int amdgpu_mes_map_legacy_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring)
{ struct mes_map_legacy_queue_input queue_input; int r;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->map_legacy_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to map legacy queue\n");
return r;
}
int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring, enum amdgpu_unmap_queues_action action,
u64 gpu_addr, u64 seq)
{ struct mes_unmap_legacy_queue_input queue_input; int r;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to unmap legacy queue\n");
return r;
}
int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsignedint vmid, bool use_mmio)
{ struct mes_reset_queue_input queue_input; int r;
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to reset legacy queue\n");
if (amdgpu_device_wb_get(adev, &addr_offset)) {
dev_err(adev->dev, "critical bug! too many mes readers\n"); goto error;
}
read_val_gpu_addr = adev->wb.gpu_addr + (addr_offset * 4);
read_val_ptr = (uint32_t *)&adev->wb.wb[addr_offset];
op_input.op = MES_MISC_OP_READ_REG;
op_input.read_reg.reg_offset = reg;
op_input.read_reg.buffer_addr = read_val_gpu_addr;
if (!adev->mes.funcs->misc_op) {
dev_err(adev->dev, "mes rreg is not supported!\n"); goto error;
}
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to read reg (0x%x)\n", reg); else
val = *(read_val_ptr);
error: if (addr_offset)
amdgpu_device_wb_free(adev, addr_offset); return val;
}
int amdgpu_mes_wreg(struct amdgpu_device *adev,
uint32_t reg, uint32_t val)
{ struct mes_misc_op_input op_input; int r;
if (!adev->mes.funcs->misc_op) {
dev_err(adev->dev, "mes wreg is not supported!\n");
r = -EINVAL; goto error;
}
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to write reg (0x%x)\n", reg);
error: return r;
}
int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev,
uint32_t reg0, uint32_t reg1,
uint32_t ref, uint32_t mask)
{ struct mes_misc_op_input op_input; int r;
if (!adev->mes.funcs->misc_op) {
dev_err(adev->dev, "mes reg_write_reg_wait is not supported!\n");
r = -EINVAL; goto error;
}
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to reg_write_reg_wait\n");
r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], AMDGPU_UCODE_REQUIRED, "%s", fw_name); if (r && need_retry && pipe == AMDGPU_MES_SCHED_PIPE) {
dev_info(adev->dev, "try to fall back to %s_mes.bin\n", ucode_prefix);
r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe],
AMDGPU_UCODE_REQUIRED, "amdgpu/%s_mes.bin", ucode_prefix);
}
/* Fix me -- node_id is used to identify the correct MES instances in the future */ staticint amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev,
uint32_t node_id, bool enable)
{ struct mes_misc_op_input op_input = {0}; int r;
if (!adev->mes.funcs->misc_op) {
dev_err(adev->dev, "mes change config is not supported!\n");
r = -EINVAL; goto error;
}
amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
amdgpu_mes_unlock(&adev->mes); if (r)
dev_err(adev->dev, "failed to change_config.\n");
error: return r;
}
int amdgpu_mes_update_enforce_isolation(struct amdgpu_device *adev)
{ int i, r = 0;
if (adev->enable_mes && adev->gfx.enable_cleaner_shader) {
mutex_lock(&adev->enforce_isolation_mutex); for (i = 0; i < (adev->xcp_mgr ? adev->xcp_mgr->num_xcps : 1); i++) { if (adev->enforce_isolation[i] == AMDGPU_ENFORCE_ISOLATION_ENABLE)
r |= amdgpu_mes_set_enforce_isolation(adev, i, true); else
r |= amdgpu_mes_set_enforce_isolation(adev, i, false);
}
mutex_unlock(&adev->enforce_isolation_mutex);
} return r;
}
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.