/* * The VCS is used for kernel-owned GGTT submissions to issue key termination. * Terminations are serialized, so we only need a single queue and a single * batch.
*/ staticint allocate_vcs_execution_resources(struct xe_pxp *pxp)
{ struct xe_gt *gt = pxp->gt; struct xe_device *xe = pxp->xe; struct xe_tile *tile = gt_to_tile(gt); struct xe_hw_engine *hwe; struct xe_exec_queue *q; struct xe_bo *bo; int err;
hwe = xe_gt_hw_engine(gt, XE_ENGINE_CLASS_VIDEO_DECODE, 0, true); if (!hwe) return -ENODEV;
/* * Each termination is 16 DWORDS, so 4K is enough to contain a * termination for each sessions.
*/
bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_GGTT); if (IS_ERR(bo)) {
err = PTR_ERR(bo); goto out_queue;
}
pxp->vcs_exec.q = q;
pxp->vcs_exec.bo = bo;
return 0;
out_queue:
xe_exec_queue_put(q); return err;
}
staticvoid destroy_vcs_execution_resources(struct xe_pxp *pxp)
{ if (pxp->vcs_exec.bo)
xe_bo_unpin_map_no_vm(pxp->vcs_exec.bo);
if (pxp->vcs_exec.q)
xe_exec_queue_put(pxp->vcs_exec.q);
}
/* we shouldn't reach here if the GSC engine is not available */
xe_assert(xe, hwe);
/* PXP instructions must be issued from PPGTT */
vm = xe_vm_create(xe, XE_VM_FLAG_GSC, NULL); if (IS_ERR(vm)) return PTR_ERR(vm);
/* We allocate a single object for the batch and the in/out memory */
xe_vm_lock(vm, false);
bo = xe_bo_create_pin_map(xe, tile, vm, PXP_BB_SIZE + inout_size * 2,
ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_NEEDS_UC);
xe_vm_unlock(vm); if (IS_ERR(bo)) {
err = PTR_ERR(bo); goto vm_out;
}
/** * xe_pxp_allocate_execution_resources - Allocate PXP submission objects * @pxp: the xe_pxp structure * * Allocates exec_queues objects for VCS and GSCCS submission. The GSCCS * submissions are done via PPGTT, so this function allocates a VM for it and * maps the object into it. * * Returns 0 if the allocation and mapping is successful, an errno value * otherwise.
*/ int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp)
{ int err;
err = allocate_vcs_execution_resources(pxp); if (err) return err;
/* * PXP commands can require a lot of BO space (see PXP_MAX_PACKET_SIZE), * but we currently only support a subset of commands that are small * (< 20 dwords), so a single page is enough for now.
*/
err = allocate_gsc_client_resources(pxp->gt, &pxp->gsc_res, XE_PAGE_SIZE); if (err) goto destroy_vcs_context;
/** * xe_pxp_submit_session_termination - submits a PXP inline termination * @pxp: the xe_pxp structure * @id: the session to terminate * * Emit an inline termination via the VCS engine to terminate a session. * * Returns 0 if the submission is successful, an errno value otherwise.
*/ int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id)
{ struct xe_sched_job *job; struct dma_fence *fence; long timeout;
u32 offset = 0;
u64 addr = xe_bo_ggtt_addr(pxp->vcs_exec.bo);
/* NOTE: zero size packets are used for session-cleanups */ if (msg_in && msg_in_size) {
xe_map_memcpy_to(xe, &gsc_res->msg_in, wr_offset,
msg_in, msg_in_size);
min_reply_size = sizeof(struct pxp_cmd_header);
}
/* Make sure the reply header does not contain stale data */
xe_gsc_poison_header(xe, &gsc_res->msg_out, 0);
/* * The BO is mapped at address 0 of the PPGTT, so no need to add its * base offset when calculating the in/out addresses.
*/
emit_pxp_heci_cmd(xe, &gsc_res->batch, PXP_BB_SIZE,
wr_offset + msg_in_size, PXP_BB_SIZE + gsc_res->inout_size,
wr_offset + msg_out_size_max);
xe_device_wmb(xe);
/* * If the GSC needs to communicate with CSME to complete our request, * it'll set the "pending" flag in the return header. In this scenario * we're expected to wait 50ms to give some time to the proxy code to * handle the GSC<->CSME communication and then try again. Note that, * although in most case the 50ms window is enough, the proxy flow is * not actually guaranteed to complete within that time period, so we * might have to try multiple times, up to a worst case of 2 seconds, * after which the request is considered aborted.
*/ do {
ret = pxp_pkt_submit(gsc_res->q, 0); if (ret) break;
if (xe_gsc_check_and_update_pending(xe, &gsc_res->msg_in, 0,
&gsc_res->msg_out, 0)) {
ret = -EAGAIN;
msleep(GSC_PENDING_RETRY_PAUSE_MS);
}
} while (--retry && ret == -EAGAIN);
if (ret) {
drm_err(&xe->drm, "failed to submit GSC PXP message (%pe)\n", ERR_PTR(ret)); return ret;
}
ret = xe_gsc_read_out_header(xe, &gsc_res->msg_out, 0,
min_reply_size, &rd_offset); if (ret) {
drm_err(&xe->drm, "invalid GSC reply for PXP (%pe)\n", ERR_PTR(ret)); return ret;
}
/** * xe_pxp_submit_session_init - submits a PXP GSC session initialization * @gsc_res: the pxp client resources * @id: the session to initialize * * Submit a message to the GSC FW to initialize (i.e. start) a PXP session. * * Returns 0 if the submission is successful, an errno value otherwise.
*/ int xe_pxp_submit_session_init(struct xe_pxp_gsc_client_resources *gsc_res, u32 id)
{ struct xe_device *xe = gsc_res->vm->xe; struct pxp43_create_arb_in msg_in = {0}; struct pxp43_create_arb_out msg_out = {0}; int ret;
if (id == DRM_XE_PXP_HWDRM_DEFAULT_SESSION)
msg_in.protection_mode = PXP43_INIT_SESSION_PROTECTION_ARB;
ret = gsccs_send_message(gsc_res, &msg_in, sizeof(msg_in),
&msg_out, sizeof(msg_out)); if (ret) {
drm_err(&xe->drm, "Failed to init PXP session %u (%pe)\n", id, ERR_PTR(ret));
} elseif (msg_out.header.status != 0) {
ret = -EIO;
if (is_fw_err_platform_config(msg_out.header.status))
drm_info_once(&xe->drm, "Failed to init PXP session %u due to BIOS/SOC, s=0x%x(%s)\n",
id, msg_out.header.status,
fw_err_to_string(msg_out.header.status)); else
drm_dbg(&xe->drm, "Failed to init PXP session %u, s=0x%x\n",
id, msg_out.header.status);
}
return ret;
}
/** * xe_pxp_submit_session_invalidation - submits a PXP GSC invalidation * @gsc_res: the pxp client resources * @id: the session to invalidate * * Submit a message to the GSC FW to notify it that a session has been * terminated and is therefore invalid. * * Returns 0 if the submission is successful, an errno value otherwise.
*/ int xe_pxp_submit_session_invalidation(struct xe_pxp_gsc_client_resources *gsc_res, u32 id)
{ struct xe_device *xe = gsc_res->vm->xe; struct pxp43_inv_stream_key_in msg_in = {0}; struct pxp43_inv_stream_key_out msg_out = {0}; int ret = 0;
/* * Stream key invalidation reuses the same version 4.2 input/output * command format but firmware requires 4.3 API interaction
*/
msg_in.header.api_version = PXP_APIVER(4, 3);
msg_in.header.command_id = PXP43_CMDID_INVALIDATE_STREAM_KEY;
msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header);
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.