lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260120130603.1066559-2-patrick@subset.ch>
Date: Tue, 20 Jan 2026 14:06:03 +0100
From: patrick@...set.ch
To: linux-kernel@...r.kernel.org
Cc: alexander.sverdlin@...mens.com,
	gregkh@...uxfoundation.org,
	arnd@...db.de,
	Patrick Wicki <patrick.wicki@...mens.com>
Subject: [PATCH 2/2] eeprom: at25: expose JEDEC ID via sysfs

From: Patrick Wicki <patrick.wicki@...mens.com>

Return the raw JEDEC ID bytes as returned by the RDID command, even for
variations that have the bytes in reverse order. This way we can avoid
ambiguity if the manufacturer ever releases a new chip that returns them
according to standard.

Signed-off-by: Patrick Wicki <patrick.wicki@...mens.com>
---
 .../ABI/testing/sysfs-class-spi-eeprom        | 11 ++++++
 drivers/misc/eeprom/at25.c                    | 38 +++++++++++++++----
 2 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-spi-eeprom b/Documentation/ABI/testing/sysfs-class-spi-eeprom
index 1ff7579820798..f4bc7d9454cfb 100644
--- a/Documentation/ABI/testing/sysfs-class-spi-eeprom
+++ b/Documentation/ABI/testing/sysfs-class-spi-eeprom
@@ -17,3 +17,14 @@ Description:
 	from the device.
 
 	This is a read-only attribute.
+
+What:		/sys/class/spi_master/spi<bus>/spi<bus>.<dev>/jedec_id
+Date:		January 2026
+KernelVersion:	6.19
+Contact:	Patrick Wicki <patrick.wicki@...mens.com>
+Description:
+	Contains the raw JEDEC ID bytes returned by the RDID (0x9f) command. The
+	bytes are exposed as a hex string in big-endian order as read from the
+	device.
+
+	This is a read-only attribute.
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 5b00921d07d2e..bc2cfb75d9bb4 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -34,6 +34,7 @@
  */
 
 #define	FM25_SN_LEN	8		/* serial number length */
+#define	FM25_MAX_ID_LEN	9		/* ID length */
 #define EE_MAXADDRLEN	3		/* 24 bit addresses, up to 2 MBytes */
 
 struct at25_data {
@@ -44,6 +45,8 @@ struct at25_data {
 	struct nvmem_config	nvmem_config;
 	struct nvmem_device	*nvmem;
 	u8 sernum[FM25_SN_LEN];
+	u8 id[FM25_MAX_ID_LEN];
+	u8 id_len;
 };
 
 #define	AT25_WREN	0x06		/* latch the write enable */
@@ -64,8 +67,6 @@ struct at25_data {
 
 #define	AT25_INSTR_BIT3	0x08		/* additional address bit in instr */
 
-#define	FM25_ID_LEN	9		/* ID length */
-
 /*
  * Specs often allow 5ms for a page write, sometimes 20ms;
  * it's important to recover from write timeouts.
@@ -180,11 +181,25 @@ static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, ch
 }
 static DEVICE_ATTR_RO(sernum);
 
-static struct attribute *sernum_attrs[] = {
+static ssize_t jedec_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct at25_data *at25;
+
+	at25 = dev_get_drvdata(dev);
+
+	if (!at25->id_len)
+		return -EOPNOTSUPP;
+
+	return sysfs_emit(buf, "%*phN\n", at25->id_len, at25->id);
+}
+static DEVICE_ATTR_RO(jedec_id);
+
+static struct attribute *at25_attrs[] = {
 	&dev_attr_sernum.attr,
+	&dev_attr_jedec_id.attr,
 	NULL,
 };
-ATTRIBUTE_GROUPS(sernum);
+ATTRIBUTE_GROUPS(at25);
 
 /*
  * Poll Read Status Register with timeout
@@ -378,7 +393,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
 {
 	struct at25_data *at25 = container_of(chip, struct at25_data, chip);
 	u8 sernum[FM25_SN_LEN];
-	u8 id[FM25_ID_LEN];
+	u8 id[FM25_MAX_ID_LEN];
 	u32 val;
 	int i;
 
@@ -388,7 +403,12 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
 		chip->byte_len = val;
 	} else {
 		/* Get ID of chip */
-		fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN);
+		fm25_aux_read(at25, id, FM25_RDID, FM25_MAX_ID_LEN);
+
+		/* Store the unprocessed ID for exposing via sysfs */
+		memcpy(at25->id, id, FM25_MAX_ID_LEN);
+		at25->id_len = FM25_MAX_ID_LEN;
+
 		/* There are inside-out FRAM variations, detect them and reverse the ID bytes */
 		if (id[6] == 0x7f && id[2] == 0xc2)
 			for (i = 0; i < ARRAY_SIZE(id) / 2; i++) {
@@ -400,6 +420,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
 			}
 
 		if (id[6] == 0xc2) {
+			at25->id_len = 9;
 			switch (id[7]) {
 			case 0x21 ... 0x26:
 				chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024;
@@ -413,6 +434,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
 				return -ENODEV;
 			}
 		} else if (id[2] == 0x82 && id[3] == 0x06) {
+			at25->id_len = 8;
 			switch (id[1]) {
 			case 0x51 ... 0x54:
 				/* CY15B102QSN ... CY15B204QSN */
@@ -424,7 +446,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
 			}
 		} else {
 			dev_err(dev, "Error: unrecognized JEDEC ID format: %*ph\n",
-				FM25_ID_LEN, id);
+				FM25_MAX_ID_LEN, id);
 			return -ENODEV;
 		}
 
@@ -549,7 +571,7 @@ static struct spi_mem_driver at25_driver = {
 		.driver = {
 			.name		= "at25",
 			.of_match_table = at25_of_match,
-			.dev_groups	= sernum_groups,
+			.dev_groups	= at25_groups,
 		},
 		.id_table	= at25_spi_ids,
 	},
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