Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915/gsc: add support for GSC proxy interrupt

The GSC notifies us of a proxy request via the HECI2 interrupt. The
interrupt must be enabled both in the HECI layer and in our usual gt irq
programming; for the latter, the interrupt is enabled via the same enable
register as the GSC CS, but it does have its own mask register. When the
interrupt is received, we also need to de-assert it in both layers.

The handling of the proxy request is deferred to the same worker that we
use for GSC load. New flags have been added to distinguish between the
init case and the proxy interrupt.

v2: Make sure not to set the reset bit when enabling/disabling the GSC
interrupts, fix defines (Alan)

v3: rebase on proxy status register check

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230502163854.317653-5-daniele.ceraolospurio@intel.com

+111 -21
+19 -3
drivers/gpu/drm/i915/gt/intel_gt_irq.c
··· 15 15 #include "intel_uncore.h" 16 16 #include "intel_rps.h" 17 17 #include "pxp/intel_pxp_irq.h" 18 + #include "uc/intel_gsc_proxy.h" 18 19 19 20 static void guc_irq_handler(struct intel_guc *guc, u16 iir) 20 21 { ··· 82 81 if (instance == OTHER_GSC_INSTANCE) 83 82 return intel_gsc_irq_handler(gt, iir); 84 83 84 + if (instance == OTHER_GSC_HECI_2_INSTANCE) 85 + return intel_gsc_proxy_irq_handler(&gt->uc.gsc, iir); 86 + 85 87 WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n", 86 88 instance, iir); 87 89 } ··· 104 100 case VIDEO_ENHANCEMENT_CLASS: 105 101 return media_gt; 106 102 case OTHER_CLASS: 103 + if (instance == OTHER_GSC_HECI_2_INSTANCE) 104 + return media_gt; 107 105 if (instance == OTHER_GSC_INSTANCE && HAS_ENGINE(media_gt, GSC0)) 108 106 return media_gt; 109 107 fallthrough; ··· 262 256 u32 irqs = GT_RENDER_USER_INTERRUPT; 263 257 u32 guc_mask = intel_uc_wants_guc(&gt->uc) ? GUC_INTR_GUC2HOST : 0; 264 258 u32 gsc_mask = 0; 259 + u32 heci_mask = 0; 265 260 u32 dmask; 266 261 u32 smask; 267 262 ··· 274 267 dmask = irqs << 16 | irqs; 275 268 smask = irqs << 16; 276 269 277 - if (HAS_ENGINE(gt, GSC0)) 270 + if (HAS_ENGINE(gt, GSC0)) { 271 + /* 272 + * the heci2 interrupt is enabled via the same register as the 273 + * GSC interrupt, but it has its own mask register. 274 + */ 278 275 gsc_mask = irqs; 279 - else if (HAS_HECI_GSC(gt->i915)) 276 + heci_mask = GSC_IRQ_INTF(1); /* HECI2 IRQ for SW Proxy*/ 277 + } else if (HAS_HECI_GSC(gt->i915)) { 280 278 gsc_mask = GSC_IRQ_INTF(0) | GSC_IRQ_INTF(1); 279 + } 281 280 282 281 BUILD_BUG_ON(irqs & 0xffff0000); 283 282 ··· 293 280 if (CCS_MASK(gt)) 294 281 intel_uncore_write(uncore, GEN12_CCS_RSVD_INTR_ENABLE, smask); 295 282 if (gsc_mask) 296 - intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE, gsc_mask); 283 + intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE, gsc_mask | heci_mask); 297 284 298 285 /* Unmask irqs on RCS, BCS, VCS and VECS engines. */ 299 286 intel_uncore_write(uncore, GEN11_RCS0_RSVD_INTR_MASK, ~smask); ··· 321 308 intel_uncore_write(uncore, GEN12_CCS2_CCS3_INTR_MASK, ~dmask); 322 309 if (gsc_mask) 323 310 intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_MASK, ~gsc_mask); 311 + if (heci_mask) 312 + intel_uncore_write(uncore, GEN12_HECI2_RSVD_INTR_MASK, 313 + ~REG_FIELD_PREP(ENGINE1_MASK, heci_mask)); 324 314 325 315 if (guc_mask) { 326 316 /* the enable bit is common for both GTs but the masks are separate */
+3
drivers/gpu/drm/i915/gt/intel_gt_regs.h
··· 1596 1596 1597 1597 #define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + ((x) * 4)) 1598 1598 #define GEN11_CSME (31) 1599 + #define GEN12_HECI_2 (30) 1599 1600 #define GEN11_GUNIT (28) 1600 1601 #define GEN11_GUC (25) 1601 1602 #define MTL_MGUC (24) ··· 1638 1637 /* irq instances for OTHER_CLASS */ 1639 1638 #define OTHER_GUC_INSTANCE 0 1640 1639 #define OTHER_GTPM_INSTANCE 1 1640 + #define OTHER_GSC_HECI_2_INSTANCE 3 1641 1641 #define OTHER_KCR_INSTANCE 4 1642 1642 #define OTHER_GSC_INSTANCE 6 1643 1643 #define OTHER_MEDIA_GUC_INSTANCE 16 ··· 1654 1652 #define GEN12_VCS6_VCS7_INTR_MASK _MMIO(0x1900b4) 1655 1653 #define GEN11_VECS0_VECS1_INTR_MASK _MMIO(0x1900d0) 1656 1654 #define GEN12_VECS2_VECS3_INTR_MASK _MMIO(0x1900d4) 1655 + #define GEN12_HECI2_RSVD_INTR_MASK _MMIO(0x1900e4) 1657 1656 #define GEN11_GUC_SG_INTR_MASK _MMIO(0x1900e8) 1658 1657 #define MTL_GUC_MGUC_INTR_MASK _MMIO(0x1900e8) /* MTL+ */ 1659 1658 #define GEN11_GPM_WGBOXPERF_INTR_MASK _MMIO(0x1900ec)
+42 -2
drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c
··· 14 14 #include "intel_gsc_uc.h" 15 15 #include "intel_gsc_uc_heci_cmd_submit.h" 16 16 #include "i915_drv.h" 17 + #include "i915_reg.h" 17 18 18 19 /* 19 20 * GSC proxy: ··· 274 273 gt_err(gt, "GSC proxy worker called without the component being bound!\n"); 275 274 err = -EIO; 276 275 } else { 276 + /* 277 + * write the status bit to clear it and allow new proxy 278 + * interrupts to be generated while we handle the current 279 + * request, but be sure not to write the reset bit 280 + */ 281 + intel_uncore_rmw(gt->uncore, HECI_H_CSR(MTL_GSC_HECI2_BASE), 282 + HECI_H_CSR_RST, HECI_H_CSR_IS); 277 283 err = proxy_query(gsc); 278 284 } 279 285 mutex_unlock(&gsc->proxy.mutex); 280 286 return err; 281 287 } 282 288 289 + void intel_gsc_proxy_irq_handler(struct intel_gsc_uc *gsc, u32 iir) 290 + { 291 + struct intel_gt *gt = gsc_uc_to_gt(gsc); 292 + 293 + if (unlikely(!iir)) 294 + return; 295 + 296 + lockdep_assert_held(gt->irq_lock); 297 + 298 + if (!gsc->proxy.component) { 299 + gt_err(gt, "GSC proxy irq received without the component being bound!\n"); 300 + return; 301 + } 302 + 303 + gsc->gsc_work_actions |= GSC_ACTION_SW_PROXY; 304 + queue_work(gsc->wq, &gsc->work); 305 + } 306 + 283 307 static int i915_gsc_proxy_component_bind(struct device *i915_kdev, 284 308 struct device *mei_kdev, void *data) 285 309 { 286 310 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); 287 - struct intel_gsc_uc *gsc = &i915->media_gt->uc.gsc; 311 + struct intel_gt *gt = i915->media_gt; 312 + struct intel_gsc_uc *gsc = &gt->uc.gsc; 313 + intel_wakeref_t wakeref; 314 + 315 + /* enable HECI2 IRQs */ 316 + with_intel_runtime_pm(&i915->runtime_pm, wakeref) 317 + intel_uncore_rmw(gt->uncore, HECI_H_CSR(MTL_GSC_HECI2_BASE), 318 + HECI_H_CSR_RST, HECI_H_CSR_IE); 288 319 289 320 mutex_lock(&gsc->proxy.mutex); 290 321 gsc->proxy.component = data; ··· 330 297 struct device *mei_kdev, void *data) 331 298 { 332 299 struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); 333 - struct intel_gsc_uc *gsc = &i915->media_gt->uc.gsc; 300 + struct intel_gt *gt = i915->media_gt; 301 + struct intel_gsc_uc *gsc = &gt->uc.gsc; 302 + intel_wakeref_t wakeref; 334 303 335 304 mutex_lock(&gsc->proxy.mutex); 336 305 gsc->proxy.component = NULL; 337 306 mutex_unlock(&gsc->proxy.mutex); 307 + 308 + /* disable HECI2 IRQs */ 309 + with_intel_runtime_pm(&i915->runtime_pm, wakeref) 310 + intel_uncore_rmw(gt->uncore, HECI_H_CSR(MTL_GSC_HECI2_BASE), 311 + HECI_H_CSR_IE | HECI_H_CSR_RST, 0); 338 312 } 339 313 340 314 static const struct component_ops i915_gsc_proxy_component_ops = {
+1
drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.h
··· 13 13 int intel_gsc_proxy_init(struct intel_gsc_uc *gsc); 14 14 void intel_gsc_proxy_fini(struct intel_gsc_uc *gsc); 15 15 int intel_gsc_proxy_request_handler(struct intel_gsc_uc *gsc); 16 + void intel_gsc_proxy_irq_handler(struct intel_gsc_uc *gsc, u32 iir); 16 17 17 18 #endif
+43 -16
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
··· 17 17 struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work); 18 18 struct intel_gt *gt = gsc_uc_to_gt(gsc); 19 19 intel_wakeref_t wakeref; 20 + u32 actions; 20 21 int ret; 21 22 22 23 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 23 24 24 - ret = intel_gsc_uc_fw_upload(gsc); 25 - if (ret) 26 - goto out_put; 25 + spin_lock_irq(gt->irq_lock); 26 + actions = gsc->gsc_work_actions; 27 + gsc->gsc_work_actions = 0; 28 + spin_unlock_irq(gt->irq_lock); 27 29 28 - ret = intel_gsc_proxy_request_handler(gsc); 29 - if (ret) 30 - goto out_put; 30 + if (actions & GSC_ACTION_FW_LOAD) { 31 + ret = intel_gsc_uc_fw_upload(gsc); 32 + if (ret == -EEXIST) /* skip proxy if not a new load */ 33 + actions &= ~GSC_ACTION_FW_LOAD; 34 + else if (ret) 35 + goto out_put; 36 + } 31 37 32 - /* 33 - * If there is a proxy establishment error, the GSC might still 34 - * complete the request handling cleanly, so we need to check the 35 - * status register to check if the proxy init was actually successful 36 - */ 37 - if (intel_gsc_uc_fw_proxy_init_done(gsc)) { 38 - drm_dbg(&gt->i915->drm, "GSC Proxy initialized\n"); 39 - intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING); 40 - } else { 41 - drm_err(&gt->i915->drm, "GSC status reports proxy init not complete\n"); 38 + if (actions & (GSC_ACTION_FW_LOAD | GSC_ACTION_SW_PROXY)) { 39 + if (!intel_gsc_uc_fw_init_done(gsc)) { 40 + gt_err(gt, "Proxy request received with GSC not loaded!\n"); 41 + goto out_put; 42 + } 43 + 44 + ret = intel_gsc_proxy_request_handler(gsc); 45 + if (ret) 46 + goto out_put; 47 + 48 + /* mark the GSC FW init as done the first time we run this */ 49 + if (actions & GSC_ACTION_FW_LOAD) { 50 + /* 51 + * If there is a proxy establishment error, the GSC might still 52 + * complete the request handling cleanly, so we need to check the 53 + * status register to check if the proxy init was actually successful 54 + */ 55 + if (intel_gsc_uc_fw_proxy_init_done(gsc)) { 56 + drm_dbg(&gt->i915->drm, "GSC Proxy initialized\n"); 57 + intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_RUNNING); 58 + } else { 59 + drm_err(&gt->i915->drm, 60 + "GSC status reports proxy init not complete\n"); 61 + } 62 + } 42 63 } 43 64 44 65 out_put: ··· 207 186 208 187 void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc) 209 188 { 189 + struct intel_gt *gt = gsc_uc_to_gt(gsc); 190 + 210 191 if (!intel_uc_fw_is_loadable(&gsc->fw)) 211 192 return; 212 193 213 194 if (intel_gsc_uc_fw_init_done(gsc)) 214 195 return; 196 + 197 + spin_lock_irq(gt->irq_lock); 198 + gsc->gsc_work_actions |= GSC_ACTION_FW_LOAD; 199 + spin_unlock_irq(gt->irq_lock); 215 200 216 201 queue_work(gsc->wq, &gsc->work); 217 202 }
+3
drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.h
··· 23 23 /* for delayed load and proxy handling */ 24 24 struct workqueue_struct *wq; 25 25 struct work_struct work; 26 + u32 gsc_work_actions; /* protected by gt->irq_lock */ 27 + #define GSC_ACTION_FW_LOAD BIT(0) 28 + #define GSC_ACTION_SW_PROXY BIT(1) 26 29 27 30 struct { 28 31 struct i915_gsc_proxy_component *component;