From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pa0-f48.google.com (mail-pa0-f48.google.com [209.85.220.48]) by dpdk.org (Postfix) with ESMTP id 93A5CC664 for ; Tue, 28 Apr 2015 18:36:39 +0200 (CEST) Received: by pabtp1 with SMTP id tp1so303017pab.2 for ; Tue, 28 Apr 2015 09:36:39 -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=cOetdsmkmeYqY79yKULVKJtOYP/P7BBQaA8Til8yPJc=; b=XKvFY5MXJsbn5h27JqknAY43t5mxTdmsfYEvkR4ljKMQnlLvwZcYsHGnIvBOWlXUtl fll6bqhZ2/1WpQu6HQLxSUHbTYlR/pYSlfefswXN3VVgWnLbVFwdXxDKDV2UsqkoerZz JgP8BMOSQ08jozcGasWNLZofS13ft6oVVzPoJTRj9HJOiIg5gZNT+2i0AizG6X/8hjrd NDi4/nkyWXAxrUt7bmN0cxUmeVlPAYUyQhDrZfcobmPAWu+UedVu58WqR4XNjDnOQ9h8 oyxnE8tXScFgTz67xsHwRaSB+yd0FfD5N/gF5FUt/wzRpDyLimlCIoN96j/3/UHRI/9C vK4Q== X-Gm-Message-State: ALoCoQm+GYWGU9bJYuWKfb9Y0KT5XxaBdv5TnKEyiPsctMBSPrBJoOkG27ZNxr0mY3cW9anbp9Hf X-Received: by 10.68.68.208 with SMTP id y16mr33468727pbt.34.1430238998940; Tue, 28 Apr 2015 09:36:38 -0700 (PDT) Received: from urahara.home.lan (static-50-53-82-155.bvtn.or.frontiernet.net. [50.53.82.155]) by mx.google.com with ESMTPSA id yc2sm22833392pbb.87.2015.04.28.09.36.38 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 28 Apr 2015 09:36:38 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Date: Tue, 28 Apr 2015 09:36:39 -0700 Message-Id: <1430239000-30881-3-git-send-email-stephen@networkplumber.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1430239000-30881-1-git-send-email-stephen@networkplumber.org> References: <1430239000-30881-1-git-send-email-stephen@networkplumber.org> Subject: [dpdk-dev] [PATCH 2/3] pci: add ability to read/write config space 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: Tue, 28 Apr 2015 16:36:40 -0000 Add new ability to read/write PCI registers in device. This is needed by BNX2X driver and is generally useful for other code. The BSD code has not been tested but is included to show how the feature is cross-platform. Signed-off-by: Stephen Hemminger --- lib/librte_eal/bsdapp/eal/eal_pci.c | 76 ++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_pci.h | 29 ++++++++++++ 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 +++++++ 6 files changed, 196 insertions(+) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 30f0232..b104e5f 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -490,6 +490,82 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d 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) +{ + struct pci_io io = { + .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 == 0 || len > sizeof(io.pi_data)) { + RTE_LOG(ERR, EAL, "%s(): invalid register length\n", __func__); + return -1; + } + + fd = open("/dev/pci", O_RDONLY); + if (fd < 0) { + RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); + return -1; + } + + if (ioctl(fd, PCIOCREAD, &io) < 0) { + RTE_LOG(ERR, EAL, "%s(): error with ioctl on /dev/pci: %s\n", + __func__, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + memcpy(buf, io.pi_data, len); + return 0; +} + +/* 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) +{ + struct pci_io io = { + .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 == 0 || len > sizeof(io.pi_data)) { + RTE_LOG(ERR, EAL, "%s(): invalid register length\n", __func__); + return -1; + } + memcpy(io.pi_data, buf, len); + + fd = open("/dev/pci", O_RDONLY); + if (fd < 0) { + RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__); + return -1; + } + + if (ioctl(fd, PCIOCWRITE, &io) < 0) { + RTE_LOG(ERR, EAL, "%s(): error with ioctl on /dev/pci: %s\n", + __func__, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} + /* Init the PCI EAL subsystem */ int rte_eal_pci_init(void) diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 223d3cd..f4836f6 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -393,6 +393,35 @@ 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 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 diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index d2adc66..4da59fe 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -756,6 +756,56 @@ rte_eal_pci_close_one_driver(struct rte_pci_driver *dr __rte_unused, } #endif /* RTE_LIBRTE_EAL_HOTPLUG */ +/* 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 RTE_EAL_VFIO + 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 RTE_EAL_VFIO + 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 aa7b755..c28e5b0 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h +++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h @@ -68,6 +68,11 @@ void *pci_find_max_end_va(void); void *pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size, int additional_flags); +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); + /* map IGB_UIO resource prototype */ int pci_uio_map_resource(struct rte_pci_device *dev); @@ -86,6 +91,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 b5116a7..ee7483e 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c @@ -58,6 +58,20 @@ EAL_REGISTER_TAILQ(rte_uio_tailq) #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 aea1fb1..092a369 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, -- 2.1.4