Patchwork [-v5,4/6] PCI: add pci_serial_number_changed() for device change identification

login
register
mail settings
Submitter Yijing Wang
Date Aug. 5, 2013, 8:54 a.m.
Message ID <1375692898-27476-5-git-send-email-wangyijing@huawei.com>
Download mbox | patch
Permalink /patch/264607/
State Superseded
Headers show

Comments

Yijing Wang - Aug. 5, 2013, 8:54 a.m.
Sometimes OS do not know the physical device swap,
for instance, some device hotplug during system suspend.
Interrupt can not deliver to OS in some platform.
So we can use pci serial number capability to detect this
issue if device supports serial number.

Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Cc: Paul Bolle <pebolle@tiscali.nl>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Oliver Neukum <oneukum@suse.de>
Cc: Gu Zheng <guz.fnst@cn.fujitsu.com>
Cc: linux-pci@vger.kernel.org
---
 drivers/pci/access.c |    9 ---------
 drivers/pci/pci.c    |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/pci.h    |    8 ++++++++
 include/linux/pci.h  |    2 ++
 4 files changed, 58 insertions(+), 9 deletions(-)

Patch

diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 0069981..7f8df11 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -194,15 +194,6 @@  PCI_USER_WRITE_CONFIG(dword, u32)
 
 /* VPD access through PCI 2.2+ VPD capability */
 
-
-struct pci_vpd_pci22 {
-	struct pci_vpd base;
-	struct mutex lock;
-	u16	flag;
-	bool	busy;
-	u8	cap;
-};
-
 /*
  * Wait for last operation to complete.
  * This code has to spin since there is no other notification from the PCI
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index cfc0f7f..a6ac0c8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2077,6 +2077,54 @@  void pci_dsn_init(struct pci_dev *dev)
 }
 
 /**
+ * pci_serial_number_changed - check the device SN is changed
+ * @pdev: the PCI device
+ *
+ * check the device serial number is changed.
+ * if device does not support device serial number,
+ * return false.
+ */
+bool pci_serial_number_changed(struct pci_dev *pdev)
+{
+	struct pci_vpd *vpd;
+	u64 old_dsn, new_dsn;
+	int ret;
+
+	/* first check PCIe DSN */
+	old_dsn = pdev->sn;
+	new_dsn = pci_device_serial_number(pdev);
+
+	if (old_dsn != new_dsn)
+		return true;
+	else if (old_dsn)
+		return false;
+
+	/* PCIe DSN does not support, check VPD SN */
+	vpd = pci_vpd_serial_number_init(pdev, NULL);
+	if (!pdev->vpd && !vpd) {
+		/* VPD SN does not support */
+		return false;
+	} else if (pdev->vpd && pdev->vpd->sn && vpd) {
+		ret = strcmp(pdev->vpd->sn, vpd->sn);
+		kfree(vpd->sn);
+		kfree(container_of(vpd, struct pci_vpd_pci22, base));
+		if (!ret)
+			return false;
+		else
+			return true;
+	} else if ((pdev->vpd && pdev->vpd->sn) || (vpd && vpd->sn)) {
+		if (vpd) {
+			kfree(vpd->sn);
+			kfree(container_of(vpd, struct pci_vpd_pci22, base));
+		}
+		return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(pci_serial_number_changed);
+
+/**
  * pci_configure_ari - enable or disable ARI forwarding
  * @dev: the PCI device
  *
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index eb77124..5d1f261 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -98,6 +98,14 @@  struct pci_vpd {
 	struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
 };
 
+struct pci_vpd_pci22 {
+	struct pci_vpd base;
+	struct mutex lock;
+	u16	flag;
+	bool	busy;
+	u8	cap;
+};
+
 int pci_vpd_pci22_init(struct pci_dev *dev);
 static inline void pci_vpd_release(struct pci_dev *dev)
 {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 5c38b55..9580fa5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -996,6 +996,8 @@  ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
 ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
 int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 
+bool pci_serial_number_changed(struct pci_dev *pdev);
+
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);