[PATCH 3/4] Add implementation of read_vpd() method for sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Ben Hutchings <bhutchings@xxxxxxxxxxxxxx>
---
 lib/pci.h   |    9 ++++---
 lib/sysfs.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 pcilib.man  |    4 +-
 3 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/lib/pci.h b/lib/pci.h
index c9c2c5f..452e1d8 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -72,10 +72,11 @@ struct pci_access {
   struct id_bucket *current_id_bucket;
   int id_load_failed;
   int id_cache_status;			/* 0=not read, 1=read, 2=dirty */
-  int fd;				/* proc: fd */
-  int fd_rw;				/* proc: fd opened read-write */
-  struct pci_dev *cached_dev;		/* proc: device the fd is for */
-  int fd_pos;				/* proc: current position */
+  int fd;				/* proc/sys: fd for config space */
+  int fd_rw;				/* proc/sys: fd opened read-write */
+  int fd_pos;				/* proc/sys: current position */
+  int fd_vpd;				/* sys: fd for VPD */
+  struct pci_dev *cached_dev;		/* proc/sys: device the fds are for */
 };
 
 /* Initialize PCI access */
diff --git a/lib/sysfs.c b/lib/sysfs.c
index 695f1c2..6ebabe1 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -177,30 +177,48 @@ static void sysfs_scan(struct pci_access *a)
   closedir(dir);
 }
 
+/* Intent of the sysfs_setup() caller */
+enum
+  {
+    SETUP_READ_CONFIG = 0,
+    SETUP_WRITE_CONFIG = 1,
+    SETUP_READ_VPD = 2
+  };
+
 static int
-sysfs_setup(struct pci_dev *d, int rw)
+sysfs_setup(struct pci_dev *d, int intent)
 {
   struct pci_access *a = d->access;
+  char namebuf[OBJNAMELEN];
 
-  if (a->cached_dev != d || a->fd_rw < rw)
+  if (a->cached_dev != d || intent == SETUP_WRITE_CONFIG && !a->fd_rw)
     {
-      char namebuf[OBJNAMELEN];
       if (a->fd >= 0)
 	close(a->fd);
       sysfs_obj_name(d, "config", namebuf);
-      a->fd_rw = a->writeable || rw;
+      a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
       a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
       if (a->fd < 0)
 	a->warning("Cannot open %s", namebuf);
-      a->cached_dev = d;
       a->fd_pos = 0;
     }
-  return a->fd;
+
+  if (a->cached_dev != d)
+    {
+      if (a->fd_vpd >= 0)
+	close(a->fd_vpd);
+      sysfs_obj_name(d, "vpd", namebuf);
+      a->fd_vpd = open(namebuf, O_RDONLY);
+      /* No warning on error; vpd may be absent or accessible only to root */
+    }
+
+  a->cached_dev = d;
+  return intent == SETUP_READ_VPD ? a->fd_vpd : a->fd;
 }
 
 static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
 {
-  int fd = sysfs_setup(d, 0);
+  int fd = sysfs_setup(d, SETUP_READ_CONFIG);
   int res;
 
   if (fd < 0)
@@ -218,7 +236,7 @@ static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
 
 static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
 {
-  int fd = sysfs_setup(d, 1);
+  int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
   int res;
 
   if (fd < 0)
@@ -237,6 +255,37 @@ static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
   return 1;
 }
 
+#ifdef PCI_HAVE_DO_READ
+
+/* pread() is not available and do_read() only works for a single fd, so we
+ * cannot implement read_vpd properly. */
+static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  return 0;
+}
+
+#else /* !PCI_HAVE_DO_READ */
+
+static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  int fd = sysfs_setup(d, SETUP_READ_VPD);
+  int res;
+
+  if (fd < 0)
+    return 0;
+  res = pread(fd, buf, len, pos);
+  if (res < 0)
+    {
+      d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
+      return 0;
+    }
+  else if (res != len)
+    return 0;
+  return 1;
+}
+
+#endif /* PCI_HAVE_DO_READ */
+
 static void sysfs_cleanup_dev(struct pci_dev *d)
 {
   struct pci_access *a = d->access;
@@ -260,7 +309,7 @@ struct pci_methods pm_linux_sysfs = {
   pci_generic_fill_info,
   sysfs_read,
   sysfs_write,
-  NULL,					/* read_vpd */
+  sysfs_read_vpd,
   NULL,					/* init_dev */
   sysfs_cleanup_dev
 };
diff --git a/pcilib.man b/pcilib.man
index 6cf5682..7f5ac69 100644
--- a/pcilib.man
+++ b/pcilib.man
@@ -21,8 +21,8 @@ of \fIlspci\fP).
 The
 .B /sys
 filesystem on Linux 2.6 and newer. The standard header of the config space is available
-to all users, the rest only to root. Supports extended configuration space, PCI domains
-and information on attached kernel drivers.
+to all users, the rest only to root. Supports extended configuration space, PCI domains,
+VPD (from Linux 2.6.26) and information on attached kernel drivers.
 .TP
 .B linux-proc
 The
-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux