1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include "xe_survivability_mode.h" 7 #include "xe_survivability_mode_types.h" 8 9 #include <linux/kobject.h> 10 #include <linux/pci.h> 11 #include <linux/sysfs.h> 12 13 #include "xe_configfs.h" 14 #include "xe_device.h" 15 #include "xe_heci_gsc.h" 16 #include "xe_i2c.h" 17 #include "xe_mmio.h" 18 #include "xe_nvm.h" 19 #include "xe_pcode_api.h" 20 #include "xe_vsec.h" 21 22 /** 23 * DOC: Survivability Mode 24 * 25 * Survivability Mode is a software based workflow for recovering a system in a failed boot state 26 * Here system recoverability is concerned with recovering the firmware responsible for boot. 27 * 28 * Boot Survivability 29 * =================== 30 * 31 * Boot Survivability is implemented by loading the driver with bare minimum (no drm card) to allow 32 * the firmware to be flashed through mei driver and collect telemetry. The driver's probe flow is 33 * modified such that it enters survivability mode when pcode initialization is incomplete and boot 34 * status denotes a failure. 35 * 36 * Survivability mode can also be entered manually using the survivability mode attribute available 37 * through configfs which is beneficial in several usecases. It can be used to address scenarios 38 * where pcode does not detect failure or for validation purposes. It can also be used in 39 * In-Field-Repair (IFR) to repair a single card without impacting the other cards in a node. 40 * 41 * Use below command enable survivability mode manually:: 42 * 43 * # echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode 44 * 45 * It is the responsibility of the user to clear the mode once firmware flash is complete. 46 * 47 * Refer :ref:`xe_configfs` for more details on how to use configfs 48 * 49 * Survivability mode is indicated by the below admin-only readable sysfs entry. It 50 * provides information about the type of survivability mode (Boot/Runtime). 51 * 52 * .. code-block:: shell 53 * 54 * # cat /sys/bus/pci/devices/<device>/survivability_mode 55 * Boot 56 * 57 * Any additional debug information if present will be visible under the directory 58 * ``survivability_info``:: 59 * 60 * /sys/bus/pci/devices/<device>/survivability_info/ 61 * ├── aux_info0 62 * ├── aux_info1 63 * ├── aux_info2 64 * ├── aux_info3 65 * ├── aux_info4 66 * ├── capability_info 67 * ├── fdo_mode 68 * ├── postcode_trace 69 * └── postcode_trace_overflow 70 * 71 * This directory has the following attributes 72 * 73 * - ``capability_info`` : Indicates Boot status and support for additional information 74 * 75 * - ``postcode_trace``, ``postcode_trace_overflow`` : Each postcode is a 8bit value and 76 * represents a boot failure event. When a new failure event is logged by PCODE the 77 * existing postcodes are shifted left. These entries provide a history of 8 postcodes. 78 * 79 * - ``aux_info<n>`` : Some failures have additional debug information 80 * 81 * - ``fdo_mode`` : To allow recovery in scenarios where MEI itself fails, a new SPI Flash 82 * Descriptor Override (FDO) mode is added in v2 survivability breadcrumbs. This mode is enabled 83 * by PCODE and provides the ability to directly update the firmware via SPI Driver without 84 * any dependency on MEI. Xe KMD initializes the nvm aux driver if FDO mode is enabled. 85 * 86 * Runtime Survivability 87 * ===================== 88 * 89 * Certain runtime firmware errors can cause the device to enter a wedged state 90 * (:ref:`xe-device-wedging`) requiring a firmware flash to restore normal operation. 91 * Runtime Survivability Mode indicates that a firmware flash is necessary to recover the device and 92 * is indicated by the presence of survivability mode sysfs. 93 * Survivability mode sysfs provides information about the type of survivability mode. 94 * 95 * .. code-block:: shell 96 * 97 * # cat /sys/bus/pci/devices/<device>/survivability_mode 98 * Runtime 99 * 100 * On some CSC firmware errors, PCODE sets FDO mode and the only recovery possible is through 101 * firmware flash using SPI driver. Userspace can check if FDO mode is set by checking the below 102 * sysfs entry. 103 * 104 * .. code-block:: shell 105 * 106 * # cat /sys/bus/pci/devices/<device>/survivability_info/fdo_mode 107 * enabled 108 * 109 * When such errors occur, userspace is notified with the drm device wedged uevent and runtime 110 * survivability mode. User can then initiate a firmware flash using userspace tools like fwupd 111 * to restore device to normal operation. 112 */ 113 114 static const char * const reg_map[] = { 115 [CAPABILITY_INFO] = "Capability Info", 116 [POSTCODE_TRACE] = "Postcode trace", 117 [POSTCODE_TRACE_OVERFLOW] = "Postcode trace overflow", 118 [AUX_INFO0] = "Auxiliary Info 0", 119 [AUX_INFO1] = "Auxiliary Info 1", 120 [AUX_INFO2] = "Auxiliary Info 2", 121 [AUX_INFO3] = "Auxiliary Info 3", 122 [AUX_INFO4] = "Auxiliary Info 4", 123 }; 124 125 #define FDO_INFO (MAX_SCRATCH_REG + 1) 126 127 struct xe_survivability_attribute { 128 struct device_attribute attr; 129 u8 index; 130 }; 131 132 static struct 133 xe_survivability_attribute *dev_attr_to_survivability_attr(struct device_attribute *attr) 134 { 135 return container_of(attr, struct xe_survivability_attribute, attr); 136 } 137 138 static void set_survivability_info(struct xe_mmio *mmio, u32 *info, int id) 139 { 140 info[id] = xe_mmio_read32(mmio, PCODE_SCRATCH(id)); 141 } 142 143 static void populate_survivability_info(struct xe_device *xe) 144 { 145 struct xe_survivability *survivability = &xe->survivability; 146 u32 *info = survivability->info; 147 struct xe_mmio *mmio; 148 u32 id = 0, reg_value; 149 150 mmio = xe_root_tile_mmio(xe); 151 set_survivability_info(mmio, info, CAPABILITY_INFO); 152 reg_value = info[CAPABILITY_INFO]; 153 154 survivability->version = REG_FIELD_GET(BREADCRUMB_VERSION, reg_value); 155 /* FDO mode is exposed only from version 2 */ 156 if (survivability->version >= 2) 157 survivability->fdo_mode = REG_FIELD_GET(FDO_MODE, reg_value); 158 159 if (reg_value & HISTORY_TRACKING) { 160 set_survivability_info(mmio, info, POSTCODE_TRACE); 161 162 if (reg_value & OVERFLOW_SUPPORT) 163 set_survivability_info(mmio, info, POSTCODE_TRACE_OVERFLOW); 164 } 165 166 /* Traverse the linked list of aux info registers */ 167 if (reg_value & AUXINFO_SUPPORT) { 168 for (id = REG_FIELD_GET(AUXINFO_REG_OFFSET, reg_value); 169 id >= AUX_INFO0 && id < MAX_SCRATCH_REG; 170 id = REG_FIELD_GET(AUXINFO_HISTORY_OFFSET, info[id])) 171 set_survivability_info(mmio, info, id); 172 } 173 } 174 175 static void log_survivability_info(struct pci_dev *pdev) 176 { 177 struct xe_device *xe = pdev_to_xe_device(pdev); 178 struct xe_survivability *survivability = &xe->survivability; 179 u32 *info = survivability->info; 180 int id; 181 182 dev_info(&pdev->dev, "Survivability Boot Status : Critical Failure (%d)\n", 183 survivability->boot_status); 184 for (id = 0; id < MAX_SCRATCH_REG; id++) { 185 if (info[id]) 186 dev_info(&pdev->dev, "%s: 0x%x\n", reg_map[id], info[id]); 187 } 188 } 189 190 static int check_boot_failure(struct xe_device *xe) 191 { 192 struct xe_survivability *survivability = &xe->survivability; 193 194 return survivability->boot_status == NON_CRITICAL_FAILURE || 195 survivability->boot_status == CRITICAL_FAILURE; 196 } 197 198 static ssize_t survivability_mode_show(struct device *dev, 199 struct device_attribute *attr, char *buff) 200 { 201 struct pci_dev *pdev = to_pci_dev(dev); 202 struct xe_device *xe = pdev_to_xe_device(pdev); 203 struct xe_survivability *survivability = &xe->survivability; 204 205 return sysfs_emit(buff, "%s\n", survivability->type ? "Runtime" : "Boot"); 206 } 207 208 static DEVICE_ATTR_ADMIN_RO(survivability_mode); 209 210 static ssize_t survivability_info_show(struct device *dev, 211 struct device_attribute *attr, char *buff) 212 { 213 struct xe_survivability_attribute *sa = dev_attr_to_survivability_attr(attr); 214 struct pci_dev *pdev = to_pci_dev(dev); 215 struct xe_device *xe = pdev_to_xe_device(pdev); 216 struct xe_survivability *survivability = &xe->survivability; 217 u32 *info = survivability->info; 218 219 if (sa->index == FDO_INFO) 220 return sysfs_emit(buff, "%s\n", str_enabled_disabled(survivability->fdo_mode)); 221 222 return sysfs_emit(buff, "0x%x\n", info[sa->index]); 223 } 224 225 #define SURVIVABILITY_ATTR_RO(name, _index) \ 226 struct xe_survivability_attribute attr_##name = { \ 227 .attr = __ATTR(name, 0400, survivability_info_show, NULL), \ 228 .index = _index, \ 229 } 230 231 static SURVIVABILITY_ATTR_RO(capability_info, CAPABILITY_INFO); 232 static SURVIVABILITY_ATTR_RO(postcode_trace, POSTCODE_TRACE); 233 static SURVIVABILITY_ATTR_RO(postcode_trace_overflow, POSTCODE_TRACE_OVERFLOW); 234 static SURVIVABILITY_ATTR_RO(aux_info0, AUX_INFO0); 235 static SURVIVABILITY_ATTR_RO(aux_info1, AUX_INFO1); 236 static SURVIVABILITY_ATTR_RO(aux_info2, AUX_INFO2); 237 static SURVIVABILITY_ATTR_RO(aux_info3, AUX_INFO3); 238 static SURVIVABILITY_ATTR_RO(aux_info4, AUX_INFO4); 239 static SURVIVABILITY_ATTR_RO(fdo_mode, FDO_INFO); 240 241 static void xe_survivability_mode_fini(void *arg) 242 { 243 struct xe_device *xe = arg; 244 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 245 struct device *dev = &pdev->dev; 246 247 device_remove_file(dev, &dev_attr_survivability_mode); 248 } 249 250 static umode_t survivability_info_attrs_visible(struct kobject *kobj, struct attribute *attr, 251 int idx) 252 { 253 struct xe_device *xe = kdev_to_xe_device(kobj_to_dev(kobj)); 254 struct xe_survivability *survivability = &xe->survivability; 255 u32 *info = survivability->info; 256 257 /* 258 * Last index in survivability_info_attrs is fdo mode and is applicable only in 259 * version 2 of survivability mode 260 */ 261 if (idx == MAX_SCRATCH_REG && survivability->version >= 2) 262 return 0400; 263 264 if (idx < MAX_SCRATCH_REG && info[idx]) 265 return 0400; 266 267 return 0; 268 } 269 270 /* Attributes are ordered according to enum scratch_reg */ 271 static struct attribute *survivability_info_attrs[] = { 272 &attr_capability_info.attr.attr, 273 &attr_postcode_trace.attr.attr, 274 &attr_postcode_trace_overflow.attr.attr, 275 &attr_aux_info0.attr.attr, 276 &attr_aux_info1.attr.attr, 277 &attr_aux_info2.attr.attr, 278 &attr_aux_info3.attr.attr, 279 &attr_aux_info4.attr.attr, 280 &attr_fdo_mode.attr.attr, 281 NULL, 282 }; 283 284 static const struct attribute_group survivability_info_group = { 285 .name = "survivability_info", 286 .attrs = survivability_info_attrs, 287 .is_visible = survivability_info_attrs_visible, 288 }; 289 290 static int create_survivability_sysfs(struct pci_dev *pdev) 291 { 292 struct device *dev = &pdev->dev; 293 struct xe_device *xe = pdev_to_xe_device(pdev); 294 int ret; 295 296 ret = device_create_file(dev, &dev_attr_survivability_mode); 297 if (ret) { 298 dev_warn(dev, "Failed to create survivability sysfs files\n"); 299 return ret; 300 } 301 302 ret = devm_add_action_or_reset(xe->drm.dev, 303 xe_survivability_mode_fini, xe); 304 if (ret) 305 return ret; 306 307 /* Survivability info is not required if enabled via configfs */ 308 if (!xe_configfs_get_survivability_mode(pdev)) { 309 ret = devm_device_add_group(dev, &survivability_info_group); 310 if (ret) 311 return ret; 312 } 313 314 return 0; 315 } 316 317 static int enable_boot_survivability_mode(struct pci_dev *pdev) 318 { 319 struct device *dev = &pdev->dev; 320 struct xe_device *xe = pdev_to_xe_device(pdev); 321 struct xe_survivability *survivability = &xe->survivability; 322 int ret = 0; 323 324 ret = create_survivability_sysfs(pdev); 325 if (ret) 326 return ret; 327 328 /* Make sure xe_heci_gsc_init() and xe_i2c_probe() are aware of survivability */ 329 survivability->mode = true; 330 331 xe_heci_gsc_init(xe); 332 333 xe_vsec_init(xe); 334 335 if (survivability->fdo_mode) { 336 ret = xe_nvm_init(xe); 337 if (ret) 338 goto err; 339 } 340 341 ret = xe_i2c_probe(xe); 342 if (ret) 343 goto err; 344 345 dev_err(dev, "In Survivability Mode\n"); 346 347 return 0; 348 349 err: 350 dev_err(dev, "Failed to enable Survivability Mode\n"); 351 survivability->mode = false; 352 return ret; 353 } 354 355 /** 356 * xe_survivability_mode_is_boot_enabled- check if boot survivability mode is enabled 357 * @xe: xe device instance 358 * 359 * Returns true if in boot survivability mode of type, else false 360 */ 361 bool xe_survivability_mode_is_boot_enabled(struct xe_device *xe) 362 { 363 struct xe_survivability *survivability = &xe->survivability; 364 365 return survivability->mode && survivability->type == XE_SURVIVABILITY_TYPE_BOOT; 366 } 367 368 /** 369 * xe_survivability_mode_is_requested - check if it's possible to enable survivability 370 * mode that was requested by firmware or userspace 371 * @xe: xe device instance 372 * 373 * This function reads configfs and boot status from Pcode. 374 * 375 * Return: true if platform support is available and boot status indicates 376 * failure or if survivability mode is requested, false otherwise. 377 */ 378 bool xe_survivability_mode_is_requested(struct xe_device *xe) 379 { 380 struct xe_survivability *survivability = &xe->survivability; 381 struct xe_mmio *mmio = xe_root_tile_mmio(xe); 382 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 383 u32 data; 384 bool survivability_mode; 385 386 if (!IS_DGFX(xe) || IS_SRIOV_VF(xe) || xe->info.platform < XE_BATTLEMAGE) 387 return false; 388 389 survivability_mode = xe_configfs_get_survivability_mode(pdev); 390 /* Enable survivability mode if set via configfs */ 391 if (survivability_mode) 392 return true; 393 394 data = xe_mmio_read32(mmio, PCODE_SCRATCH(0)); 395 survivability->boot_status = REG_FIELD_GET(BOOT_STATUS, data); 396 397 return check_boot_failure(xe); 398 } 399 400 /** 401 * xe_survivability_mode_runtime_enable - Initialize and enable runtime survivability mode 402 * @xe: xe device instance 403 * 404 * Initialize survivability information and enable runtime survivability mode. 405 * Runtime survivability mode is enabled when certain errors cause the device to be 406 * in non-recoverable state. The device is declared wedged with the appropriate 407 * recovery method and survivability mode sysfs exposed to userspace 408 */ 409 void xe_survivability_mode_runtime_enable(struct xe_device *xe) 410 { 411 struct xe_survivability *survivability = &xe->survivability; 412 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 413 414 if (!IS_DGFX(xe) || IS_SRIOV_VF(xe) || xe->info.platform < XE_BATTLEMAGE) { 415 dev_err(&pdev->dev, "Runtime Survivability Mode not supported\n"); 416 return; 417 } 418 419 populate_survivability_info(xe); 420 421 if (create_survivability_sysfs(pdev)) 422 dev_err(&pdev->dev, "Failed to create survivability sysfs\n"); 423 424 survivability->type = XE_SURVIVABILITY_TYPE_RUNTIME; 425 dev_err(&pdev->dev, "Runtime Survivability mode enabled\n"); 426 427 xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_VENDOR); 428 xe_device_declare_wedged(xe); 429 dev_err(&pdev->dev, "Firmware flash required, Please refer to the userspace documentation for more details!\n"); 430 } 431 432 /** 433 * xe_survivability_mode_boot_enable - Initialize and enable boot survivability mode 434 * @xe: xe device instance 435 * 436 * Initialize survivability information and enable boot survivability mode 437 * 438 * Return: 0 if boot survivability mode is enabled or not requested, negative error 439 * code otherwise. 440 */ 441 int xe_survivability_mode_boot_enable(struct xe_device *xe) 442 { 443 struct xe_survivability *survivability = &xe->survivability; 444 struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 445 446 if (!xe_survivability_mode_is_requested(xe)) 447 return 0; 448 449 populate_survivability_info(xe); 450 451 /* 452 * v2 supports survivability mode for critical errors 453 */ 454 if (survivability->version < 2 && survivability->boot_status == CRITICAL_FAILURE) { 455 log_survivability_info(pdev); 456 return -ENXIO; 457 } 458 459 survivability->type = XE_SURVIVABILITY_TYPE_BOOT; 460 461 return enable_boot_survivability_mode(pdev); 462 } 463