1*f289f780SMatthew Brost // SPDX-License-Identifier: MIT 2*f289f780SMatthew Brost /* 3*f289f780SMatthew Brost * Copyright © 2025 Intel Corporation 4*f289f780SMatthew Brost */ 5*f289f780SMatthew Brost 6*f289f780SMatthew Brost #include "abi/guc_actions_abi.h" 7*f289f780SMatthew Brost #include "xe_guc.h" 8*f289f780SMatthew Brost #include "xe_guc_ct.h" 9*f289f780SMatthew Brost #include "xe_guc_pagefault.h" 10*f289f780SMatthew Brost #include "xe_pagefault.h" 11*f289f780SMatthew Brost 12*f289f780SMatthew Brost static void guc_ack_fault(struct xe_pagefault *pf, int err) 13*f289f780SMatthew Brost { 14*f289f780SMatthew Brost u32 vfid = FIELD_GET(PFD_VFID, pf->producer.msg[2]); 15*f289f780SMatthew Brost u32 engine_instance = FIELD_GET(PFD_ENG_INSTANCE, pf->producer.msg[0]); 16*f289f780SMatthew Brost u32 engine_class = FIELD_GET(PFD_ENG_CLASS, pf->producer.msg[0]); 17*f289f780SMatthew Brost u32 pdata = FIELD_GET(PFD_PDATA_LO, pf->producer.msg[0]) | 18*f289f780SMatthew Brost (FIELD_GET(PFD_PDATA_HI, pf->producer.msg[1]) << 19*f289f780SMatthew Brost PFD_PDATA_HI_SHIFT); 20*f289f780SMatthew Brost u32 action[] = { 21*f289f780SMatthew Brost XE_GUC_ACTION_PAGE_FAULT_RES_DESC, 22*f289f780SMatthew Brost 23*f289f780SMatthew Brost FIELD_PREP(PFR_VALID, 1) | 24*f289f780SMatthew Brost FIELD_PREP(PFR_SUCCESS, !!err) | 25*f289f780SMatthew Brost FIELD_PREP(PFR_REPLY, PFR_ACCESS) | 26*f289f780SMatthew Brost FIELD_PREP(PFR_DESC_TYPE, FAULT_RESPONSE_DESC) | 27*f289f780SMatthew Brost FIELD_PREP(PFR_ASID, pf->consumer.asid), 28*f289f780SMatthew Brost 29*f289f780SMatthew Brost FIELD_PREP(PFR_VFID, vfid) | 30*f289f780SMatthew Brost FIELD_PREP(PFR_ENG_INSTANCE, engine_instance) | 31*f289f780SMatthew Brost FIELD_PREP(PFR_ENG_CLASS, engine_class) | 32*f289f780SMatthew Brost FIELD_PREP(PFR_PDATA, pdata), 33*f289f780SMatthew Brost }; 34*f289f780SMatthew Brost struct xe_guc *guc = pf->producer.private; 35*f289f780SMatthew Brost 36*f289f780SMatthew Brost xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); 37*f289f780SMatthew Brost } 38*f289f780SMatthew Brost 39*f289f780SMatthew Brost static const struct xe_pagefault_ops guc_pagefault_ops = { 40*f289f780SMatthew Brost .ack_fault = guc_ack_fault, 41*f289f780SMatthew Brost }; 42*f289f780SMatthew Brost 43*f289f780SMatthew Brost /** 44*f289f780SMatthew Brost * xe_guc_pagefault_handler() - G2H page fault handler 45*f289f780SMatthew Brost * @guc: GuC object 46*f289f780SMatthew Brost * @msg: G2H message 47*f289f780SMatthew Brost * @len: Length of G2H message 48*f289f780SMatthew Brost * 49*f289f780SMatthew Brost * Parse GuC to host (G2H) message into a struct xe_pagefault and forward onto 50*f289f780SMatthew Brost * the Xe page fault layer. 51*f289f780SMatthew Brost * 52*f289f780SMatthew Brost * Return: 0 on success, errno on failure 53*f289f780SMatthew Brost */ 54*f289f780SMatthew Brost int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len) 55*f289f780SMatthew Brost { 56*f289f780SMatthew Brost struct xe_pagefault pf; 57*f289f780SMatthew Brost int i; 58*f289f780SMatthew Brost 59*f289f780SMatthew Brost #define GUC_PF_MSG_LEN_DW \ 60*f289f780SMatthew Brost (sizeof(struct xe_guc_pagefault_desc) / sizeof(u32)) 61*f289f780SMatthew Brost 62*f289f780SMatthew Brost BUILD_BUG_ON(GUC_PF_MSG_LEN_DW > XE_PAGEFAULT_PRODUCER_MSG_LEN_DW); 63*f289f780SMatthew Brost 64*f289f780SMatthew Brost if (len != GUC_PF_MSG_LEN_DW) 65*f289f780SMatthew Brost return -EPROTO; 66*f289f780SMatthew Brost 67*f289f780SMatthew Brost pf.gt = guc_to_gt(guc); 68*f289f780SMatthew Brost 69*f289f780SMatthew Brost /* 70*f289f780SMatthew Brost * XXX: These values happen to match the enum in xe_pagefault_types.h. 71*f289f780SMatthew Brost * If that changes, we’ll need to remap them here. 72*f289f780SMatthew Brost */ 73*f289f780SMatthew Brost pf.consumer.page_addr = ((u64)FIELD_GET(PFD_VIRTUAL_ADDR_HI, msg[3]) 74*f289f780SMatthew Brost << PFD_VIRTUAL_ADDR_HI_SHIFT) | 75*f289f780SMatthew Brost (FIELD_GET(PFD_VIRTUAL_ADDR_LO, msg[2]) << 76*f289f780SMatthew Brost PFD_VIRTUAL_ADDR_LO_SHIFT); 77*f289f780SMatthew Brost pf.consumer.asid = FIELD_GET(PFD_ASID, msg[1]); 78*f289f780SMatthew Brost pf.consumer.access_type = FIELD_GET(PFD_ACCESS_TYPE, msg[2]); 79*f289f780SMatthew Brost pf.consumer.fault_type = FIELD_GET(PFD_FAULT_TYPE, msg[2]); 80*f289f780SMatthew Brost if (FIELD_GET(XE2_PFD_TRVA_FAULT, msg[0])) 81*f289f780SMatthew Brost pf.consumer.fault_level = XE_PAGEFAULT_LEVEL_NACK; 82*f289f780SMatthew Brost else 83*f289f780SMatthew Brost pf.consumer.fault_level = FIELD_GET(PFD_FAULT_LEVEL, msg[0]); 84*f289f780SMatthew Brost pf.consumer.engine_class = FIELD_GET(PFD_ENG_CLASS, msg[0]); 85*f289f780SMatthew Brost pf.consumer.engine_instance = FIELD_GET(PFD_ENG_INSTANCE, msg[0]); 86*f289f780SMatthew Brost 87*f289f780SMatthew Brost pf.producer.private = guc; 88*f289f780SMatthew Brost pf.producer.ops = &guc_pagefault_ops; 89*f289f780SMatthew Brost for (i = 0; i < GUC_PF_MSG_LEN_DW; ++i) 90*f289f780SMatthew Brost pf.producer.msg[i] = msg[i]; 91*f289f780SMatthew Brost 92*f289f780SMatthew Brost #undef GUC_PF_MSG_LEN_DW 93*f289f780SMatthew Brost 94*f289f780SMatthew Brost return xe_pagefault_handler(guc_to_xe(guc), &pf); 95*f289f780SMatthew Brost } 96