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

Configure Feed

Select the types of activity you want to include in your feed.

spi: intel: Add protected and locked attributes

The manufacturing access to the PCH/SoC SPI device is traditionally
performed via userspace driver accessing registers via /dev/mem but due
to security concerns /dev/mem access is being much restricted, hence the
reason for utilizing dedicated Intel PCH/SoC SPI controller driver,
which is already implemented in the Linux kernel.

Intel PCH/SoC SPI controller protects the flash storage via two
mechanisms one is the via region protection registers and second via
BIOS lock. The BIOS locks only the BIOS regions usually 0 and/or 6.

The device always boots with BIOS lock set, but during manufacturing the
BIOS lock has to be lifted in order to enable the write access. This can
be done by passing "writeable=1" in the command line when the driver is
loaded. This "locked" state is exposed through new sysfs attributes
(intel_spi_locked, intel_spi_bios_locked).

Second, also the region protection status is exposed via sysfs attribute
(intel_spi_protected) as the manufacturing will need the both files in
order to validate that the device is properly sealed.

Includes code written by Tamar Mashiah.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Co-developed-by: Tomas Winkler <tomasw@gmail.com>
Signed-off-by: Tomas Winkler <tomasw@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Link: https://patch.msgid.link/20241009062244.2436793-1-mika.westerberg@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Alexander Usyskin and committed by
Mark Brown
b1258105 c2a59c89

