1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright(c) 2023, Intel Corporation. All rights reserved. 4 */ 5 6 #include <linux/irq.h> 7 #include <linux/mei_aux.h> 8 #include <linux/pci.h> 9 #include <linux/sizes.h> 10 11 #include "xe_device_types.h" 12 #include "xe_drv.h" 13 #include "xe_heci_gsc.h" 14 #include "regs/xe_gsc_regs.h" 15 #include "xe_platform_types.h" 16 #include "xe_survivability_mode.h" 17 18 #define GSC_BAR_LENGTH 0x00000FFC 19 20 static void heci_gsc_irq_mask(struct irq_data *d) 21 { 22 /* generic irq handling */ 23 } 24 25 static void heci_gsc_irq_unmask(struct irq_data *d) 26 { 27 /* generic irq handling */ 28 } 29 30 static const struct irq_chip heci_gsc_irq_chip = { 31 .name = "gsc_irq_chip", 32 .irq_mask = heci_gsc_irq_mask, 33 .irq_unmask = heci_gsc_irq_unmask, 34 }; 35 36 static int heci_gsc_irq_init(int irq) 37 { 38 irq_set_chip_and_handler_name(irq, &heci_gsc_irq_chip, 39 handle_simple_irq, "heci_gsc_irq_handler"); 40 41 return irq_set_chip_data(irq, NULL); 42 } 43 44 /** 45 * struct heci_gsc_def - graphics security controller heci interface definitions 46 * 47 * @name: name of the heci device 48 * @bar: address of the mmio bar 49 * @bar_size: size of the mmio bar 50 * @use_polling: indication of using polling mode for the device 51 * @slow_firmware: indication of whether the device is slow (needs longer timeouts) 52 */ 53 struct heci_gsc_def { 54 const char *name; 55 unsigned long bar; 56 size_t bar_size; 57 bool use_polling; 58 bool slow_firmware; 59 }; 60 61 /* gsc resources and definitions */ 62 static const struct heci_gsc_def heci_gsc_def_dg1 = { 63 .name = "mei-gscfi", 64 .bar = DG1_GSC_HECI2_BASE, 65 .bar_size = GSC_BAR_LENGTH, 66 }; 67 68 static const struct heci_gsc_def heci_gsc_def_dg2 = { 69 .name = "mei-gscfi", 70 .bar = DG2_GSC_HECI2_BASE, 71 .bar_size = GSC_BAR_LENGTH, 72 }; 73 74 static const struct heci_gsc_def heci_gsc_def_pvc = { 75 .name = "mei-gscfi", 76 .bar = PVC_GSC_HECI2_BASE, 77 .bar_size = GSC_BAR_LENGTH, 78 .slow_firmware = true, 79 }; 80 81 static void heci_gsc_release_dev(struct device *dev) 82 { 83 struct auxiliary_device *aux_dev = to_auxiliary_dev(dev); 84 struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev); 85 86 kfree(adev); 87 } 88 89 static void xe_heci_gsc_fini(void *arg) 90 { 91 struct xe_heci_gsc *heci_gsc = arg; 92 93 if (heci_gsc->adev) { 94 struct auxiliary_device *aux_dev = &heci_gsc->adev->aux_dev; 95 96 auxiliary_device_delete(aux_dev); 97 auxiliary_device_uninit(aux_dev); 98 heci_gsc->adev = NULL; 99 } 100 101 if (heci_gsc->irq >= 0) 102 irq_free_desc(heci_gsc->irq); 103 104 heci_gsc->irq = -1; 105 } 106 107 static int heci_gsc_irq_setup(struct xe_device *xe) 108 { 109 struct xe_heci_gsc *heci_gsc = &xe->heci_gsc; 110 int ret; 111 112 heci_gsc->irq = irq_alloc_desc(0); 113 if (heci_gsc->irq < 0) { 114 drm_err(&xe->drm, "gsc irq error %d\n", heci_gsc->irq); 115 return heci_gsc->irq; 116 } 117 118 ret = heci_gsc_irq_init(heci_gsc->irq); 119 if (ret < 0) 120 drm_err(&xe->drm, "gsc irq init failed %d\n", ret); 121 122 return ret; 123 } 124 125 static int heci_gsc_add_device(struct xe_device *xe, const struct heci_gsc_def *def) 126 { 127 struct xe_heci_gsc *heci_gsc = &xe->heci_gsc; 128 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 129 struct auxiliary_device *aux_dev; 130 struct mei_aux_device *adev; 131 int ret; 132 133 adev = kzalloc(sizeof(*adev), GFP_KERNEL); 134 if (!adev) 135 return -ENOMEM; 136 adev->irq = heci_gsc->irq; 137 adev->bar.parent = &pdev->resource[0]; 138 adev->bar.start = def->bar + pdev->resource[0].start; 139 adev->bar.end = adev->bar.start + def->bar_size - 1; 140 adev->bar.flags = IORESOURCE_MEM; 141 adev->bar.desc = IORES_DESC_NONE; 142 adev->slow_firmware = def->slow_firmware; 143 144 aux_dev = &adev->aux_dev; 145 aux_dev->name = def->name; 146 aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | 147 PCI_DEVID(pdev->bus->number, pdev->devfn); 148 aux_dev->dev.parent = &pdev->dev; 149 aux_dev->dev.release = heci_gsc_release_dev; 150 151 ret = auxiliary_device_init(aux_dev); 152 if (ret < 0) { 153 drm_err(&xe->drm, "gsc aux init failed %d\n", ret); 154 kfree(adev); 155 return ret; 156 } 157 158 heci_gsc->adev = adev; /* needed by the notifier */ 159 ret = auxiliary_device_add(aux_dev); 160 if (ret < 0) { 161 drm_err(&xe->drm, "gsc aux add failed %d\n", ret); 162 heci_gsc->adev = NULL; 163 164 /* adev will be freed with the put_device() and .release sequence */ 165 auxiliary_device_uninit(aux_dev); 166 } 167 return ret; 168 } 169 170 int xe_heci_gsc_init(struct xe_device *xe) 171 { 172 struct xe_heci_gsc *heci_gsc = &xe->heci_gsc; 173 const struct heci_gsc_def *def = NULL; 174 int ret; 175 176 if (!xe->info.has_heci_gscfi && !xe->info.has_heci_cscfi) 177 return 0; 178 179 heci_gsc->irq = -1; 180 181 if (xe->info.platform == XE_BATTLEMAGE) { 182 def = &heci_gsc_def_dg2; 183 } else if (xe->info.platform == XE_PVC) { 184 def = &heci_gsc_def_pvc; 185 } else if (xe->info.platform == XE_DG2) { 186 def = &heci_gsc_def_dg2; 187 } else if (xe->info.platform == XE_DG1) { 188 def = &heci_gsc_def_dg1; 189 } 190 191 if (!def || !def->name) { 192 drm_warn(&xe->drm, "HECI is not implemented!\n"); 193 return 0; 194 } 195 196 ret = devm_add_action_or_reset(xe->drm.dev, xe_heci_gsc_fini, heci_gsc); 197 if (ret) 198 return ret; 199 200 if (!def->use_polling && !xe_survivability_mode_is_enabled(xe)) { 201 ret = heci_gsc_irq_setup(xe); 202 if (ret) 203 return ret; 204 } 205 206 return heci_gsc_add_device(xe, def); 207 } 208 209 void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir) 210 { 211 int ret; 212 213 if ((iir & GSC_IRQ_INTF(1)) == 0) 214 return; 215 216 if (!xe->info.has_heci_gscfi) { 217 drm_warn_once(&xe->drm, "GSC irq: not supported"); 218 return; 219 } 220 221 if (xe->heci_gsc.irq < 0) 222 return; 223 224 ret = generic_handle_irq(xe->heci_gsc.irq); 225 if (ret) 226 drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); 227 } 228 229 void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir) 230 { 231 int ret; 232 233 if ((iir & CSC_IRQ_INTF(1)) == 0) 234 return; 235 236 if (!xe->info.has_heci_cscfi) { 237 drm_warn_once(&xe->drm, "CSC irq: not supported"); 238 return; 239 } 240 241 if (xe->heci_gsc.irq < 0) 242 return; 243 244 ret = generic_handle_irq(xe->heci_gsc.irq); 245 if (ret) 246 drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); 247 } 248