eal: provide functions to access PCI config

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 <stephen@networkplumber.org>
Acked-by: Harish Patil <harish.patil@qlogic.com>
This commit is contained in:
Stephen Hemminger 2015-07-20 09:33:17 -07:00 committed by Thomas Monjalon
parent d12b6da14b
commit 632b2d1dee
8 changed files with 210 additions and 0 deletions

View File

@ -396,6 +396,89 @@ rte_eal_pci_scan(void)
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)

View File

@ -116,6 +116,8 @@ DPDK_2.1 {
global:
rte_eal_pci_detach;
rte_eal_pci_read_config;
rte_eal_pci_write_config;
rte_memzone_free;
} DPDK_2.0;

View File

@ -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

View File

@ -571,6 +571,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)

View File

@ -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);

View File

@ -52,6 +52,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)
{

View File

@ -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,

View File

@ -116,6 +116,8 @@ DPDK_2.1 {
global:
rte_eal_pci_detach;
rte_eal_pci_read_config;
rte_eal_pci_write_config;
rte_memzone_free;
} DPDK_2.0;