xref: /linux/drivers/gpu/drm/xe/xe_guc_pagefault.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
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