From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pd0-f177.google.com (mail-pd0-f177.google.com [209.85.192.177]) by dpdk.org (Postfix) with ESMTP id F2D91C320 for ; Mon, 20 Jul 2015 18:33:14 +0200 (CEST) Received: by pdrg1 with SMTP id g1so103998764pdr.2 for ; Mon, 20 Jul 2015 09:33:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=cOYCaLQP2Ctk2SUj9Bce0vS3zytqw5akagvApbqsKPg=; b=j7CHWgWl0Mw1tYF/XihNcsuXR7dYYI+BbA40q/bUcFCS42mrZe6Zy7FeFeWT8jdraX mpCJ3E8XW2kmeLwoNATwvfR9zLoXGC08OxaXwNEIYKvAbQnzttEYbTqMxn9fKj4xHAlT BE+Ur6E1EPJuOtAiJ7Uk2dUwIdweMSkTTUvtL5w5txCHwRcLpYQVXSDtXfFiUYezx0oj uFcRYQSdLqu71GRZIloE7vjMwbkYQ+1Tlh/Dujt6HcAg5Po2Q2dY9sKoyAwG78tTSuT+ zg2vTO4UTunenrz0uxXSzDDOxfQL1ewNshjvNdOXosDdAo4TuG93CM0TZPNR2TM38ADe 9uEw== X-Gm-Message-State: ALoCoQnAyxlzRIFUyXoJKhOXFfxSxuKxleBzkNESwJE8fxQUzddJ46/vBwg+t+Z+rH2UOau40iid X-Received: by 10.66.62.163 with SMTP id z3mr61311016par.12.1437409994181; Mon, 20 Jul 2015 09:33:14 -0700 (PDT) Received: from urahara.home.lan (static-50-53-82-155.bvtn.or.frontiernet.net. [50.53.82.155]) by smtp.gmail.com with ESMTPSA id dx4sm7323856pab.6.2015.07.20.09.33.11 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 20 Jul 2015 09:33:13 -0700 (PDT) From: Stephen Hemminger To: harish.patil@qlogic.com Date: Mon, 20 Jul 2015 09:33:17 -0700 Message-Id: <1437410000-15907-2-git-send-email-stephen@networkplumber.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1437410000-15907-1-git-send-email-stephen@networkplumber.org> References: <1437410000-15907-1-git-send-email-stephen@networkplumber.org> Cc: dev@dpdk.org Subject: [dpdk-dev] [PATCH v5 1/4] eal: provide functions to access PCI config X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Jul 2015 16:33:15 -0000 Some drivers need ability to access PCI config (for example for power management). This adds an abstraction to do this for both Linux and BSD. Signed-off-by: Stephen Hemminger --- lib/librte_eal/bsdapp/eal/eal_pci.c | 83 +++++++++++++++++++++++++ lib/librte_eal/bsdapp/eal/rte_eal_version.map | 3 +- lib/librte_eal/common/include/rte_pci.h | 32 ++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 50 +++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci_init.h | 11 ++++ lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 14 +++++ lib/librte_eal/linuxapp/eal/eal_pci_vfio.c | 16 +++++ lib/librte_eal/linuxapp/eal/rte_eal_version.map | 3 +- 8 files changed, 210 insertions(+), 2 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index ed31222..61ae429 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -397,6 +397,89 @@ error: return -1; } +/* Read PCI config space. */ +int rte_eal_pci_read_config(const struct rte_pci_device *dev, + void *buf, size_t len, off_t offset) +{ + int fd = -1; + struct pci_io pi = { + .pi_sel = { + .pc_domain = dev->addr.domain, + .pc_bus = dev->addr.bus, + .pc_dev = dev->addr.devid, + .pc_func = dev->addr.function, + }, + .pi_reg = offset, + .pi_width = len, + }; + + if (len == 3 || len > sizeof(pi.pi_data)) { + RTE_LOG(ERR, EAL, "%s(): invalid pci read length\n", __func__); + goto error; + } + + fd = open("/dev/pci", O_RDONLY); + if (fd < 0) { + RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); + goto error; + } + + if (ioctl(fd, PCIOCREAD, &pi) < 0) + goto error; + close(fd); + + memcpy(buf, &pi.pi_data, len); + return 0; + + error: + if (fd >= 0) + close(fd); + return -1; +} + +/* Write PCI config space. */ +int rte_eal_pci_write_config(const struct rte_pci_device *dev, + const void *buf, size_t len, off_t offset) +{ + int fd = -1; + + struct pci_io pi = { + .pi_sel = { + .pc_domain = dev->addr.domain, + .pc_bus = dev->addr.bus, + .pc_dev = dev->addr.devid, + .pc_func = dev->addr.function, + }, + .pi_reg = offset, + .pi_data = *(u_int32_t *)buf, + .pi_width = len, + }; + + if (len == 3 || len > sizeof(pi.pi_data)) { + RTE_LOG(ERR, EAL, "%s(): invalid pci read length\n", __func__); + goto error; + } + + memcpy(pi.pi_data, buf, len); + + fd = open("/dev/pci", O_RDONLY); + if (fd < 0) { + RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); + goto error; + } + + if (ioctl(fd, PCIOCWRITE, &pi) < 0) + goto error; + + close(fd); + return 0; + + error: + if (fd >= 0) + close(fd); + return -1; +} + /* Init the PCI EAL subsystem */ int rte_eal_pci_init(void) diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index b2d4441..47323ae 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -117,5 +117,6 @@ DPDK_2.1 { rte_eal_pci_detach; rte_memzone_free; - + rte_eal_pci_read_config; + rte_eal_pci_write_config; } DPDK_2.0; diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index e3ca3fc..34cafa6 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -455,6 +455,38 @@ void rte_eal_pci_register(struct rte_pci_driver *driver); */ 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 len + * The length of the data buffer. + * @param offset + * The offset into PCI config space + */ +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 len + * The length of the data buffer. + * @param offset + * The offset into PCI config space + */ +int rte_eal_pci_write_config(const struct rte_pci_device *device, + const void *buf, size_t len, off_t offset); + #ifdef __cplusplus } #endif diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index 9a28ede..6e45aac 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -572,6 +572,56 @@ pci_config_space_set(struct rte_pci_device *dev) } #endif +/* Read PCI config space. */ +int rte_eal_pci_read_config(const struct rte_pci_device *device, + void *buf, size_t len, off_t offset) +{ + const struct rte_intr_handle *intr_handle = &device->intr_handle; + + switch (intr_handle->type) { + case RTE_INTR_HANDLE_UIO: + case RTE_INTR_HANDLE_UIO_INTX: + return pci_uio_read_config(intr_handle, buf, len, offset); + +#ifdef VFIO_PRESENT + case RTE_INTR_HANDLE_VFIO_MSIX: + case RTE_INTR_HANDLE_VFIO_MSI: + case RTE_INTR_HANDLE_VFIO_LEGACY: + return pci_vfio_read_config(intr_handle, buf, len, offset); +#endif + default: + RTE_LOG(ERR, EAL, + "Unknown handle type of fd %d\n", + intr_handle->fd); + return -1; + } +} + +/* 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) +{ + const struct rte_intr_handle *intr_handle = &device->intr_handle; + + switch (intr_handle->type) { + case RTE_INTR_HANDLE_UIO: + case RTE_INTR_HANDLE_UIO_INTX: + return pci_uio_write_config(intr_handle, buf, len, offset); + +#ifdef VFIO_PRESENT + case RTE_INTR_HANDLE_VFIO_MSIX: + case RTE_INTR_HANDLE_VFIO_MSI: + case RTE_INTR_HANDLE_VFIO_LEGACY: + return pci_vfio_write_config(intr_handle, buf, len, offset); +#endif + default: + RTE_LOG(ERR, EAL, + "Unknown handle type of fd %d\n", + intr_handle->fd); + return -1; + } +} + /* Init the PCI EAL subsystem */ int rte_eal_pci_init(void) diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h index 7104b13..a17c708 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h +++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h @@ -49,6 +49,11 @@ void pci_uio_free_resource(struct rte_pci_device *dev, int pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx, struct mapped_pci_resource *uio_res, int map_idx); +int pci_uio_read_config(const struct rte_intr_handle *intr_handle, + void *buf, size_t len, off_t offs); +int pci_uio_write_config(const struct rte_intr_handle *intr_handle, + const void *buf, size_t len, off_t offs); + #ifdef VFIO_PRESENT #define VFIO_MAX_GROUPS 64 @@ -57,6 +62,12 @@ int pci_vfio_enable(void); int pci_vfio_is_enabled(void); int pci_vfio_mp_sync_setup(void); +/* access config space */ +int pci_vfio_read_config(const struct rte_intr_handle *intr_handle, + void *buf, size_t len, off_t offs); +int pci_vfio_write_config(const struct rte_intr_handle *intr_handle, + const void *buf, size_t len, off_t offs); + /* map VFIO resource prototype */ int pci_vfio_map_resource(struct rte_pci_device *dev); int pci_vfio_get_group_fd(int iommu_group_fd); diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c index c35feb4..fca7987 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c @@ -53,6 +53,20 @@ void *pci_map_addr = NULL; #define OFF_MAX ((uint64_t)(off_t)-1) +int +pci_uio_read_config(const struct rte_intr_handle *intr_handle, + void *buf, size_t len, off_t offset) +{ + return pread(intr_handle->uio_cfg_fd, buf, len, offset); +} + +int +pci_uio_write_config(const struct rte_intr_handle *intr_handle, + const void *buf, size_t len, off_t offset) +{ + return pwrite(intr_handle->uio_cfg_fd, buf, len, offset); +} + static int pci_uio_set_bus_master(int dev_fd) { diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c index cf5ac50..0e6c48a 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c @@ -77,6 +77,22 @@ EAL_REGISTER_TAILQ(rte_vfio_tailq) /* per-process VFIO config */ static struct vfio_config vfio_cfg; +int +pci_vfio_read_config(const struct rte_intr_handle *intr_handle, + void *buf, size_t len, off_t offs) +{ + return pread64(intr_handle->vfio_dev_fd, buf, len, + VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs); +} + +int +pci_vfio_write_config(const struct rte_intr_handle *intr_handle, + const void *buf, size_t len, off_t offs) +{ + return pwrite64(intr_handle->vfio_dev_fd, buf, len, + VFIO_GET_REGION_ADDR(VFIO_PCI_CONFIG_REGION_INDEX) + offs); +} + /* get PCI BAR number where MSI-X interrupts are */ static int pci_vfio_get_msix_bar(int fd, int *msix_bar, uint32_t *msix_table_offset, diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index b2d4441..47323ae 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -117,5 +117,6 @@ DPDK_2.1 { rte_eal_pci_detach; rte_memzone_free; - + rte_eal_pci_read_config; + rte_eal_pci_write_config; } DPDK_2.0; -- 2.1.4