Commit cf6ee09b authored by Matthew Wood's avatar Matthew Wood Committed by Bjorn Helgaas
Browse files

PCI/sysfs: Expose PCI device serial number



Add a single sysfs read-only interface for reading PCI device serial
numbers from userspace in a programmatic way. This device attribute uses
the same hexadecimal 1-byte dashed formatting as lspci serial number
capability output. If a device doesn't support the serial number
capability, the serial_number sysfs attribute will not be visible.

Signed-off-by: default avatarMatthew Wood <thepacketgeek@gmail.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarMario Limonciello <superm1@kernel.org>
Reviewed-by: default avatarJonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: default avatarThomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: default avatarKeith Busch <kbusch@kernel.org>
Reviewed-by: default avatarKrzysztof Wilczyński <kwilczynski@kernel.org>
Link: https://patch.msgid.link/20250917125815.722952-2-thepacketgeek@gmail.com
parent fac679df
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -612,3 +612,12 @@ Description:

		  # ls doe_features
		  0001:01        0001:02        doe_discovery

What:		/sys/bus/pci/devices/.../serial_number
Date:		December 2025
Contact:	Matthew Wood <thepacketgeek@gmail.com>
Description:
		This is visible only for PCI devices that support the serial
		number extended capability. The file is read only and due to
		the possible sensitivity of accessible serial numbers, admin
		only.
+21 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/aperture.h>
#include <linux/unaligned.h>
#include "pci.h"

#ifndef ARCH_PCI_DEV_GROUPS
@@ -694,6 +695,22 @@ static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(boot_vga);

static ssize_t serial_number_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{
	struct pci_dev *pci_dev = to_pci_dev(dev);
	u64 dsn;
	u8 bytes[8];

	dsn = pci_get_dsn(pci_dev);
	if (!dsn)
		return -EIO;

	put_unaligned_be64(dsn, bytes);
	return sysfs_emit(buf, "%8phD\n", bytes);
}
static DEVICE_ATTR_ADMIN_RO(serial_number);

static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
			       const struct bin_attribute *bin_attr, char *buf,
			       loff_t off, size_t count)
@@ -1698,6 +1715,7 @@ late_initcall(pci_sysfs_init);

static struct attribute *pci_dev_dev_attrs[] = {
	&dev_attr_boot_vga.attr,
	&dev_attr_serial_number.attr,
	NULL,
};

@@ -1710,6 +1728,9 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
	if (a == &dev_attr_boot_vga.attr && pci_is_vga(pdev))
		return a->mode;

	if (a == &dev_attr_serial_number.attr && pci_get_dsn(pdev))
		return a->mode;

	return 0;
}