+83 -5
+20
Documentation/ABI/testing/sysfs-driver-spi-intel
··· 1 + What: /sys/devices/.../intel_spi_protected 2 + Date: Feb 2025 3 + KernelVersion: 6.13 4 + Contact: Alexander Usyskin <alexander.usyskin@intel.com> 5 + Description: This attribute allows the userspace to check if the 6 + Intel SPI flash controller is write protected from the host. 7 + 8 + What: /sys/devices/.../intel_spi_locked 9 + Date: Feb 2025 10 + KernelVersion: 6.13 11 + Contact: Alexander Usyskin <alexander.usyskin@intel.com> 12 + Description: This attribute allows the user space to check if the 13 + Intel SPI flash controller locks supported opcodes. 14 + 15 + What: /sys/devices/.../intel_spi_bios_locked 16 + Date: Feb 2025 17 + KernelVersion: 6.13 18 + Contact: Alexander Usyskin <alexander.usyskin@intel.com> 19 + Description: This attribute allows the user space to check if the 20 + Intel SPI flash controller BIOS region is locked for writes.
+1
drivers/spi/spi-intel-pci.c
··· 94 94 .name = "intel-spi", 95 95 .id_table = intel_spi_pci_ids, 96 96 .probe = intel_spi_pci_probe, 97 + .dev_groups = intel_spi_groups, 97 98 }; 98 99 99 100 module_pci_driver(intel_spi_pci_driver);
+1
drivers/spi/spi-intel-platform.c
··· 28 28 .probe = intel_spi_platform_probe, 29 29 .driver = { 30 30 .name = "intel-spi", 31 + .dev_groups = intel_spi_groups, 31 32 }, 32 33 }; 33 34
+59 -5
drivers/spi/spi-intel.c
··· 148 148 * @pr_num: Maximum number of protected range registers 149 149 * @chip0_size: Size of the first flash chip in bytes 150 150 * @locked: Is SPI setting locked 151 + * @protected: Whether the regions are write protected 152 + * @bios_locked: Is BIOS region locked 151 153 * @swseq_reg: Use SW sequencer in register reads/writes 152 154 * @swseq_erase: Use SW sequencer in erase operation 153 155 * @atomic_preopcode: Holds preopcode when atomic sequence is requested ··· 168 166 size_t pr_num; 169 167 size_t chip0_size; 170 168 bool locked; 169 + bool protected; 170 + bool bios_locked; 171 171 bool swseq_reg; 172 172 bool swseq_erase; 173 173 u8 atomic_preopcode; ··· 1113 1109 return -EINVAL; 1114 1110 } 1115 1111 1116 - /* Try to disable write protection if user asked to do so */ 1117 - if (writeable && !intel_spi_set_writeable(ispi)) { 1118 - dev_warn(ispi->dev, "can't disable chip write protection\n"); 1119 - writeable = false; 1112 + ispi->bios_locked = true; 1113 + /* Try to disable BIOS write protection if user asked to do so */ 1114 + if (writeable) { 1115 + if (intel_spi_set_writeable(ispi)) 1116 + ispi->bios_locked = false; 1117 + else 1118 + dev_warn(ispi->dev, "can't disable chip write protection\n"); 1120 1119 } 1121 1120 1122 1121 /* Disable #SMI generation from HW sequencer */ ··· 1254 1247 * Also if the user did not ask the chip to be writeable 1255 1248 * mask the bit too. 1256 1249 */ 1257 - if (!writeable || intel_spi_is_protected(ispi, base, limit)) 1250 + if (!writeable || intel_spi_is_protected(ispi, base, limit)) { 1258 1251 part->mask_flags |= MTD_WRITEABLE; 1252 + ispi->protected = true; 1253 + } 1259 1254 1260 1255 end = (limit << 12) + 4096; 1261 1256 if (end > part->size) ··· 1420 1411 return 0; 1421 1412 } 1422 1413 1414 + static ssize_t intel_spi_protected_show(struct device *dev, 1415 + struct device_attribute *attr, char *buf) 1416 + { 1417 + struct intel_spi *ispi = dev_get_drvdata(dev); 1418 + 1419 + return sysfs_emit(buf, "%d\n", ispi->protected); 1420 + } 1421 + static DEVICE_ATTR_ADMIN_RO(intel_spi_protected); 1422 + 1423 + static ssize_t intel_spi_locked_show(struct device *dev, 1424 + struct device_attribute *attr, char *buf) 1425 + { 1426 + struct intel_spi *ispi = dev_get_drvdata(dev); 1427 + 1428 + return sysfs_emit(buf, "%d\n", ispi->locked); 1429 + } 1430 + static DEVICE_ATTR_ADMIN_RO(intel_spi_locked); 1431 + 1432 + static ssize_t intel_spi_bios_locked_show(struct device *dev, 1433 + struct device_attribute *attr, char *buf) 1434 + { 1435 + struct intel_spi *ispi = dev_get_drvdata(dev); 1436 + 1437 + return sysfs_emit(buf, "%d\n", ispi->bios_locked); 1438 + } 1439 + static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked); 1440 + 1441 + static struct attribute *intel_spi_attrs[] = { 1442 + &dev_attr_intel_spi_protected.attr, 1443 + &dev_attr_intel_spi_locked.attr, 1444 + &dev_attr_intel_spi_bios_locked.attr, 1445 + NULL 1446 + }; 1447 + 1448 + static const struct attribute_group intel_spi_attr_group = { 1449 + .attrs = intel_spi_attrs, 1450 + }; 1451 + 1452 + const struct attribute_group *intel_spi_groups[] = { 1453 + &intel_spi_attr_group, 1454 + NULL 1455 + }; 1456 + EXPORT_SYMBOL_GPL(intel_spi_groups); 1457 + 1423 1458 /** 1424 1459 * intel_spi_probe() - Probe the Intel SPI flash controller 1425 1460 * @dev: Pointer to the parent device ··· 1504 1451 if (ret) 1505 1452 return ret; 1506 1453 1454 + dev_set_drvdata(dev, ispi); 1507 1455 return intel_spi_populate_chip(ispi); 1508 1456 } 1509 1457 EXPORT_SYMBOL_GPL(intel_spi_probe);
+2
drivers/spi/spi-intel.h
··· 13 13 14 14 struct resource; 15 15 16 + extern const struct attribute_group *intel_spi_groups[]; 17 + 16 18 int intel_spi_probe(struct device *dev, struct resource *mem, 17 19 const struct intel_spi_boardinfo *info); 18 20