1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2022 Intel Corporation
4 */
5
6 #include <linux/types.h>
7
8 #include "gt/intel_gt.h"
9 #include "intel_gsc_uc.h"
10 #include "intel_gsc_fw.h"
11 #include "i915_drv.h"
12
gsc_work(struct work_struct * work)13 static void gsc_work(struct work_struct *work)
14 {
15 struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work);
16 struct intel_gt *gt = gsc_uc_to_gt(gsc);
17 intel_wakeref_t wakeref;
18
19 with_intel_runtime_pm(gt->uncore->rpm, wakeref)
20 intel_gsc_uc_fw_upload(gsc);
21 }
22
gsc_engine_supported(struct intel_gt * gt)23 static bool gsc_engine_supported(struct intel_gt *gt)
24 {
25 intel_engine_mask_t mask;
26
27 /*
28 * We reach here from i915_driver_early_probe for the primary GT before
29 * its engine mask is set, so we use the device info engine mask for it.
30 * For other GTs we expect the GT-specific mask to be set before we
31 * call this function.
32 */
33 GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);
34
35 if (gt_is_root(gt))
36 mask = RUNTIME_INFO(gt->i915)->platform_engine_mask;
37 else
38 mask = gt->info.engine_mask;
39
40 return __HAS_ENGINE(mask, GSC0);
41 }
42
intel_gsc_uc_init_early(struct intel_gsc_uc * gsc)43 void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
44 {
45 intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC);
46 INIT_WORK(&gsc->work, gsc_work);
47
48 /* we can arrive here from i915_driver_early_probe for primary
49 * GT with it being not fully setup hence check device info's
50 * engine mask
51 */
52 if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) {
53 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
54 return;
55 }
56 }
57
intel_gsc_uc_init(struct intel_gsc_uc * gsc)58 int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
59 {
60 static struct lock_class_key gsc_lock;
61 struct intel_gt *gt = gsc_uc_to_gt(gsc);
62 struct drm_i915_private *i915 = gt->i915;
63 struct intel_engine_cs *engine = gt->engine[GSC0];
64 struct intel_context *ce;
65 struct i915_vma *vma;
66 int err;
67
68 err = intel_uc_fw_init(&gsc->fw);
69 if (err)
70 goto out;
71
72 vma = intel_guc_allocate_vma(>->uc.guc, SZ_8M);
73 if (IS_ERR(vma)) {
74 err = PTR_ERR(vma);
75 goto out_fw;
76 }
77
78 gsc->local = vma;
79
80 ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,
81 I915_GEM_HWS_GSC_ADDR,
82 &gsc_lock, "gsc_context");
83 if (IS_ERR(ce)) {
84 drm_err(>->i915->drm,
85 "failed to create GSC CS ctx for FW communication\n");
86 err = PTR_ERR(ce);
87 goto out_vma;
88 }
89
90 gsc->ce = ce;
91
92 intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);
93
94 return 0;
95
96 out_vma:
97 i915_vma_unpin_and_release(&gsc->local, 0);
98 out_fw:
99 intel_uc_fw_fini(&gsc->fw);
100 out:
101 i915_probe_error(i915, "failed with %d\n", err);
102 return err;
103 }
104
intel_gsc_uc_fini(struct intel_gsc_uc * gsc)105 void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
106 {
107 if (!intel_uc_fw_is_loadable(&gsc->fw))
108 return;
109
110 flush_work(&gsc->work);
111
112 if (gsc->ce)
113 intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));
114
115 i915_vma_unpin_and_release(&gsc->local, 0);
116
117 intel_uc_fw_fini(&gsc->fw);
118 }
119
intel_gsc_uc_suspend(struct intel_gsc_uc * gsc)120 void intel_gsc_uc_suspend(struct intel_gsc_uc *gsc)
121 {
122 if (!intel_uc_fw_is_loadable(&gsc->fw))
123 return;
124
125 flush_work(&gsc->work);
126 }
127
intel_gsc_uc_load_start(struct intel_gsc_uc * gsc)128 void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)
129 {
130 if (!intel_uc_fw_is_loadable(&gsc->fw))
131 return;
132
133 if (intel_gsc_uc_fw_init_done(gsc))
134 return;
135
136 queue_work(system_unbound_wq, &gsc->work);
137 }
138