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