[dpdk-dev,RFC] PCI config access for drivers

Message ID 20140825174429.2065320b@urahara (mailing list archive)
State RFC, archived
Headers

Commit Message

Stephen Hemminger Aug. 26, 2014, 12:44 a.m. UTC
  Some drivers need ability to access PCI config (for example for power
management). This adds an abstraction to do this; only implemented
on Linux, but should be possible on BSD.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
  

Comments

Anatoly Burakov Aug. 27, 2014, 10:37 a.m. UTC | #1
Hi Stephen,

> Some drivers need ability to access PCI config (for example for power management). This
> adds an abstraction to do this; only implemented on Linux, but should be possible on BSD.

Since VFIO has to go to PCI config space too for some things, could you please amend your patch to make VFIO use this generic API also? Currently, it uses VFIO to read and write from PCI config.

Thanks,
Anatoly
  

Patch

--- a/lib/librte_eal/common/include/rte_pci.h	2014-06-24 09:20:05.651993525 -0700
+++ b/lib/librte_eal/common/include/rte_pci.h	2014-06-24 09:25:42.150616572 -0700
@@ -151,6 +151,7 @@  struct rte_pci_device {
 	const struct rte_pci_driver *driver;    /**< Associated driver */
 	uint16_t max_vfs;                       /**< sriov enable if not zero */
 	int numa_node;                          /**< NUMA node connection */
+	int config_fd;				/**< PCI config access */
 	struct rte_devargs *devargs;            /**< Device user arguments */
 };
 
@@ -298,6 +299,34 @@  void rte_eal_pci_register(struct rte_pci
  */
 void rte_eal_pci_unregister(struct rte_pci_driver *driver);
 
+/**
+ * Read PCI config space.
+ *
+ * @param device
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ * @param buf
+ *   A data buffer where the bytes should be read into
+ * @param size
+ *   The length of the data buffer.
+ */
+int rte_eal_pci_read_config(const struct rte_pci_device *device,
+			    void *buf, size_t len, off_t offset);
+
+/**
+ * Write PCI config space.
+ *
+ * @param device
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ * @param buf
+ *   A data buffer containing the bytes should be written
+ * @param size
+ *   The length of the data buffer.
+ */
+int rte_eal_pci_write_config(const struct rte_pci_device *device,
+			     const void *buf, size_t len, off_t offset);
+
 #ifdef __cplusplus
 }
 #endif
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c	2014-06-24 09:20:05.651993525 -0700
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c	2014-06-24 09:20:05.651993525 -0700
@@ -219,6 +219,7 @@  pci_scan_one(const char *dirname, uint16
 	dev->addr.bus = bus;
 	dev->addr.devid = devid;
 	dev->addr.function = function;
+	dev->config_fd = -1;
 
 	/* get vendor id */
 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
@@ -578,6 +579,20 @@  rte_eal_pci_probe_one_driver(struct rte_
 	return 1;
 }
 
+/* Read PCI config space. */
+int rte_eal_pci_read_config(const struct rte_pci_device *device,
+			    void *buf, size_t len, off_t offset)
+{
+	return pread(device->config_fd, buf, len, offset);
+}
+
+/* Write PCI config space. */
+int rte_eal_pci_write_config(const struct rte_pci_device *device,
+			     const void *buf, size_t len, off_t offset)
+{
+	return pwrite(device->config_fd, buf, len, offset);
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c	2014-06-24 08:35:31.832146544 -0700
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c	2014-06-24 09:37:44.892296443 -0700
@@ -280,6 +280,7 @@  pci_uio_map_resource(struct rte_pci_devi
 	int i, j;
 	char dirname[PATH_MAX];
 	char devname[PATH_MAX]; /* contains the /dev/uioX */
+	char cfgname[PATH_MAX];
 	void *mapaddr;
 	int uio_num;
 	uint64_t phaddr;
@@ -326,11 +327,23 @@  pci_uio_map_resource(struct rte_pci_devi
 	snprintf(uio_res->path, sizeof(uio_res->path), "%s", devname);
 	memcpy(&uio_res->pci_addr, &dev->addr, sizeof(uio_res->pci_addr));
 
+	/* Open fd for access to PCI config */
+	snprintf(cfgname, sizeof(cfgname),
+		 "%s/device/config", dirname);
+	dev->config_fd = open(cfgname, O_RDWR);
+	if (dev->config_fd < 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot open %s: %s\n",
+			__func__, cfgname, strerror(errno));
+		rte_free(uio_res);
+		return -1;
+	}
+
 	/* collect info about device mappings */
 	nb_maps = pci_uio_get_mappings(dirname, uio_res->maps,
 				       RTE_DIM(uio_res->maps));
 	if (nb_maps < 0) {
 		rte_free(uio_res);
+		close(dev->config_fd);
 		return nb_maps;
 	}
 
@@ -379,6 +392,7 @@  pci_uio_map_resource(struct rte_pci_devi
 
 			if (fail) {
 				rte_free(uio_res);
+				close(dev->config_fd);
 				close(fd);
 				return -1;
 			}