DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v1 0/4] Support OFS card
@ 2022-05-17  6:28 Wei Huang
  2022-05-17  6:28 ` [PATCH v1 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
                   ` (3 more replies)
  0 siblings, 4 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-17  6:28 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

The first patch turns some experimental APIs to formal.
The second patch is a fix for virtual device release, because in OFS card, AFU
(Acceleration Function Unit) is always used as a virtual device.
The third patch is a improvement for interrupt release.
The fourth patch is for OFS (Open FPGA Stack) type card enumeration and
initialization.

Wei Huang (4):
  raw/ifpga: remove experimental tag from ifpga APIs
  raw/ifpga: remove vdev when ifpga is closed
  raw/ifpga: unregister interrupt in ifpga close function
  raw/ifpga: support ofs card probe

 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 678 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           | 241 ++++++----
 drivers/raw/ifpga/ifpga_rawdev.h           |   8 +
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  48 --
 drivers/raw/ifpga/version.map              |   7 +-
 11 files changed, 737 insertions(+), 298 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v1 1/4] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-17  6:28 [PATCH v1 0/4] Support OFS card Wei Huang
@ 2022-05-17  6:28 ` Wei Huang
  2022-05-17  6:28 ` [PATCH v1 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-17  6:28 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

These APIs are introduced in DPDK 21.05 and have been tested in several
release, experimental tag can be formally removed.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
 drivers/raw/ifpga/version.map     |  7 ++----
 2 files changed, 2 insertions(+), 53 deletions(-)

diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 47d66ba..3fa5d34 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -68,9 +68,6 @@
 } rte_pmd_ifpga_phy_info;
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
  *
  * @param pci_addr
@@ -82,14 +79,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-ENODEV) if FPGA is not probed by ifpga driver.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -103,14 +96,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Set current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -124,14 +113,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get FPGA property of specified Intel FPGA device
  *
  * @param dev_id
@@ -144,14 +129,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PHY information of specified Intel FPGA device
  *
  * @param dev_id
@@ -164,14 +145,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Update image flash of specified Intel FPGA device
  *
  * @param dev_id
@@ -187,15 +164,11 @@
  *   - (-EBUSY) if FPGA is updating or rebooting.
  *   - (-EIO) if failed to open image file.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
 	uint64_t *status);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Stop flash update of specified Intel FPGA device
  *
  * @param dev_id
@@ -208,14 +181,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EAGAIN) if failed with force.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Check current Intel FPGA status and change it to reboot status if it is idle
  *
  * @param dev_id
@@ -226,14 +195,10 @@
  *   - (-ENOMEM) if share data is not initialized.
  *   - (-EBUSY) if FPGA is updating or rebooting.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reboot_try(uint16_t dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Trigger full reconfiguration of specified Intel FPGA device
  *
  * @param dev_id
@@ -252,28 +217,20 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PCI bus the Intel FPGA driver register to
  *
  * @return
  *   - (valid pointer) if successful.
  *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
  */
-__rte_experimental
 const struct rte_pci_bus *
 rte_pmd_ifpga_get_pci_bus(void);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Perform PR (partial reconfiguration) on specified Intel FPGA device
  *
  * @param dev_id
@@ -287,17 +244,12 @@
  *   - (-EINVAL) if bad parameter or operation failed.
  *   - (-ENOMEM) if failed to allocate memory.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Free software resources allocated by Intel FPGA PMD
  */
-__rte_experimental
 void
 rte_pmd_ifpga_cleanup(void);
 
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index a1a6be2..ff71a45 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -1,11 +1,6 @@
 DPDK_22 {
-	local: *;
-};
-
-EXPERIMENTAL {
 	global:
 
-	# added in 21.05
 	rte_pmd_ifpga_get_dev_id;
 	rte_pmd_ifpga_get_rsu_status;
 	rte_pmd_ifpga_set_rsu_status;
@@ -18,4 +13,6 @@ EXPERIMENTAL {
 	rte_pmd_ifpga_get_pci_bus;
 	rte_pmd_ifpga_partial_reconfigure;
 	rte_pmd_ifpga_cleanup;
+
+	local: *;
 };
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v1 2/4] raw/ifpga: remove vdev when ifpga is closed
  2022-05-17  6:28 [PATCH v1 0/4] Support OFS card Wei Huang
  2022-05-17  6:28 ` [PATCH v1 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-17  6:28 ` Wei Huang
  2022-05-17  6:28 ` [PATCH v1 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
  2022-05-17  6:28 ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Wei Huang
  3 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-17  6:28 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Virtual devices created on ifpga raw device are not removed when
ifpga is closed. To avoid such problem, ifpga virtual device remove
function is implemented, virtual device is removed in raw device
close function.

Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Acked-by: Rosen Xu <rosen.xu@intel.com>
---
 drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---------
 drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
 2 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 6d4117c..fe3fc43 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -134,6 +134,8 @@ struct ifpga_rawdev *
 	for (i = 0; i < IFPGA_MAX_IRQ; i++)
 		dev->intr_handle[i] = NULL;
 	dev->poll_enabled = 0;
+	for (i = 0; i < IFPGA_MAX_VDEV; i++)
+		dev->vdev_name[i] = NULL;
 
 	return dev;
 }
@@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(
 static int
 ifpga_rawdev_close(struct rte_rawdev *dev)
 {
+	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	char *vdev_name = NULL;
+	int i = 0;
 
 	if (dev) {
-		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
+		ifpga_rdev = ifpga_rawdev_get(dev);
+		if (ifpga_rdev) {
+			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+				vdev_name = ifpga_rdev->vdev_name[i];
+				if (vdev_name)
+					rte_vdev_uninit(vdev_name);
+			}
+			ifpga_monitor_stop_func(ifpga_rdev);
+			ifpga_rdev->rawdev = NULL;
+		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
 			opae_adapter_destroy(adapter);
@@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		return -EINVAL;
 	}
 	dev = ifpga_rawdev_get(rawdev);
-	if (dev)
-		dev->rawdev = NULL;
 
 	adapter = ifpga_rawdev_get_priv(rawdev);
 	if (!adapter)
@@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 
 	return 0;
 }
+
 static int
-ifpga_cfg_probe(struct rte_vdev_device *dev)
+ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
+	struct ifpga_vdev_args *args)
 {
-	struct rte_devargs *devargs;
-	struct rte_kvargs *kvlist = NULL;
-	struct rte_rawdev *rawdev = NULL;
-	struct ifpga_rawdev *ifpga_dev;
-	int port;
+	struct rte_kvargs *kvlist;
 	char *name = NULL;
-	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
-	int ret = -1;
+	int port = 0;
+	int ret = -EINVAL;
 
-	devargs = dev->device.devargs;
+	if (!devargs || !args)
+		return ret;
 
 	kvlist = rte_kvargs_parse(devargs->args, valid_args);
 	if (!kvlist) {
-		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
-		goto end;
+		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
+		return ret;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
 		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
-				       &ifpga_rawdev_get_string_arg,
-				       &name) < 0) {
+			&ifpga_rawdev_get_string_arg, &name) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
-				     IFPGA_ARG_NAME);
+				IFPGA_ARG_NAME);
 			goto end;
+		} else {
+			strlcpy(args->bdf, name, sizeof(args->bdf));
+			rte_free(name);
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_NAME);
+			IFPGA_ARG_NAME);
 		goto end;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
-		if (rte_kvargs_process(kvlist,
-			IFPGA_ARG_PORT,
-			&rte_ifpga_get_integer32_arg,
-			&port) < 0) {
+		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
+			&rte_ifpga_get_integer32_arg, &port) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
 				IFPGA_ARG_PORT);
 			goto end;
+		} else {
+			args->port = port;
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_PORT);
+			IFPGA_ARG_PORT);
 		goto end;
 	}
 
+	ret = 0;
+
+end:
+	if (kvlist)
+		rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+ifpga_cfg_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	int i, n, ret = 0;
+
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
 	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name);
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
 	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
 	if (!rawdev)
-		goto end;
+		return -ENODEV;
 	ifpga_dev = ifpga_rawdev_get(rawdev);
 	if (!ifpga_dev)
-		goto end;
+		return -ENODEV;
 
-	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
-	port, name);
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		if (ifpga_dev->vdev_name[i] == NULL) {
+			n = strlen(vdev_name) + 1;
+			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
+			if (ifpga_dev->vdev_name[i] == NULL)
+				return -ENOMEM;
+			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
+			break;
+		}
+	}
 
+	if (i >= IFPGA_MAX_VDEV) {
+		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
+		return -ENOENT;
+	}
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
 	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
-			dev_name, devargs->args);
-end:
-	rte_kvargs_free(kvlist);
-	free(name);
+			dev_name, vdev->device.devargs->args);
+	if (ret) {
+		rte_free(ifpga_dev->vdev_name[i]);
+		ifpga_dev->vdev_name[i] = NULL;
+	}
 
 	return ret;
 }
@@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 static int
 ifpga_cfg_remove(struct rte_vdev_device *vdev)
 {
-	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
-		vdev);
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	char *tmp_vdev = NULL;
+	int i, ret = 0;
 
-	return 0;
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
+	memset(dev_name, 0, sizeof(dev_name));
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
+	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
+	if (!rawdev)
+		return -ENODEV;
+	ifpga_dev = ifpga_rawdev_get(rawdev);
+	if (!ifpga_dev)
+		return -ENODEV;
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
+	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME), dev_name);
+
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		tmp_vdev = ifpga_dev->vdev_name[i];
+		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
+			free(tmp_vdev);
+			ifpga_dev->vdev_name[i] = NULL;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static struct rte_vdev_driver ifpga_cfg_driver = {
diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
index 857b734..eb9a9a5 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.h
+++ b/drivers/raw/ifpga/ifpga_rawdev.h
@@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
 
 #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
 #define IFPGA_RAWDEV_NUM 32
+#define IFPGA_MAX_VDEV 4
 #define IFPGA_MAX_IRQ 12
 
 struct ifpga_rawdev {
@@ -64,6 +65,13 @@ struct ifpga_rawdev {
 	void *intr_handle[IFPGA_MAX_IRQ];
 	/* enable monitor thread poll device's sensors or not */
 	int poll_enabled;
+	/* name of virtual devices created on raw device */
+	char *vdev_name[IFPGA_MAX_VDEV];
+};
+
+struct ifpga_vdev_args {
+	char bdf[8];
+	int port;
 };
 
 struct ifpga_rawdev *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v1 3/4] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-17  6:28 [PATCH v1 0/4] Support OFS card Wei Huang
  2022-05-17  6:28 ` [PATCH v1 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
  2022-05-17  6:28 ` [PATCH v1 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-17  6:28 ` Wei Huang
  2022-05-17  6:28 ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Wei Huang
  3 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-17  6:28 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Move interrupt unregistration from ifpga destroy function to
ifpga close function, so rte_rawdev_pmd_release function can
release interrupt resource.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index fe3fc43..94df56c 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(
 static int ifpga_pci_find_next_ext_capability(unsigned int fd,
 					      int start, uint32_t cap);
 static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
+static void fme_interrupt_handler(void *param);
 
 struct ifpga_rawdev *
 ifpga_rawdev_get(const struct rte_rawdev *rawdev)
@@ -740,8 +741,9 @@ static int set_surprise_link_check_aer(
 {
 	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	struct opae_manager *mgr;
 	char *vdev_name = NULL;
-	int i = 0;
+	int i, ret = 0;
 
 	if (dev) {
 		ifpga_rdev = ifpga_rawdev_get(dev);
@@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
 		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
+			mgr = opae_adapter_get_mgr(adapter);
+			if (ifpga_rdev && mgr) {
+				if (ifpga_unregister_msix_irq(ifpga_rdev,
+					IFPGA_FME_IRQ, 0,
+					fme_interrupt_handler, mgr) < 0)
+					ret = -EINVAL;
+			}
 			opae_adapter_destroy(adapter);
 			opae_adapter_data_free(adapter->data);
 		}
 	}
 
-	return dev ? 0:1;
+	return ret;
 }
 
 static int
@@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	int ret;
 	struct rte_rawdev *rawdev;
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
-	struct opae_adapter *adapter;
-	struct opae_manager *mgr;
-	struct ifpga_rawdev *dev;
 
 	if (!pci_dev) {
 		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
@@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
 		return -EINVAL;
 	}
-	dev = ifpga_rawdev_get(rawdev);
-
-	adapter = ifpga_rawdev_get_priv(rawdev);
-	if (!adapter)
-		return -ENODEV;
-
-	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
-		return -ENODEV;
-
-	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
-				fme_interrupt_handler, mgr) < 0)
-		return -EINVAL;
 
 	/* rte_rawdev_close is called by pmd_release */
 	ret = rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v1 4/4] raw/ifpga: support ofs card probe
  2022-05-17  6:28 [PATCH v1 0/4] Support OFS card Wei Huang
                   ` (2 preceding siblings ...)
  2022-05-17  6:28 ` [PATCH v1 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-17  6:28 ` Wei Huang
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
  2022-05-25  3:18   ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Zhang, Tianfei
  3 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-17  6:28 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

ofs card introduces some changes in DFL (Device Feature List) and
DFH (Device Feature Header) of FPGA. ifpga driver adapt these
changes mainly by adjusting enumeration process.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 678 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
 8 files changed, 587 insertions(+), 192 deletions(-)

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index 4610ef1..f19cc26 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -13,15 +13,22 @@
 static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
 			      struct uuid *uuid)
 {
-	struct opae_bridge *br = acc->br;
-	struct ifpga_port_hw *port;
+	struct ifpga_afu_info *afu_info = acc->data;
+	struct opae_reg_region *region;
+	u64 val = 0;
 
-	if (!br || !br->data)
-		return -EINVAL;
+	if (!afu_info)
+		return -ENODEV;
 
-	port = br->data;
+	region = &afu_info->region[0];
+	if (uuid) {
+		val = readq(region->addr + sizeof(struct feature_header));
+		opae_memcpy(uuid->b, &val, sizeof(u64));
+		val = readq(region->addr + sizeof(struct feature_header) + 8);
+		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
+	}
 
-	return fpga_get_afu_uuid(port, uuid);
+	return 0;
 }
 
 static int ifpga_acc_set_irq(struct opae_accelerator *acc,
@@ -32,6 +39,9 @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
 	struct ifpga_port_hw *port;
 	struct fpga_uafu_irq_set irq_set;
 
+	if (!afu_info)
+		return -ENODEV;
+
 	if (!br || !br->data)
 		return -EINVAL;
 
@@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
 	struct ifpga_afu_info *afu_info = acc->data;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (info->index >= afu_info->num_regions)
 		return -EINVAL;
@@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
@@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h
index 8f62033..9a280eb 100644
--- a/drivers/raw/ifpga/base/ifpga_defines.h
+++ b/drivers/raw/ifpga/base/ifpga_defines.h
@@ -73,6 +73,7 @@
 enum fpga_id_type {
 	FME_ID,
 	PORT_ID,
+	AFU_ID,
 	FPGA_ID_MAX,
 };
 
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c b/drivers/raw/ifpga/base/ifpga_enumerate.c
index 48b8af4..257e609 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.c
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
@@ -2,6 +2,10 @@
  * Copyright(c) 2010-2018 Intel Corporation
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
 #include "opae_hw_api.h"
 #include "ifpga_api.h"
 
@@ -9,6 +13,19 @@
 #include "ifpga_enumerate.h"
 #include "ifpga_feature_dev.h"
 
+struct dfl_fpga_enum_dfl {
+	u64 start;
+	u64 len;
+	void *addr;
+	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
+};
+
+TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl);
+struct dfl_fpga_enum_info {
+	struct ifpga_hw *hw;
+	struct dfl_fpga_enum_dfls dfls;
+};
+
 struct build_feature_devs_info {
 	struct opae_adapter_data_pci *pci_data;
 
@@ -21,7 +38,6 @@ struct build_feature_devs_info {
 	void *ioaddr;
 	void *ioend;
 	uint64_t phys_addr;
-	int current_bar;
 
 	void *pfme_hdr;
 
@@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
 			unsigned int size, unsigned int vec_start,
 			unsigned int vec_cnt)
 {
-	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
-			vec_cnt);
+	if (binfo->current_type != AFU_ID)
+		return build_info_add_sub_feature(binfo, start, fid, size,
+			vec_start, vec_cnt);
+	return 0;
 }
 
 /*
@@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
  */
 static bool feature_is_UAFU(struct build_feature_devs_info *binfo)
 {
-	if (binfo->current_type != PORT_ID)
-		return false;
+	if ((binfo->current_type == PORT_ID) ||
+		(binfo->current_type == AFU_ID))
+		return true;
 
-	return true;
+	return false;
 }
 
-static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
+static int parse_feature_uafu(struct build_feature_devs_info *binfo,
 				   struct feature_header *hdr)
 {
 	u64 id = PORT_FEATURE_ID_UAFU;
@@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	int ret;
 	int size;
 
+	if (binfo->acc_info) {
+		dev_info(binfo, "Sub AFU found @ %p.\n", start);
+		return 0;
+	}
+
 	capability.csr = readq(&port_hdr->capability);
 
-	size = capability.mmio_size << 10;
+	if (binfo->current_type == AFU_ID) {
+		size = AFU_REGION_SIZE;
+	} else {
+		capability.csr = readq(&port_hdr->capability);
+		size = capability.mmio_size << 10;
+	}
 
 	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
 	if (ret)
@@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	info->region[0].phys_addr = binfo->phys_addr +
 			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
 	info->region[0].len = size;
-	info->num_regions = 1;
+	info->num_regions = AFU_MAX_REGION;
 
 	binfo->acc_info = info;
 
 	return ret;
 }
 
-static int parse_feature_afus(struct build_feature_devs_info *binfo,
-			      struct feature_header *hdr)
-{
-	int ret;
-	struct feature_afu_header *afu_hdr, header;
-	u8 __iomem *start;
-	u8 __iomem *end = binfo->ioend;
-
-	start = (u8 __iomem *)hdr;
-	for (; start < end; start += header.next_afu) {
-		if ((unsigned int)(end - start) <
-			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
-			return -EINVAL;
-
-		hdr = (struct feature_header *)start;
-		afu_hdr = (struct feature_afu_header *)(hdr + 1);
-		header.csr = readq(&afu_hdr->csr);
-
-		if (feature_is_UAFU(binfo)) {
-			ret = parse_feature_port_uafu(binfo, hdr);
-			if (ret)
-				return ret;
-		}
-
-		if (!header.next_afu)
-			break;
-	}
-
-	return 0;
-}
-
 /* create and register proper private data */
 static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
@@ -235,13 +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	struct ifpga_fme_hw *fme;
 	struct ifpga_feature *feature;
 
-	if (!binfo->fiu)
-		return 0;
-
 	if (binfo->current_type == PORT_ID) {
-		/* return error if no valid acc info data structure */
-		if (!info)
-			return -EFAULT;
+		if (!binfo->fiu)
+			return 0;
 
 		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
 				       binfo->fiu);
@@ -254,7 +248,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 		port = &hw->port[binfo->current_port_id];
 		feature = get_feature_by_id(&port->feature_list,
 				PORT_FEATURE_ID_UINT);
-		if (feature)
+		if (feature && info)
 			info->num_irqs = feature->vec_cnt;
 
 		acc = opae_accelerator_alloc(hw->adapter->name,
@@ -264,17 +258,21 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 			return -ENOMEM;
 		}
 
+		acc->adapter = hw->adapter;
 		acc->br = br;
 		if (hw->adapter->mgr)
 			acc->mgr = hw->adapter->mgr;
 		acc->index = br->id;
 
 		fme = &hw->fme;
-		fme->nums_acc_region = info->num_regions;
+		fme->nums_acc_region = info ? info->num_regions : 0;
 
 		opae_adapter_add_acc(hw->adapter, acc);
 
 	} else if (binfo->current_type == FME_ID) {
+		if (!binfo->fiu)
+			return 0;
+
 		mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,
 				&ifpga_mgr_network_ops, binfo->fiu);
 		if (!mgr)
@@ -282,6 +280,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 
 		mgr->adapter = hw->adapter;
 		hw->adapter->mgr = mgr;
+	} else if (binfo->current_type == AFU_ID) {
+		if (!info)
+			return -EFAULT;
+
+		info->num_irqs = 0;
+		acc = opae_accelerator_alloc(hw->adapter->name,
+					&ifpga_acc_ops, info);
+		if (!acc)
+			return -ENOMEM;
+
+		acc->adapter = hw->adapter;
+		acc->br = NULL;
+		acc->mgr = NULL;
+		acc->index = hw->num_afus++;
+
+		opae_adapter_add_acc(hw->adapter, acc);
 	}
 
 	binfo->fiu = NULL;
@@ -295,11 +309,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
 	int ret;
 
+	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
+		return 0;
+
 	ret = build_info_commit_dev(binfo);
 	if (ret)
 		return ret;
 
 	binfo->current_type = type;
+	binfo->acc_info = NULL;
 
 	if (type == FME_ID) {
 		binfo->fiu = &binfo->hw->fme;
@@ -311,6 +329,41 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	return 0;
 }
 
+static int parse_feature_afus(struct build_feature_devs_info *binfo,
+			      struct feature_header *hdr)
+{
+	int ret;
+	struct feature_afu_header *afu_hdr, header;
+	u8 __iomem *start;
+	u8 __iomem *end = binfo->ioend;
+
+	ret = build_info_create_dev(binfo, AFU_ID, 0);
+	if (ret)
+		return ret;
+
+	start = (u8 __iomem *)hdr;
+	for (; start < end; start += header.next_afu) {
+		if ((unsigned int)(end - start) <
+			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
+			return -EINVAL;
+
+		hdr = (struct feature_header *)start;
+		afu_hdr = (struct feature_afu_header *)(hdr + 1);
+		header.csr = readq(&afu_hdr->csr);
+
+		if (feature_is_UAFU(binfo)) {
+			ret = parse_feature_uafu(binfo, hdr);
+			if (ret)
+				return ret;
+		}
+
+		if (!header.next_afu)
+			break;
+	}
+
+	return 0;
+}
+
 static int parse_feature_fme(struct build_feature_devs_info *binfo,
 			     struct feature_header *start)
 {
@@ -405,7 +458,7 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 			if (ret)
 				return ret;
 		} else {
-			dev_info(binfo, "No AFUs detected on Port\n");
+			dev_info(binfo, "No AFU detected on Port\n");
 		}
 
 		break;
@@ -426,7 +479,7 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 
 	id = feature_id(start);
 
-	if (id == PORT_FEATURE_ID_UINT) {
+	if ((binfo->current_type == PORT_ID) && (id == PORT_FEATURE_ID_UINT)) {
 		struct feature_port_uint *port_uint = start;
 		struct feature_port_uint_cap uint_cap;
 
@@ -437,7 +490,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 		} else {
 			dev_debug(binfo, "UAFU doesn't support interrupt\n");
 		}
-	} else if (id == PORT_FEATURE_ID_ERROR) {
+	} else if ((binfo->current_type == PORT_ID) &&
+			(id == PORT_FEATURE_ID_ERROR)) {
 		struct feature_port_error *port_err = start;
 		struct feature_port_err_capability port_err_cap;
 
@@ -449,7 +503,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 			dev_debug(&binfo, "Port error doesn't support interrupt\n");
 		}
 
-	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
+	} else if ((binfo->current_type == FME_ID) &&
+			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
 		struct feature_fme_err *fme_err = start;
 		struct feature_fme_error_capability fme_err_cap;
 
@@ -497,9 +552,15 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
 		return parse_feature_fme_private(binfo, hdr);
 	case PORT_ID:
 		return parse_feature_port_private(binfo, hdr);
+	case AFU_ID:
+		dev_err(binfo, "private feature %x belonging to AFU "
+			"is not supported yet.\n", header.id);
+		break;
 	default:
-		dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n",
+		dev_err(binfo, "private feature %x belonging to TYPE %d "
+			"(unknown_type) is not supported yet.\n",
 			header.id, binfo->current_type);
+		break;
 	}
 	return 0;
 }
@@ -530,32 +591,57 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return ret;
 }
 
-static int
-parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
+static int build_info_prepare(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
 {
+	if (!binfo || !dfl)
+		return -EINVAL;
+
+	binfo->ioaddr = dfl->addr;
+	binfo->ioend = (u8 *)dfl->addr + dfl->len;
+	binfo->phys_addr = dfl->start;
+
+	return 0;
+}
+
+static int parse_feature_list(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
+{
+	u8 *start, *end;
 	struct feature_header *hdr, header;
-	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
 	int ret = 0;
 
+	ret = build_info_prepare(binfo, dfl);
+	if (ret)
+		return ret;
+
+	start = (u8 *)binfo->ioaddr;
+	end = (u8 *)binfo->ioend;
+
+	/* walk through the device feature list via DFH's next DFH pointer. */
 	for (; start < end; start += header.next_header_offset) {
 		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
-			dev_err(binfo, "The region is too small to contain a feature.\n");
-			ret =  -EINVAL;
+			dev_err(binfo, "The region is too small to "
+				"contain a feature.\n");
+			ret = -EINVAL;
 			break;
 		}
 
 		hdr = (struct feature_header *)start;
-		header.csr = readq(hdr);
+		header.csr = opae_readq(hdr);
 
-		dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n",
-			__func__, hdr, (unsigned long long)header.csr,
-			header.id, header.next_header_offset,
-			header.end_of_list, header.type);
+		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
+			"header.id=0x%x, header.next_offset=0x%x, "
+			"header.eol=0x%x, header.type=0x%x\n",
+			__func__, hdr, header.csr, header.id,
+			header.next_header_offset, header.end_of_list,
+			header.type);
 
 		ret = parse_feature(binfo, hdr);
 		if (ret)
 			return ret;
 
+		/* stop parsing if EOL(End of List) is set or offset is 0 */
 		if (header.end_of_list || !header.next_header_offset)
 			break;
 	}
@@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return build_info_commit_dev(binfo);
 }
 
-/* switch the memory mapping to BAR# @bar */
-static int parse_switch_to(struct build_feature_devs_info *binfo, int bar)
-{
-	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
-
-	if (!pci_data->region[bar].addr)
-		return -ENOMEM;
-
-	binfo->ioaddr = pci_data->region[bar].addr;
-	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len;
-	binfo->phys_addr = pci_data->region[bar].phys_addr;
-	binfo->current_bar = bar;
-
-	return 0;
-}
-
-static int parse_ports_from_fme(struct build_feature_devs_info *binfo)
-{
-	struct feature_fme_header *fme_hdr;
-	struct feature_fme_port port;
-	int i = 0, ret = 0;
-
-	if (!binfo->pfme_hdr) {
-		dev_info(binfo,  "VF is detected.\n");
-		return ret;
-	}
-
-	fme_hdr = binfo->pfme_hdr;
-
-	do {
-		port.csr = readq(&fme_hdr->port[i]);
-		if (!port.port_implemented)
-			break;
-
-		/* skip port which only could be accessed via VF */
-		if (port.afu_access_control == FME_AFU_ACCESS_VF)
-			continue;
-
-		ret = parse_switch_to(binfo, port.port_bar);
-		if (ret)
-			break;
-
-		ret = parse_feature_list(binfo,
-					 (u8 __iomem *)binfo->ioaddr +
-					  port.port_offset);
-		if (ret)
-			break;
-	} while (++i < MAX_FPGA_PORT_NUM);
-
-	return ret;
-}
-
-static struct build_feature_devs_info *
-build_info_alloc_and_init(struct ifpga_hw *hw)
-{
-	struct build_feature_devs_info *binfo;
-
-	binfo = zmalloc(sizeof(*binfo));
-	if (!binfo)
-		return binfo;
-
-	binfo->hw = hw;
-	binfo->pci_data = hw->pci_data;
-
-	/* fpga feature list starts from BAR 0 */
-	if (parse_switch_to(binfo, 0)) {
-		free(binfo);
-		return NULL;
-	}
-
-	return binfo;
-}
-
 static void build_info_free(struct build_feature_devs_info *binfo)
 {
-	free(binfo);
+	opae_free(binfo);
 }
 
 static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
@@ -648,6 +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	struct ifpga_feature *feature;
 	int i;
 
+	if (fme->state == IFPGA_FME_UNUSED) {
+		dev_info(hw, "FME is not present\n");
+		return;
+	}
+
 	dev_info(hw, "found fme_device, is in PF: %s\n",
 		 is_ifpga_hw_pf(hw) ? "yes" : "no");
 
@@ -685,40 +703,408 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	}
 }
 
-int ifpga_bus_enumerate(struct ifpga_hw *hw)
+static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct ifpga_hw *hw)
 {
-	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_info *info;
+
+	info = opae_zmalloc(sizeof(*info));
+	if (!info)
+		return NULL;
+
+	info->hw = hw;
+	TAILQ_INIT(&info->dfls);
+
+	return info;
+}
+
+static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
+{
+	struct dfl_fpga_enum_dfl *tmp, *dfl;
+
+	if (!info)
+		return;
+
+	/* remove all device feature lists in the list. */
+	for (dfl = TAILQ_FIRST(&info->dfls);
+		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
+		dfl = tmp) {
+		TAILQ_REMOVE(&info->dfls, dfl, node);
+		opae_free(dfl);
+	}
+
+	opae_free(info);
+}
+
+static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
+	u64 start, u64 len, void *addr)
+{
+	struct dfl_fpga_enum_dfl *dfl;
+
+	dfl = opae_zmalloc(sizeof(*dfl));
+	if (!dfl)
+		return -ENOMEM;
+
+	dfl->start = start;
+	dfl->len = len;
+	dfl->addr = addr;
+
+	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
+
+	return 0;
+}
+
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+static int
+pci_find_next_ecap(int fd, int start, u32 cap)
+{
+	u32 header;
+	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+	int pos = PCI_CFG_SPACE_SIZE;
 	int ret;
 
-	binfo = build_info_alloc_and_init(hw);
+	if (start > 0)
+		pos = start;
+
+	ret = pread(fd, &header, sizeof(header), pos);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+		ret = pread(fd, &header, sizeof(header), pos);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PCI_EXT_CAP_ID_VNDR	0x0B
+#define PCI_VNDR_HEADER		4
+#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VSEC_ID_INTEL_DFLS 0x43
+#define PCI_VNDR_DFLS_CNT 0x8
+#define PCI_VNDR_DFLS_RES 0xc
+#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
+#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
+
+static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	char path[64];
+	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
+	int fd, ret, dfl_res_off, voff = 0;
+	u64 start, len;
+	void *addr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->adapter || !hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
+			hw->adapter->name);
+	if ((unsigned int)ret >= sizeof(path))
+		return -EINVAL;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -EIO;
+
+	while ((voff = pci_find_next_ecap(fd, voff,
+		PCI_EXT_CAP_ID_VNDR))) {
+		vndr_hdr = 0;
+		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
+			voff + PCI_VNDR_HEADER);
+		if (ret < 0)
+			return -EIO;
+		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
+			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
+			break;
+	}
+
+	if (!voff) {
+		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
+		return -ENODEV;
+	}
+
+	dfl_cnt = 0;
+	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
+	if (ret < 0)
+		return -EIO;
+
+	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
+	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
+		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
+		dfl_res = GENMASK(31, 0);
+		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
+		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
+		if (bir >= PCI_MAX_RESOURCE) {
+			dev_err(hw, "%s bad bir number %d\n",
+				__func__, bir);
+			return -EINVAL;
+		}
+
+		len = pci_data->region[bir].len;
+		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
+		if (offset >= len) {
+			dev_err(hw, "%s bad offset %u >= %zu\n",
+				__func__, offset, len);
+			return -EINVAL;
+		}
+
+		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
+		len -= offset;
+		start = pci_data->region[bir].phys_addr + offset;
+		addr = pci_data->region[bir].addr + offset;
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	}
+
+	return 0;
+}
+
+/* default method of finding dfls starting at offset 0 of bar 0 */
+static int
+find_dfls_by_default(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	int port_num, bar, i, ret = 0;
+	u64 start, len;
+	void *addr;
+	u32 offset;
+	struct feature_header hdr;
+	struct feature_fme_capability cap;
+	struct feature_fme_port port;
+	struct feature_fme_header *fme_hdr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	/* start to find Device Feature List from Bar 0 */
+	addr = pci_data->region[0].addr;
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * PF device has FME and Ports/AFUs, and VF device only has one
+	 * Port/AFU. Check them and add related "Device Feature List" info
+	 * for the next step enumeration.
+	 */
+	hdr.csr = opae_readq(addr);
+	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id == FEATURE_FIU_ID_FME)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+
+		/*
+		 * find more Device Feature Lists (e.g. Ports) per information
+		 * indicated by FME module.
+		 */
+		fme_hdr = (struct feature_fme_header *)addr;
+		cap.csr = opae_readq(&fme_hdr->capability);
+		port_num = (int)cap.num_ports;
+
+		dev_info(hw, "port_num = %d\n", port_num);
+		if (port_num > MAX_FPGA_PORT_NUM)
+			port_num = MAX_FPGA_PORT_NUM;
+
+		for (i = 0; i < port_num; i++) {
+			port.csr = opae_readq(&fme_hdr->port[i]);
+
+			/* skip ports which are not implemented. */
+			if (!port.port_implemented)
+				continue;
+
+			/* skip port which only could be accessed via VF */
+			if (port.afu_access_control == FME_AFU_ACCESS_VF)
+				continue;
+
+			/*
+			 * add Port's Device Feature List information for next
+			 * step enumeration.
+			 */
+			bar = (int)port.port_bar;
+			offset = port.port_offset;
+			if (bar >= PCI_MAX_RESOURCE) {
+				dev_info(hw, "skipping BAR %d\n", bar);
+				continue;
+			} else {
+				dev_info(hw, "BAR %d offset %u\n", bar, offset);
+			}
+
+			len = pci_data->region[bar].len;
+			if (offset >= len) {
+				dev_warn(hw, "bad port offset %u >= %pa\n",
+					 offset, &len);
+				continue;
+			}
+
+			len -= offset;
+			start = pci_data->region[bar].phys_addr + offset;
+			addr = pci_data->region[bar].addr + offset;
+			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+		}
+	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
+		(hdr.id == FEATURE_FIU_ID_PORT)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else if (hdr.type == FEATURE_TYPE_AFU) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else {
+		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
+			 hdr.type, hdr.id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
+{
+	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_dfl *dfl;
+	int ret = 0;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+
+	/* create and init build info for enumeration */
+	binfo = opae_zmalloc(sizeof(*binfo));
 	if (!binfo)
 		return -ENOMEM;
 
-	ret = parse_feature_list(binfo, binfo->ioaddr);
+	binfo->hw = info->hw;
+	binfo->pci_data = info->hw->pci_data;
+
+	/*
+	 * start enumeration for all feature devices based on Device Feature
+	 * Lists.
+	 */
+	TAILQ_FOREACH(dfl, &info->dfls, node) {
+		ret = parse_feature_list(binfo, dfl);
+		if (ret)
+			break;
+	}
+
+	build_info_free(binfo);
+
+	return ret;
+}
+
+int ifpga_bus_enumerate(struct ifpga_hw *hw)
+{
+	struct dfl_fpga_enum_info *info;
+	int ret;
+
+	/* allocate enumeration info */
+	info = dfl_fpga_enum_info_alloc(hw);
+	if (!info)
+		return -ENOMEM;
+
+	ret = find_dfls_by_vsec(info);
+	if (ret < 0)
+		ret = find_dfls_by_default(info);
+
 	if (ret)
 		goto exit;
 
-	ret = parse_ports_from_fme(binfo);
-	if (ret)
+	/* start enumeration with prepared enumeration information */
+	ret = dfl_fpga_feature_devs_enumerate(info);
+	if (ret < 0) {
+		dev_err(hw, "Enumeration failure\n");
 		goto exit;
+	}
 
 	ifpga_print_device_feature_list(hw);
 
 exit:
-	build_info_free(binfo);
+	dfl_fpga_enum_info_free(info);
+
 	return ret;
 }
 
-int ifpga_bus_init(struct ifpga_hw *hw)
+static void ifpga_print_acc_list(struct opae_adapter *adapter)
 {
+	struct opae_accelerator *acc;
+	struct ifpga_afu_info *info;
+	struct uuid guid;
+	char buf[48];
 	int i;
+
+	opae_adapter_for_each_acc(adapter, acc) {
+		info = acc->data;
+		if (!info)
+			continue;
+		acc->ops->get_uuid(acc, &guid);
+		i = sprintf(buf, "%02x%02x%02x%02x-",
+			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
+		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
+			guid.b[5], guid.b[4], guid.b[3],
+			guid.b[2], guid.b[1], guid.b[0]);
+		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
+			acc->name, acc->index, info->region[0].addr,
+			info->region[0].len, buf);
+	}
+}
+
+int ifpga_bus_init(struct ifpga_hw *hw)
+{
+	int i, ret = 0;
 	struct ifpga_port_hw *port;
 
-	fme_hw_init(&hw->fme);
+	ret = fme_hw_init(&hw->fme);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
 		port = &hw->port[i];
 		port_hw_init(port);
 	}
+	ifpga_print_acc_list(hw->adapter);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c
index 0813513..dbecc7b 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
@@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
 	if (fpga_wait_register_field(port_sftrst_ack, control,
 				     &port_hdr->control, RST_POLL_TIMEOUT,
 				     RST_POLL_INVL)) {
-		dev_err(port, "timeout, fail to reset device\n");
+		dev_err(port, "timeout, fail to reset FIM port\n");
 		return -ETIMEDOUT;
 	}
 
@@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list *list)
 	struct ifpga_feature *feature;
 
 	TAILQ_FOREACH(feature, list, next) {
-		if (feature->state != IFPGA_FEATURE_ATTACHED)
+		if (feature->state != IFPGA_FEATURE_INITED)
 			continue;
 		if (feature->ops && feature->ops->uinit)
 			feature->ops->uinit(feature);
+		feature->state = IFPGA_FEATURE_ATTACHED;
 	}
 }
 
@@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
 					ret = feature->ops->init(feature);
 					if (ret)
 						goto error;
+					else
+						feature->state =
+							IFPGA_FEATURE_INITED;
 				}
 			}
 		}
@@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
 
 int fme_hw_init(struct ifpga_fme_hw *fme)
 {
-	int ret;
-
-	if (fme->state != IFPGA_FME_IMPLEMENTED)
-		return -ENODEV;
-
-	ret = feature_init(fme_feature_drvs, &fme->feature_list);
-	if (ret)
-		return ret;
+	if (fme->state == IFPGA_FME_IMPLEMENTED)
+		return feature_init(fme_feature_drvs, &fme->feature_list);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h
index ed5edc6..4d56deb 100644
--- a/drivers/raw/ifpga/base/ifpga_hw.h
+++ b/drivers/raw/ifpga/base/ifpga_hw.h
@@ -15,6 +15,7 @@
 enum ifpga_feature_state {
 	IFPGA_FEATURE_UNUSED = 0,
 	IFPGA_FEATURE_ATTACHED,
+	IFPGA_FEATURE_INITED
 };
 
 enum feature_type {
@@ -134,6 +135,7 @@ struct ifpga_hw {
 
 	struct ifpga_fme_hw fme;
 	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
+	int num_afus;
 };
 
 static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 11c9887..87256fc 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator *acc,
 int opae_acc_set_irq(struct opae_accelerator *acc,
 		     u32 start, u32 count, s32 evtfds[])
 {
-	if (!acc || !acc->data)
+	if (!acc)
 		return -EINVAL;
 
 	if (start + count <= start)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 7e04b56..fd40e09 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -143,6 +143,7 @@ struct opae_accelerator {
 	TAILQ_ENTRY(opae_accelerator) node;
 	const char *name;
 	int index;
+	struct opae_adapter *adapter;
 	struct opae_bridge *br;
 	struct opae_manager *mgr;
 	struct opae_accelerator_ops *ops;
@@ -240,6 +241,7 @@ struct opae_adapter_data {
 
 struct opae_reg_region {
 	u64 phys_addr;
+#define AFU_REGION_SIZE  0x8000
 	u64 len;
 	u8 *addr;
 };
diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 94df56c..ceb18ae 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -47,11 +47,13 @@
 #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
 #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
 #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
+#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
 /* VF Device */
 #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
 #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
 #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
 #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
+#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
 #define RTE_MAX_RAW_DEVICE           10
 
 static const struct rte_pci_id pci_ifpga_map[] = {
@@ -63,6 +65,8 @@
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),},
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N6000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N6000),},
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -110,6 +114,7 @@ struct ifpga_rawdev *
 
 	return IFPGA_RAWDEV_NUM;
 }
+
 static struct ifpga_rawdev *
 ifpga_rawdev_allocate(struct rte_rawdev *rawdev)
 {
@@ -365,7 +370,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 		return -ENODEV;
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
+	if (!mgr || !mgr->sensor_list)
 		return -ENODEV;
 
 	opae_mgr_for_each_sensor(mgr, sensor) {
@@ -377,7 +382,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 			goto fail;
 
 		if (value == 0xdeadbeef) {
-			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value %x\n",
+			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s value %x\n",
 					raw_dev->dev_id, sensor->name, value);
 			continue;
 		}
@@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(
 {
 	struct opae_adapter *adapter;
 	struct opae_manager *mgr;
-	struct opae_board_info *info;
+	struct opae_board_info *info = NULL;
 	struct rte_afu_pr_conf *afu_pr_conf;
 	int ret;
 	struct uuid uuid;
@@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
 	}
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr) {
-		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL");
-		return -1;
-	}
-
-	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
-		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
-		return -1;
+	if (mgr) {
+		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
+			IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
+			return -1;
+		}
 	}
 
-	if (info->lightweight) {
+	if (info && info->lightweight) {
 		/* set uuid to all 0, when fpga is lightweight image */
 		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
 		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
@@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
 			__func__,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
-		}
+	}
 	return 0;
 }
 
@@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
 	if (ret) {
 		ret = -ENOMEM;
-		goto free_adapter_data;
+		goto cleanup;
 	}
 
 	rawdev->dev_ops = &ifpga_rawdev_ops;
@@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	/* must enumerate the adapter before use it */
 	ret = opae_adapter_enumerate(adapter);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	/* get opae_manager to rawdev */
 	mgr = opae_adapter_get_mgr(adapter);
 	if (mgr) {
-		/* PF function */
-		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
+		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
+				fme_interrupt_handler, "fme_irq", mgr);
+		if (ret)
+			goto cleanup;
 	}
 
-	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
-			fme_interrupt_handler, "fme_irq", mgr);
-	if (ret)
-		goto free_adapter_data;
-
 	ret = ifpga_monitor_start_func(dev);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	return ret;
 
-free_adapter_data:
-	if (data)
-		opae_adapter_data_free(data);
 cleanup:
 	if (rawdev)
 		rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 0/4] Support OFS card
  2022-05-17  6:28 ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Wei Huang
@ 2022-05-18  8:29   ` Wei Huang
  2022-05-18  8:29     ` [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
                       ` (4 more replies)
  2022-05-25  3:18   ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Zhang, Tianfei
  1 sibling, 5 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-18  8:29 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

The changes in version 2:
Fix build error in UB2004-32, replace "%zu" with "PRIu64".

Wei Huang (4):
  raw/ifpga: remove experimental tag from ifpga APIs
  raw/ifpga: remove vdev when ifpga is closed
  raw/ifpga: unregister interrupt in ifpga close function
  raw/ifpga: support ofs card probe

 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 678 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           | 241 ++++++----
 drivers/raw/ifpga/ifpga_rawdev.h           |   8 +
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  48 --
 drivers/raw/ifpga/version.map              |   7 +-
 11 files changed, 737 insertions(+), 298 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
@ 2022-05-18  8:29     ` Wei Huang
  2022-05-25  3:22       ` Zhang, Tianfei
  2022-05-18  8:29     ` [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-18  8:29 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

These APIs are introduced in DPDK 21.05 and have been tested in several
release, experimental tag can be formally removed.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
 drivers/raw/ifpga/version.map     |  7 ++----
 2 files changed, 2 insertions(+), 53 deletions(-)

diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 47d66ba..3fa5d34 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -68,9 +68,6 @@
 } rte_pmd_ifpga_phy_info;
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
  *
  * @param pci_addr
@@ -82,14 +79,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-ENODEV) if FPGA is not probed by ifpga driver.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -103,14 +96,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Set current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -124,14 +113,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get FPGA property of specified Intel FPGA device
  *
  * @param dev_id
@@ -144,14 +129,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PHY information of specified Intel FPGA device
  *
  * @param dev_id
@@ -164,14 +145,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Update image flash of specified Intel FPGA device
  *
  * @param dev_id
@@ -187,15 +164,11 @@
  *   - (-EBUSY) if FPGA is updating or rebooting.
  *   - (-EIO) if failed to open image file.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
 	uint64_t *status);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Stop flash update of specified Intel FPGA device
  *
  * @param dev_id
@@ -208,14 +181,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EAGAIN) if failed with force.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Check current Intel FPGA status and change it to reboot status if it is idle
  *
  * @param dev_id
@@ -226,14 +195,10 @@
  *   - (-ENOMEM) if share data is not initialized.
  *   - (-EBUSY) if FPGA is updating or rebooting.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reboot_try(uint16_t dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Trigger full reconfiguration of specified Intel FPGA device
  *
  * @param dev_id
@@ -252,28 +217,20 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PCI bus the Intel FPGA driver register to
  *
  * @return
  *   - (valid pointer) if successful.
  *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
  */
-__rte_experimental
 const struct rte_pci_bus *
 rte_pmd_ifpga_get_pci_bus(void);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Perform PR (partial reconfiguration) on specified Intel FPGA device
  *
  * @param dev_id
@@ -287,17 +244,12 @@
  *   - (-EINVAL) if bad parameter or operation failed.
  *   - (-ENOMEM) if failed to allocate memory.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Free software resources allocated by Intel FPGA PMD
  */
-__rte_experimental
 void
 rte_pmd_ifpga_cleanup(void);
 
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index a1a6be2..ff71a45 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -1,11 +1,6 @@
 DPDK_22 {
-	local: *;
-};
-
-EXPERIMENTAL {
 	global:
 
-	# added in 21.05
 	rte_pmd_ifpga_get_dev_id;
 	rte_pmd_ifpga_get_rsu_status;
 	rte_pmd_ifpga_set_rsu_status;
@@ -18,4 +13,6 @@ EXPERIMENTAL {
 	rte_pmd_ifpga_get_pci_bus;
 	rte_pmd_ifpga_partial_reconfigure;
 	rte_pmd_ifpga_cleanup;
+
+	local: *;
 };
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
  2022-05-18  8:29     ` [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-18  8:29     ` Wei Huang
  2022-05-25  4:09       ` Zhang, Tianfei
  2022-05-18  8:29     ` [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-18  8:29 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Virtual devices created on ifpga raw device are not removed when
ifpga is closed. To avoid such problem, ifpga virtual device remove
function is implemented, virtual device is removed in raw device
close function.

Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Acked-by: Rosen Xu <rosen.xu@intel.com>
---
 drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---------
 drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
 2 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 6d4117c..fe3fc43 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -134,6 +134,8 @@ struct ifpga_rawdev *
 	for (i = 0; i < IFPGA_MAX_IRQ; i++)
 		dev->intr_handle[i] = NULL;
 	dev->poll_enabled = 0;
+	for (i = 0; i < IFPGA_MAX_VDEV; i++)
+		dev->vdev_name[i] = NULL;
 
 	return dev;
 }
@@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(
 static int
 ifpga_rawdev_close(struct rte_rawdev *dev)
 {
+	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	char *vdev_name = NULL;
+	int i = 0;
 
 	if (dev) {
-		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
+		ifpga_rdev = ifpga_rawdev_get(dev);
+		if (ifpga_rdev) {
+			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+				vdev_name = ifpga_rdev->vdev_name[i];
+				if (vdev_name)
+					rte_vdev_uninit(vdev_name);
+			}
+			ifpga_monitor_stop_func(ifpga_rdev);
+			ifpga_rdev->rawdev = NULL;
+		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
 			opae_adapter_destroy(adapter);
@@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		return -EINVAL;
 	}
 	dev = ifpga_rawdev_get(rawdev);
-	if (dev)
-		dev->rawdev = NULL;
 
 	adapter = ifpga_rawdev_get_priv(rawdev);
 	if (!adapter)
@@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 
 	return 0;
 }
+
 static int
-ifpga_cfg_probe(struct rte_vdev_device *dev)
+ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
+	struct ifpga_vdev_args *args)
 {
-	struct rte_devargs *devargs;
-	struct rte_kvargs *kvlist = NULL;
-	struct rte_rawdev *rawdev = NULL;
-	struct ifpga_rawdev *ifpga_dev;
-	int port;
+	struct rte_kvargs *kvlist;
 	char *name = NULL;
-	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
-	int ret = -1;
+	int port = 0;
+	int ret = -EINVAL;
 
-	devargs = dev->device.devargs;
+	if (!devargs || !args)
+		return ret;
 
 	kvlist = rte_kvargs_parse(devargs->args, valid_args);
 	if (!kvlist) {
-		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
-		goto end;
+		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
+		return ret;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
 		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
-				       &ifpga_rawdev_get_string_arg,
-				       &name) < 0) {
+			&ifpga_rawdev_get_string_arg, &name) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
-				     IFPGA_ARG_NAME);
+				IFPGA_ARG_NAME);
 			goto end;
+		} else {
+			strlcpy(args->bdf, name, sizeof(args->bdf));
+			rte_free(name);
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_NAME);
+			IFPGA_ARG_NAME);
 		goto end;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
-		if (rte_kvargs_process(kvlist,
-			IFPGA_ARG_PORT,
-			&rte_ifpga_get_integer32_arg,
-			&port) < 0) {
+		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
+			&rte_ifpga_get_integer32_arg, &port) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
 				IFPGA_ARG_PORT);
 			goto end;
+		} else {
+			args->port = port;
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_PORT);
+			IFPGA_ARG_PORT);
 		goto end;
 	}
 
+	ret = 0;
+
+end:
+	if (kvlist)
+		rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+ifpga_cfg_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	int i, n, ret = 0;
+
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
 	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name);
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
 	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
 	if (!rawdev)
-		goto end;
+		return -ENODEV;
 	ifpga_dev = ifpga_rawdev_get(rawdev);
 	if (!ifpga_dev)
-		goto end;
+		return -ENODEV;
 
-	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
-	port, name);
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		if (ifpga_dev->vdev_name[i] == NULL) {
+			n = strlen(vdev_name) + 1;
+			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
+			if (ifpga_dev->vdev_name[i] == NULL)
+				return -ENOMEM;
+			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
+			break;
+		}
+	}
 
+	if (i >= IFPGA_MAX_VDEV) {
+		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
+		return -ENOENT;
+	}
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
 	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
-			dev_name, devargs->args);
-end:
-	rte_kvargs_free(kvlist);
-	free(name);
+			dev_name, vdev->device.devargs->args);
+	if (ret) {
+		rte_free(ifpga_dev->vdev_name[i]);
+		ifpga_dev->vdev_name[i] = NULL;
+	}
 
 	return ret;
 }
@@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 static int
 ifpga_cfg_remove(struct rte_vdev_device *vdev)
 {
-	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
-		vdev);
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	char *tmp_vdev = NULL;
+	int i, ret = 0;
 
-	return 0;
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
+	memset(dev_name, 0, sizeof(dev_name));
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
+	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
+	if (!rawdev)
+		return -ENODEV;
+	ifpga_dev = ifpga_rawdev_get(rawdev);
+	if (!ifpga_dev)
+		return -ENODEV;
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
+	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME), dev_name);
+
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		tmp_vdev = ifpga_dev->vdev_name[i];
+		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
+			free(tmp_vdev);
+			ifpga_dev->vdev_name[i] = NULL;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static struct rte_vdev_driver ifpga_cfg_driver = {
diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
index 857b734..eb9a9a5 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.h
+++ b/drivers/raw/ifpga/ifpga_rawdev.h
@@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
 
 #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
 #define IFPGA_RAWDEV_NUM 32
+#define IFPGA_MAX_VDEV 4
 #define IFPGA_MAX_IRQ 12
 
 struct ifpga_rawdev {
@@ -64,6 +65,13 @@ struct ifpga_rawdev {
 	void *intr_handle[IFPGA_MAX_IRQ];
 	/* enable monitor thread poll device's sensors or not */
 	int poll_enabled;
+	/* name of virtual devices created on raw device */
+	char *vdev_name[IFPGA_MAX_VDEV];
+};
+
+struct ifpga_vdev_args {
+	char bdf[8];
+	int port;
 };
 
 struct ifpga_rawdev *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
  2022-05-18  8:29     ` [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
  2022-05-18  8:29     ` [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-18  8:29     ` Wei Huang
  2022-05-25  3:26       ` Zhang, Tianfei
  2022-05-18  8:29     ` [PATCH v2 4/4] raw/ifpga: support ofs card probe Wei Huang
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
  4 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-18  8:29 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Move interrupt unregistration from ifpga destroy function to
ifpga close function, so rte_rawdev_pmd_release function can
release interrupt resource.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index fe3fc43..94df56c 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(
 static int ifpga_pci_find_next_ext_capability(unsigned int fd,
 					      int start, uint32_t cap);
 static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
+static void fme_interrupt_handler(void *param);
 
 struct ifpga_rawdev *
 ifpga_rawdev_get(const struct rte_rawdev *rawdev)
@@ -740,8 +741,9 @@ static int set_surprise_link_check_aer(
 {
 	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	struct opae_manager *mgr;
 	char *vdev_name = NULL;
-	int i = 0;
+	int i, ret = 0;
 
 	if (dev) {
 		ifpga_rdev = ifpga_rawdev_get(dev);
@@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
 		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
+			mgr = opae_adapter_get_mgr(adapter);
+			if (ifpga_rdev && mgr) {
+				if (ifpga_unregister_msix_irq(ifpga_rdev,
+					IFPGA_FME_IRQ, 0,
+					fme_interrupt_handler, mgr) < 0)
+					ret = -EINVAL;
+			}
 			opae_adapter_destroy(adapter);
 			opae_adapter_data_free(adapter->data);
 		}
 	}
 
-	return dev ? 0:1;
+	return ret;
 }
 
 static int
@@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	int ret;
 	struct rte_rawdev *rawdev;
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
-	struct opae_adapter *adapter;
-	struct opae_manager *mgr;
-	struct ifpga_rawdev *dev;
 
 	if (!pci_dev) {
 		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
@@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
 		return -EINVAL;
 	}
-	dev = ifpga_rawdev_get(rawdev);
-
-	adapter = ifpga_rawdev_get_priv(rawdev);
-	if (!adapter)
-		return -ENODEV;
-
-	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
-		return -ENODEV;
-
-	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
-				fme_interrupt_handler, mgr) < 0)
-		return -EINVAL;
 
 	/* rte_rawdev_close is called by pmd_release */
 	ret = rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 4/4] raw/ifpga: support ofs card probe
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
                       ` (2 preceding siblings ...)
  2022-05-18  8:29     ` [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-18  8:29     ` Wei Huang
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
  4 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-18  8:29 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

ofs card introduces some changes in DFL (Device Feature List) and
DFH (Device Feature Header) of FPGA. ifpga driver adapt these
changes mainly by adjusting enumeration process.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
v2: fix build error in UB2004-32
---
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 678 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
 8 files changed, 587 insertions(+), 192 deletions(-)

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index 4610ef1..f19cc26 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -13,15 +13,22 @@
 static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
 			      struct uuid *uuid)
 {
-	struct opae_bridge *br = acc->br;
-	struct ifpga_port_hw *port;
+	struct ifpga_afu_info *afu_info = acc->data;
+	struct opae_reg_region *region;
+	u64 val = 0;
 
-	if (!br || !br->data)
-		return -EINVAL;
+	if (!afu_info)
+		return -ENODEV;
 
-	port = br->data;
+	region = &afu_info->region[0];
+	if (uuid) {
+		val = readq(region->addr + sizeof(struct feature_header));
+		opae_memcpy(uuid->b, &val, sizeof(u64));
+		val = readq(region->addr + sizeof(struct feature_header) + 8);
+		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
+	}
 
-	return fpga_get_afu_uuid(port, uuid);
+	return 0;
 }
 
 static int ifpga_acc_set_irq(struct opae_accelerator *acc,
@@ -32,6 +39,9 @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
 	struct ifpga_port_hw *port;
 	struct fpga_uafu_irq_set irq_set;
 
+	if (!afu_info)
+		return -ENODEV;
+
 	if (!br || !br->data)
 		return -EINVAL;
 
@@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
 	struct ifpga_afu_info *afu_info = acc->data;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (info->index >= afu_info->num_regions)
 		return -EINVAL;
@@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
@@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h
index 8f62033..9a280eb 100644
--- a/drivers/raw/ifpga/base/ifpga_defines.h
+++ b/drivers/raw/ifpga/base/ifpga_defines.h
@@ -73,6 +73,7 @@
 enum fpga_id_type {
 	FME_ID,
 	PORT_ID,
+	AFU_ID,
 	FPGA_ID_MAX,
 };
 
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c b/drivers/raw/ifpga/base/ifpga_enumerate.c
index 48b8af4..8fa8273 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.c
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
@@ -2,6 +2,10 @@
  * Copyright(c) 2010-2018 Intel Corporation
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
 #include "opae_hw_api.h"
 #include "ifpga_api.h"
 
@@ -9,6 +13,19 @@
 #include "ifpga_enumerate.h"
 #include "ifpga_feature_dev.h"
 
+struct dfl_fpga_enum_dfl {
+	u64 start;
+	u64 len;
+	void *addr;
+	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
+};
+
+TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl);
+struct dfl_fpga_enum_info {
+	struct ifpga_hw *hw;
+	struct dfl_fpga_enum_dfls dfls;
+};
+
 struct build_feature_devs_info {
 	struct opae_adapter_data_pci *pci_data;
 
@@ -21,7 +38,6 @@ struct build_feature_devs_info {
 	void *ioaddr;
 	void *ioend;
 	uint64_t phys_addr;
-	int current_bar;
 
 	void *pfme_hdr;
 
@@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
 			unsigned int size, unsigned int vec_start,
 			unsigned int vec_cnt)
 {
-	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
-			vec_cnt);
+	if (binfo->current_type != AFU_ID)
+		return build_info_add_sub_feature(binfo, start, fid, size,
+			vec_start, vec_cnt);
+	return 0;
 }
 
 /*
@@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
  */
 static bool feature_is_UAFU(struct build_feature_devs_info *binfo)
 {
-	if (binfo->current_type != PORT_ID)
-		return false;
+	if ((binfo->current_type == PORT_ID) ||
+		(binfo->current_type == AFU_ID))
+		return true;
 
-	return true;
+	return false;
 }
 
-static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
+static int parse_feature_uafu(struct build_feature_devs_info *binfo,
 				   struct feature_header *hdr)
 {
 	u64 id = PORT_FEATURE_ID_UAFU;
@@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	int ret;
 	int size;
 
+	if (binfo->acc_info) {
+		dev_info(binfo, "Sub AFU found @ %p.\n", start);
+		return 0;
+	}
+
 	capability.csr = readq(&port_hdr->capability);
 
-	size = capability.mmio_size << 10;
+	if (binfo->current_type == AFU_ID) {
+		size = AFU_REGION_SIZE;
+	} else {
+		capability.csr = readq(&port_hdr->capability);
+		size = capability.mmio_size << 10;
+	}
 
 	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
 	if (ret)
@@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	info->region[0].phys_addr = binfo->phys_addr +
 			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
 	info->region[0].len = size;
-	info->num_regions = 1;
+	info->num_regions = AFU_MAX_REGION;
 
 	binfo->acc_info = info;
 
 	return ret;
 }
 
-static int parse_feature_afus(struct build_feature_devs_info *binfo,
-			      struct feature_header *hdr)
-{
-	int ret;
-	struct feature_afu_header *afu_hdr, header;
-	u8 __iomem *start;
-	u8 __iomem *end = binfo->ioend;
-
-	start = (u8 __iomem *)hdr;
-	for (; start < end; start += header.next_afu) {
-		if ((unsigned int)(end - start) <
-			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
-			return -EINVAL;
-
-		hdr = (struct feature_header *)start;
-		afu_hdr = (struct feature_afu_header *)(hdr + 1);
-		header.csr = readq(&afu_hdr->csr);
-
-		if (feature_is_UAFU(binfo)) {
-			ret = parse_feature_port_uafu(binfo, hdr);
-			if (ret)
-				return ret;
-		}
-
-		if (!header.next_afu)
-			break;
-	}
-
-	return 0;
-}
-
 /* create and register proper private data */
 static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
@@ -235,13 +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	struct ifpga_fme_hw *fme;
 	struct ifpga_feature *feature;
 
-	if (!binfo->fiu)
-		return 0;
-
 	if (binfo->current_type == PORT_ID) {
-		/* return error if no valid acc info data structure */
-		if (!info)
-			return -EFAULT;
+		if (!binfo->fiu)
+			return 0;
 
 		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
 				       binfo->fiu);
@@ -254,7 +248,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 		port = &hw->port[binfo->current_port_id];
 		feature = get_feature_by_id(&port->feature_list,
 				PORT_FEATURE_ID_UINT);
-		if (feature)
+		if (feature && info)
 			info->num_irqs = feature->vec_cnt;
 
 		acc = opae_accelerator_alloc(hw->adapter->name,
@@ -264,17 +258,21 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 			return -ENOMEM;
 		}
 
+		acc->adapter = hw->adapter;
 		acc->br = br;
 		if (hw->adapter->mgr)
 			acc->mgr = hw->adapter->mgr;
 		acc->index = br->id;
 
 		fme = &hw->fme;
-		fme->nums_acc_region = info->num_regions;
+		fme->nums_acc_region = info ? info->num_regions : 0;
 
 		opae_adapter_add_acc(hw->adapter, acc);
 
 	} else if (binfo->current_type == FME_ID) {
+		if (!binfo->fiu)
+			return 0;
+
 		mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,
 				&ifpga_mgr_network_ops, binfo->fiu);
 		if (!mgr)
@@ -282,6 +280,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 
 		mgr->adapter = hw->adapter;
 		hw->adapter->mgr = mgr;
+	} else if (binfo->current_type == AFU_ID) {
+		if (!info)
+			return -EFAULT;
+
+		info->num_irqs = 0;
+		acc = opae_accelerator_alloc(hw->adapter->name,
+					&ifpga_acc_ops, info);
+		if (!acc)
+			return -ENOMEM;
+
+		acc->adapter = hw->adapter;
+		acc->br = NULL;
+		acc->mgr = NULL;
+		acc->index = hw->num_afus++;
+
+		opae_adapter_add_acc(hw->adapter, acc);
 	}
 
 	binfo->fiu = NULL;
@@ -295,11 +309,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
 	int ret;
 
+	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
+		return 0;
+
 	ret = build_info_commit_dev(binfo);
 	if (ret)
 		return ret;
 
 	binfo->current_type = type;
+	binfo->acc_info = NULL;
 
 	if (type == FME_ID) {
 		binfo->fiu = &binfo->hw->fme;
@@ -311,6 +329,41 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	return 0;
 }
 
+static int parse_feature_afus(struct build_feature_devs_info *binfo,
+			      struct feature_header *hdr)
+{
+	int ret;
+	struct feature_afu_header *afu_hdr, header;
+	u8 __iomem *start;
+	u8 __iomem *end = binfo->ioend;
+
+	ret = build_info_create_dev(binfo, AFU_ID, 0);
+	if (ret)
+		return ret;
+
+	start = (u8 __iomem *)hdr;
+	for (; start < end; start += header.next_afu) {
+		if ((unsigned int)(end - start) <
+			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
+			return -EINVAL;
+
+		hdr = (struct feature_header *)start;
+		afu_hdr = (struct feature_afu_header *)(hdr + 1);
+		header.csr = readq(&afu_hdr->csr);
+
+		if (feature_is_UAFU(binfo)) {
+			ret = parse_feature_uafu(binfo, hdr);
+			if (ret)
+				return ret;
+		}
+
+		if (!header.next_afu)
+			break;
+	}
+
+	return 0;
+}
+
 static int parse_feature_fme(struct build_feature_devs_info *binfo,
 			     struct feature_header *start)
 {
@@ -405,7 +458,7 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 			if (ret)
 				return ret;
 		} else {
-			dev_info(binfo, "No AFUs detected on Port\n");
+			dev_info(binfo, "No AFU detected on Port\n");
 		}
 
 		break;
@@ -426,7 +479,7 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 
 	id = feature_id(start);
 
-	if (id == PORT_FEATURE_ID_UINT) {
+	if ((binfo->current_type == PORT_ID) && (id == PORT_FEATURE_ID_UINT)) {
 		struct feature_port_uint *port_uint = start;
 		struct feature_port_uint_cap uint_cap;
 
@@ -437,7 +490,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 		} else {
 			dev_debug(binfo, "UAFU doesn't support interrupt\n");
 		}
-	} else if (id == PORT_FEATURE_ID_ERROR) {
+	} else if ((binfo->current_type == PORT_ID) &&
+			(id == PORT_FEATURE_ID_ERROR)) {
 		struct feature_port_error *port_err = start;
 		struct feature_port_err_capability port_err_cap;
 
@@ -449,7 +503,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 			dev_debug(&binfo, "Port error doesn't support interrupt\n");
 		}
 
-	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
+	} else if ((binfo->current_type == FME_ID) &&
+			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
 		struct feature_fme_err *fme_err = start;
 		struct feature_fme_error_capability fme_err_cap;
 
@@ -497,9 +552,15 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
 		return parse_feature_fme_private(binfo, hdr);
 	case PORT_ID:
 		return parse_feature_port_private(binfo, hdr);
+	case AFU_ID:
+		dev_err(binfo, "private feature %x belonging to AFU "
+			"is not supported yet.\n", header.id);
+		break;
 	default:
-		dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n",
+		dev_err(binfo, "private feature %x belonging to TYPE %d "
+			"(unknown_type) is not supported yet.\n",
 			header.id, binfo->current_type);
+		break;
 	}
 	return 0;
 }
@@ -530,32 +591,57 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return ret;
 }
 
-static int
-parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
+static int build_info_prepare(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
 {
+	if (!binfo || !dfl)
+		return -EINVAL;
+
+	binfo->ioaddr = dfl->addr;
+	binfo->ioend = (u8 *)dfl->addr + dfl->len;
+	binfo->phys_addr = dfl->start;
+
+	return 0;
+}
+
+static int parse_feature_list(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
+{
+	u8 *start, *end;
 	struct feature_header *hdr, header;
-	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
 	int ret = 0;
 
+	ret = build_info_prepare(binfo, dfl);
+	if (ret)
+		return ret;
+
+	start = (u8 *)binfo->ioaddr;
+	end = (u8 *)binfo->ioend;
+
+	/* walk through the device feature list via DFH's next DFH pointer. */
 	for (; start < end; start += header.next_header_offset) {
 		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
-			dev_err(binfo, "The region is too small to contain a feature.\n");
-			ret =  -EINVAL;
+			dev_err(binfo, "The region is too small to "
+				"contain a feature.\n");
+			ret = -EINVAL;
 			break;
 		}
 
 		hdr = (struct feature_header *)start;
-		header.csr = readq(hdr);
+		header.csr = opae_readq(hdr);
 
-		dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n",
-			__func__, hdr, (unsigned long long)header.csr,
-			header.id, header.next_header_offset,
-			header.end_of_list, header.type);
+		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
+			"header.id=0x%x, header.next_offset=0x%x, "
+			"header.eol=0x%x, header.type=0x%x\n",
+			__func__, hdr, header.csr, header.id,
+			header.next_header_offset, header.end_of_list,
+			header.type);
 
 		ret = parse_feature(binfo, hdr);
 		if (ret)
 			return ret;
 
+		/* stop parsing if EOL(End of List) is set or offset is 0 */
 		if (header.end_of_list || !header.next_header_offset)
 			break;
 	}
@@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return build_info_commit_dev(binfo);
 }
 
-/* switch the memory mapping to BAR# @bar */
-static int parse_switch_to(struct build_feature_devs_info *binfo, int bar)
-{
-	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
-
-	if (!pci_data->region[bar].addr)
-		return -ENOMEM;
-
-	binfo->ioaddr = pci_data->region[bar].addr;
-	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len;
-	binfo->phys_addr = pci_data->region[bar].phys_addr;
-	binfo->current_bar = bar;
-
-	return 0;
-}
-
-static int parse_ports_from_fme(struct build_feature_devs_info *binfo)
-{
-	struct feature_fme_header *fme_hdr;
-	struct feature_fme_port port;
-	int i = 0, ret = 0;
-
-	if (!binfo->pfme_hdr) {
-		dev_info(binfo,  "VF is detected.\n");
-		return ret;
-	}
-
-	fme_hdr = binfo->pfme_hdr;
-
-	do {
-		port.csr = readq(&fme_hdr->port[i]);
-		if (!port.port_implemented)
-			break;
-
-		/* skip port which only could be accessed via VF */
-		if (port.afu_access_control == FME_AFU_ACCESS_VF)
-			continue;
-
-		ret = parse_switch_to(binfo, port.port_bar);
-		if (ret)
-			break;
-
-		ret = parse_feature_list(binfo,
-					 (u8 __iomem *)binfo->ioaddr +
-					  port.port_offset);
-		if (ret)
-			break;
-	} while (++i < MAX_FPGA_PORT_NUM);
-
-	return ret;
-}
-
-static struct build_feature_devs_info *
-build_info_alloc_and_init(struct ifpga_hw *hw)
-{
-	struct build_feature_devs_info *binfo;
-
-	binfo = zmalloc(sizeof(*binfo));
-	if (!binfo)
-		return binfo;
-
-	binfo->hw = hw;
-	binfo->pci_data = hw->pci_data;
-
-	/* fpga feature list starts from BAR 0 */
-	if (parse_switch_to(binfo, 0)) {
-		free(binfo);
-		return NULL;
-	}
-
-	return binfo;
-}
-
 static void build_info_free(struct build_feature_devs_info *binfo)
 {
-	free(binfo);
+	opae_free(binfo);
 }
 
 static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
@@ -648,6 +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	struct ifpga_feature *feature;
 	int i;
 
+	if (fme->state == IFPGA_FME_UNUSED) {
+		dev_info(hw, "FME is not present\n");
+		return;
+	}
+
 	dev_info(hw, "found fme_device, is in PF: %s\n",
 		 is_ifpga_hw_pf(hw) ? "yes" : "no");
 
@@ -685,40 +703,408 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	}
 }
 
-int ifpga_bus_enumerate(struct ifpga_hw *hw)
+static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct ifpga_hw *hw)
 {
-	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_info *info;
+
+	info = opae_zmalloc(sizeof(*info));
+	if (!info)
+		return NULL;
+
+	info->hw = hw;
+	TAILQ_INIT(&info->dfls);
+
+	return info;
+}
+
+static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
+{
+	struct dfl_fpga_enum_dfl *tmp, *dfl;
+
+	if (!info)
+		return;
+
+	/* remove all device feature lists in the list. */
+	for (dfl = TAILQ_FIRST(&info->dfls);
+		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
+		dfl = tmp) {
+		TAILQ_REMOVE(&info->dfls, dfl, node);
+		opae_free(dfl);
+	}
+
+	opae_free(info);
+}
+
+static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
+	u64 start, u64 len, void *addr)
+{
+	struct dfl_fpga_enum_dfl *dfl;
+
+	dfl = opae_zmalloc(sizeof(*dfl));
+	if (!dfl)
+		return -ENOMEM;
+
+	dfl->start = start;
+	dfl->len = len;
+	dfl->addr = addr;
+
+	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
+
+	return 0;
+}
+
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+static int
+pci_find_next_ecap(int fd, int start, u32 cap)
+{
+	u32 header;
+	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+	int pos = PCI_CFG_SPACE_SIZE;
 	int ret;
 
-	binfo = build_info_alloc_and_init(hw);
+	if (start > 0)
+		pos = start;
+
+	ret = pread(fd, &header, sizeof(header), pos);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+		ret = pread(fd, &header, sizeof(header), pos);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PCI_EXT_CAP_ID_VNDR	0x0B
+#define PCI_VNDR_HEADER		4
+#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VSEC_ID_INTEL_DFLS 0x43
+#define PCI_VNDR_DFLS_CNT 0x8
+#define PCI_VNDR_DFLS_RES 0xc
+#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
+#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
+
+static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	char path[64];
+	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
+	int fd, ret, dfl_res_off, voff = 0;
+	u64 start, len;
+	void *addr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->adapter || !hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
+			hw->adapter->name);
+	if ((unsigned int)ret >= sizeof(path))
+		return -EINVAL;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -EIO;
+
+	while ((voff = pci_find_next_ecap(fd, voff,
+		PCI_EXT_CAP_ID_VNDR))) {
+		vndr_hdr = 0;
+		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
+			voff + PCI_VNDR_HEADER);
+		if (ret < 0)
+			return -EIO;
+		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
+			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
+			break;
+	}
+
+	if (!voff) {
+		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
+		return -ENODEV;
+	}
+
+	dfl_cnt = 0;
+	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
+	if (ret < 0)
+		return -EIO;
+
+	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
+	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
+		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
+		dfl_res = GENMASK(31, 0);
+		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
+		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
+		if (bir >= PCI_MAX_RESOURCE) {
+			dev_err(hw, "%s bad bir number %d\n",
+				__func__, bir);
+			return -EINVAL;
+		}
+
+		len = pci_data->region[bir].len;
+		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
+		if (offset >= len) {
+			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
+				__func__, offset, len);
+			return -EINVAL;
+		}
+
+		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
+		len -= offset;
+		start = pci_data->region[bir].phys_addr + offset;
+		addr = pci_data->region[bir].addr + offset;
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	}
+
+	return 0;
+}
+
+/* default method of finding dfls starting at offset 0 of bar 0 */
+static int
+find_dfls_by_default(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	int port_num, bar, i, ret = 0;
+	u64 start, len;
+	void *addr;
+	u32 offset;
+	struct feature_header hdr;
+	struct feature_fme_capability cap;
+	struct feature_fme_port port;
+	struct feature_fme_header *fme_hdr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	/* start to find Device Feature List from Bar 0 */
+	addr = pci_data->region[0].addr;
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * PF device has FME and Ports/AFUs, and VF device only has one
+	 * Port/AFU. Check them and add related "Device Feature List" info
+	 * for the next step enumeration.
+	 */
+	hdr.csr = opae_readq(addr);
+	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id == FEATURE_FIU_ID_FME)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+
+		/*
+		 * find more Device Feature Lists (e.g. Ports) per information
+		 * indicated by FME module.
+		 */
+		fme_hdr = (struct feature_fme_header *)addr;
+		cap.csr = opae_readq(&fme_hdr->capability);
+		port_num = (int)cap.num_ports;
+
+		dev_info(hw, "port_num = %d\n", port_num);
+		if (port_num > MAX_FPGA_PORT_NUM)
+			port_num = MAX_FPGA_PORT_NUM;
+
+		for (i = 0; i < port_num; i++) {
+			port.csr = opae_readq(&fme_hdr->port[i]);
+
+			/* skip ports which are not implemented. */
+			if (!port.port_implemented)
+				continue;
+
+			/* skip port which only could be accessed via VF */
+			if (port.afu_access_control == FME_AFU_ACCESS_VF)
+				continue;
+
+			/*
+			 * add Port's Device Feature List information for next
+			 * step enumeration.
+			 */
+			bar = (int)port.port_bar;
+			offset = port.port_offset;
+			if (bar >= PCI_MAX_RESOURCE) {
+				dev_info(hw, "skipping BAR %d\n", bar);
+				continue;
+			} else {
+				dev_info(hw, "BAR %d offset %u\n", bar, offset);
+			}
+
+			len = pci_data->region[bar].len;
+			if (offset >= len) {
+				dev_warn(hw, "bad port offset %u >= %pa\n",
+					 offset, &len);
+				continue;
+			}
+
+			len -= offset;
+			start = pci_data->region[bar].phys_addr + offset;
+			addr = pci_data->region[bar].addr + offset;
+			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+		}
+	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
+		(hdr.id == FEATURE_FIU_ID_PORT)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else if (hdr.type == FEATURE_TYPE_AFU) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else {
+		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
+			 hdr.type, hdr.id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
+{
+	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_dfl *dfl;
+	int ret = 0;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+
+	/* create and init build info for enumeration */
+	binfo = opae_zmalloc(sizeof(*binfo));
 	if (!binfo)
 		return -ENOMEM;
 
-	ret = parse_feature_list(binfo, binfo->ioaddr);
+	binfo->hw = info->hw;
+	binfo->pci_data = info->hw->pci_data;
+
+	/*
+	 * start enumeration for all feature devices based on Device Feature
+	 * Lists.
+	 */
+	TAILQ_FOREACH(dfl, &info->dfls, node) {
+		ret = parse_feature_list(binfo, dfl);
+		if (ret)
+			break;
+	}
+
+	build_info_free(binfo);
+
+	return ret;
+}
+
+int ifpga_bus_enumerate(struct ifpga_hw *hw)
+{
+	struct dfl_fpga_enum_info *info;
+	int ret;
+
+	/* allocate enumeration info */
+	info = dfl_fpga_enum_info_alloc(hw);
+	if (!info)
+		return -ENOMEM;
+
+	ret = find_dfls_by_vsec(info);
+	if (ret < 0)
+		ret = find_dfls_by_default(info);
+
 	if (ret)
 		goto exit;
 
-	ret = parse_ports_from_fme(binfo);
-	if (ret)
+	/* start enumeration with prepared enumeration information */
+	ret = dfl_fpga_feature_devs_enumerate(info);
+	if (ret < 0) {
+		dev_err(hw, "Enumeration failure\n");
 		goto exit;
+	}
 
 	ifpga_print_device_feature_list(hw);
 
 exit:
-	build_info_free(binfo);
+	dfl_fpga_enum_info_free(info);
+
 	return ret;
 }
 
-int ifpga_bus_init(struct ifpga_hw *hw)
+static void ifpga_print_acc_list(struct opae_adapter *adapter)
 {
+	struct opae_accelerator *acc;
+	struct ifpga_afu_info *info;
+	struct uuid guid;
+	char buf[48];
 	int i;
+
+	opae_adapter_for_each_acc(adapter, acc) {
+		info = acc->data;
+		if (!info)
+			continue;
+		acc->ops->get_uuid(acc, &guid);
+		i = sprintf(buf, "%02x%02x%02x%02x-",
+			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
+		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
+			guid.b[5], guid.b[4], guid.b[3],
+			guid.b[2], guid.b[1], guid.b[0]);
+		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
+			acc->name, acc->index, info->region[0].addr,
+			info->region[0].len, buf);
+	}
+}
+
+int ifpga_bus_init(struct ifpga_hw *hw)
+{
+	int i, ret = 0;
 	struct ifpga_port_hw *port;
 
-	fme_hw_init(&hw->fme);
+	ret = fme_hw_init(&hw->fme);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
 		port = &hw->port[i];
 		port_hw_init(port);
 	}
+	ifpga_print_acc_list(hw->adapter);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c
index 0813513..dbecc7b 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
@@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
 	if (fpga_wait_register_field(port_sftrst_ack, control,
 				     &port_hdr->control, RST_POLL_TIMEOUT,
 				     RST_POLL_INVL)) {
-		dev_err(port, "timeout, fail to reset device\n");
+		dev_err(port, "timeout, fail to reset FIM port\n");
 		return -ETIMEDOUT;
 	}
 
@@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list *list)
 	struct ifpga_feature *feature;
 
 	TAILQ_FOREACH(feature, list, next) {
-		if (feature->state != IFPGA_FEATURE_ATTACHED)
+		if (feature->state != IFPGA_FEATURE_INITED)
 			continue;
 		if (feature->ops && feature->ops->uinit)
 			feature->ops->uinit(feature);
+		feature->state = IFPGA_FEATURE_ATTACHED;
 	}
 }
 
@@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
 					ret = feature->ops->init(feature);
 					if (ret)
 						goto error;
+					else
+						feature->state =
+							IFPGA_FEATURE_INITED;
 				}
 			}
 		}
@@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
 
 int fme_hw_init(struct ifpga_fme_hw *fme)
 {
-	int ret;
-
-	if (fme->state != IFPGA_FME_IMPLEMENTED)
-		return -ENODEV;
-
-	ret = feature_init(fme_feature_drvs, &fme->feature_list);
-	if (ret)
-		return ret;
+	if (fme->state == IFPGA_FME_IMPLEMENTED)
+		return feature_init(fme_feature_drvs, &fme->feature_list);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h
index ed5edc6..4d56deb 100644
--- a/drivers/raw/ifpga/base/ifpga_hw.h
+++ b/drivers/raw/ifpga/base/ifpga_hw.h
@@ -15,6 +15,7 @@
 enum ifpga_feature_state {
 	IFPGA_FEATURE_UNUSED = 0,
 	IFPGA_FEATURE_ATTACHED,
+	IFPGA_FEATURE_INITED
 };
 
 enum feature_type {
@@ -134,6 +135,7 @@ struct ifpga_hw {
 
 	struct ifpga_fme_hw fme;
 	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
+	int num_afus;
 };
 
 static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 11c9887..87256fc 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator *acc,
 int opae_acc_set_irq(struct opae_accelerator *acc,
 		     u32 start, u32 count, s32 evtfds[])
 {
-	if (!acc || !acc->data)
+	if (!acc)
 		return -EINVAL;
 
 	if (start + count <= start)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 7e04b56..fd40e09 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -143,6 +143,7 @@ struct opae_accelerator {
 	TAILQ_ENTRY(opae_accelerator) node;
 	const char *name;
 	int index;
+	struct opae_adapter *adapter;
 	struct opae_bridge *br;
 	struct opae_manager *mgr;
 	struct opae_accelerator_ops *ops;
@@ -240,6 +241,7 @@ struct opae_adapter_data {
 
 struct opae_reg_region {
 	u64 phys_addr;
+#define AFU_REGION_SIZE  0x8000
 	u64 len;
 	u8 *addr;
 };
diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 94df56c..ceb18ae 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -47,11 +47,13 @@
 #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
 #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
 #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
+#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
 /* VF Device */
 #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
 #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
 #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
 #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
+#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
 #define RTE_MAX_RAW_DEVICE           10
 
 static const struct rte_pci_id pci_ifpga_map[] = {
@@ -63,6 +65,8 @@
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),},
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N6000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N6000),},
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -110,6 +114,7 @@ struct ifpga_rawdev *
 
 	return IFPGA_RAWDEV_NUM;
 }
+
 static struct ifpga_rawdev *
 ifpga_rawdev_allocate(struct rte_rawdev *rawdev)
 {
@@ -365,7 +370,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 		return -ENODEV;
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
+	if (!mgr || !mgr->sensor_list)
 		return -ENODEV;
 
 	opae_mgr_for_each_sensor(mgr, sensor) {
@@ -377,7 +382,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 			goto fail;
 
 		if (value == 0xdeadbeef) {
-			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value %x\n",
+			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s value %x\n",
 					raw_dev->dev_id, sensor->name, value);
 			continue;
 		}
@@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(
 {
 	struct opae_adapter *adapter;
 	struct opae_manager *mgr;
-	struct opae_board_info *info;
+	struct opae_board_info *info = NULL;
 	struct rte_afu_pr_conf *afu_pr_conf;
 	int ret;
 	struct uuid uuid;
@@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
 	}
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr) {
-		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL");
-		return -1;
-	}
-
-	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
-		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
-		return -1;
+	if (mgr) {
+		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
+			IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
+			return -1;
+		}
 	}
 
-	if (info->lightweight) {
+	if (info && info->lightweight) {
 		/* set uuid to all 0, when fpga is lightweight image */
 		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
 		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
@@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
 			__func__,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
-		}
+	}
 	return 0;
 }
 
@@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
 	if (ret) {
 		ret = -ENOMEM;
-		goto free_adapter_data;
+		goto cleanup;
 	}
 
 	rawdev->dev_ops = &ifpga_rawdev_ops;
@@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	/* must enumerate the adapter before use it */
 	ret = opae_adapter_enumerate(adapter);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	/* get opae_manager to rawdev */
 	mgr = opae_adapter_get_mgr(adapter);
 	if (mgr) {
-		/* PF function */
-		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
+		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
+				fme_interrupt_handler, "fme_irq", mgr);
+		if (ret)
+			goto cleanup;
 	}
 
-	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
-			fme_interrupt_handler, "fme_irq", mgr);
-	if (ret)
-		goto free_adapter_data;
-
 	ret = ifpga_monitor_start_func(dev);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	return ret;
 
-free_adapter_data:
-	if (data)
-		opae_adapter_data_free(data);
 cleanup:
 	if (rawdev)
 		rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v1 4/4] raw/ifpga: support ofs card probe
  2022-05-17  6:28 ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Wei Huang
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
@ 2022-05-25  3:18   ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-25  3:18 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Tuesday, May 17, 2022 2:29 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v1 4/4] raw/ifpga: support ofs card probe
> 
> ofs card introduces some changes in DFL (Device Feature List) and DFH (Device
> Feature Header) of FPGA. ifpga driver adapt these changes mainly by adjusting
> enumeration process.

Would you like add more explanation about OFS in git commit?

> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>

It is better that you can add Acked Tag after I acked in maillist.

> ---
>  drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
>  drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
>  drivers/raw/ifpga/base/ifpga_enumerate.c   | 678 ++++++++++++++++++++++--
> -----
>  drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
>  drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
>  drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
>  drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
>  drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
>  8 files changed, 587 insertions(+), 192 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_api.c
> b/drivers/raw/ifpga/base/ifpga_api.c
> index 4610ef1..f19cc26 100644
> --- a/drivers/raw/ifpga/base/ifpga_api.c
> +++ b/drivers/raw/ifpga/base/ifpga_api.c
> @@ -13,15 +13,22 @@
>  static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
>  			      struct uuid *uuid)
>  {
> -	struct opae_bridge *br = acc->br;
> -	struct ifpga_port_hw *port;
> +	struct ifpga_afu_info *afu_info = acc->data;
> +	struct opae_reg_region *region;
> +	u64 val = 0;
> 
> -	if (!br || !br->data)
> -		return -EINVAL;
> +	if (!afu_info)
> +		return -ENODEV;
> 
> -	port = br->data;
> +	region = &afu_info->region[0];
> +	if (uuid) {
> +		val = readq(region->addr + sizeof(struct feature_header));
> +		opae_memcpy(uuid->b, &val, sizeof(u64));
> +		val = readq(region->addr + sizeof(struct feature_header) + 8);
> +		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
> +	}
> 
> -	return fpga_get_afu_uuid(port, uuid);
> +	return 0;
>  }
> 
>  static int ifpga_acc_set_irq(struct opae_accelerator *acc, @@ -32,6 +39,9 @@
> static int ifpga_acc_set_irq(struct opae_accelerator *acc,
>  	struct ifpga_port_hw *port;
>  	struct fpga_uafu_irq_set irq_set;
> 
> +	if (!afu_info)
> +		return -ENODEV;
> +
>  	if (!br || !br->data)
>  		return -EINVAL;
> 
> @@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct
> opae_accelerator *acc,
>  	struct ifpga_afu_info *afu_info = acc->data;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (info->index >= afu_info->num_regions)
>  		return -EINVAL;
> @@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc,
> unsigned int region_idx,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> @@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> diff --git a/drivers/raw/ifpga/base/ifpga_defines.h
> b/drivers/raw/ifpga/base/ifpga_defines.h
> index 8f62033..9a280eb 100644
> --- a/drivers/raw/ifpga/base/ifpga_defines.h
> +++ b/drivers/raw/ifpga/base/ifpga_defines.h
> @@ -73,6 +73,7 @@
>  enum fpga_id_type {
>  	FME_ID,
>  	PORT_ID,
> +	AFU_ID,
>  	FPGA_ID_MAX,
>  };
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c
> b/drivers/raw/ifpga/base/ifpga_enumerate.c
> index 48b8af4..257e609 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.c
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
> @@ -2,6 +2,10 @@
>   * Copyright(c) 2010-2018 Intel Corporation
>   */
> 
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <unistd.h>
> +
>  #include "opae_hw_api.h"
>  #include "ifpga_api.h"
> 
> @@ -9,6 +13,19 @@
>  #include "ifpga_enumerate.h"
>  #include "ifpga_feature_dev.h"
> 
> +struct dfl_fpga_enum_dfl {
> +	u64 start;
> +	u64 len;
> +	void *addr;
> +	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
> +};
> +
> +TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl); struct
> +dfl_fpga_enum_info {
> +	struct ifpga_hw *hw;
> +	struct dfl_fpga_enum_dfls dfls;
> +};
> +
>  struct build_feature_devs_info {
>  	struct opae_adapter_data_pci *pci_data;
> 
> @@ -21,7 +38,6 @@ struct build_feature_devs_info {
>  	void *ioaddr;
>  	void *ioend;
>  	uint64_t phys_addr;
> -	int current_bar;
> 
>  	void *pfme_hdr;
> 
> @@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
>  			unsigned int size, unsigned int vec_start,
>  			unsigned int vec_cnt)
>  {
> -	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
> -			vec_cnt);
> +	if (binfo->current_type != AFU_ID)
> +		return build_info_add_sub_feature(binfo, start, fid, size,
> +			vec_start, vec_cnt);
> +	return 0;
>  }
> 
>  /*
> @@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
>   */
>  static bool feature_is_UAFU(struct build_feature_devs_info *binfo)  {
> -	if (binfo->current_type != PORT_ID)
> -		return false;
> +	if ((binfo->current_type == PORT_ID) ||
> +		(binfo->current_type == AFU_ID))
> +		return true;
> 
> -	return true;
> +	return false;
>  }
> 
> -static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
> +static int parse_feature_uafu(struct build_feature_devs_info *binfo,
>  				   struct feature_header *hdr)
>  {
>  	u64 id = PORT_FEATURE_ID_UAFU;
> @@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	int ret;
>  	int size;
> 
> +	if (binfo->acc_info) {
> +		dev_info(binfo, "Sub AFU found @ %p.\n", start);
> +		return 0;
> +	}
> +
>  	capability.csr = readq(&port_hdr->capability);
> 
> -	size = capability.mmio_size << 10;
> +	if (binfo->current_type == AFU_ID) {
> +		size = AFU_REGION_SIZE;
> +	} else {
> +		capability.csr = readq(&port_hdr->capability);
> +		size = capability.mmio_size << 10;
> +	}
> 
>  	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
>  	if (ret)
> @@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	info->region[0].phys_addr = binfo->phys_addr +
>  			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
>  	info->region[0].len = size;
> -	info->num_regions = 1;
> +	info->num_regions = AFU_MAX_REGION;
> 
>  	binfo->acc_info = info;
> 
>  	return ret;
>  }
> 
> -static int parse_feature_afus(struct build_feature_devs_info *binfo,
> -			      struct feature_header *hdr)
> -{
> -	int ret;
> -	struct feature_afu_header *afu_hdr, header;
> -	u8 __iomem *start;
> -	u8 __iomem *end = binfo->ioend;
> -
> -	start = (u8 __iomem *)hdr;
> -	for (; start < end; start += header.next_afu) {
> -		if ((unsigned int)(end - start) <
> -			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> -			return -EINVAL;
> -
> -		hdr = (struct feature_header *)start;
> -		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> -		header.csr = readq(&afu_hdr->csr);
> -
> -		if (feature_is_UAFU(binfo)) {
> -			ret = parse_feature_port_uafu(binfo, hdr);
> -			if (ret)
> -				return ret;
> -		}
> -
> -		if (!header.next_afu)
> -			break;
> -	}
> -
> -	return 0;
> -}
> -
>  /* create and register proper private data */  static int
> build_info_commit_dev(struct build_feature_devs_info *binfo)  { @@ -235,13
> +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info
> *binfo)
>  	struct ifpga_fme_hw *fme;
>  	struct ifpga_feature *feature;
> 
> -	if (!binfo->fiu)
> -		return 0;
> -
>  	if (binfo->current_type == PORT_ID) {
> -		/* return error if no valid acc info data structure */
> -		if (!info)
> -			return -EFAULT;
> +		if (!binfo->fiu)
> +			return 0;
> 
>  		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
>  				       binfo->fiu);
> @@ -254,7 +248,7 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  		port = &hw->port[binfo->current_port_id];
>  		feature = get_feature_by_id(&port->feature_list,
>  				PORT_FEATURE_ID_UINT);
> -		if (feature)
> +		if (feature && info)
>  			info->num_irqs = feature->vec_cnt;
> 
>  		acc = opae_accelerator_alloc(hw->adapter->name,
> @@ -264,17 +258,21 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  			return -ENOMEM;
>  		}
> 
> +		acc->adapter = hw->adapter;
>  		acc->br = br;
>  		if (hw->adapter->mgr)
>  			acc->mgr = hw->adapter->mgr;
>  		acc->index = br->id;
> 
>  		fme = &hw->fme;
> -		fme->nums_acc_region = info->num_regions;
> +		fme->nums_acc_region = info ? info->num_regions : 0;
> 
>  		opae_adapter_add_acc(hw->adapter, acc);
> 
>  	} else if (binfo->current_type == FME_ID) {
> +		if (!binfo->fiu)
> +			return 0;
> +
>  		mgr = opae_manager_alloc(hw->adapter->name,
> &ifpga_mgr_ops,
>  				&ifpga_mgr_network_ops, binfo->fiu);
>  		if (!mgr)
> @@ -282,6 +280,22 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
> 
>  		mgr->adapter = hw->adapter;
>  		hw->adapter->mgr = mgr;
> +	} else if (binfo->current_type == AFU_ID) {
> +		if (!info)
> +			return -EFAULT;
> +
> +		info->num_irqs = 0;
> +		acc = opae_accelerator_alloc(hw->adapter->name,
> +					&ifpga_acc_ops, info);
> +		if (!acc)
> +			return -ENOMEM;
> +
> +		acc->adapter = hw->adapter;
> +		acc->br = NULL;
> +		acc->mgr = NULL;
> +		acc->index = hw->num_afus++;
> +
> +		opae_adapter_add_acc(hw->adapter, acc);
>  	}
> 
>  	binfo->fiu = NULL;
> @@ -295,11 +309,15 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)  {
>  	int ret;
> 
> +	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
> +		return 0;
> +
>  	ret = build_info_commit_dev(binfo);
>  	if (ret)
>  		return ret;
> 
>  	binfo->current_type = type;
> +	binfo->acc_info = NULL;
> 
>  	if (type == FME_ID) {
>  		binfo->fiu = &binfo->hw->fme;
> @@ -311,6 +329,41 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	return 0;
>  }
> 
> +static int parse_feature_afus(struct build_feature_devs_info *binfo,
> +			      struct feature_header *hdr)
> +{
> +	int ret;
> +	struct feature_afu_header *afu_hdr, header;
> +	u8 __iomem *start;
> +	u8 __iomem *end = binfo->ioend;
> +
> +	ret = build_info_create_dev(binfo, AFU_ID, 0);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 __iomem *)hdr;
> +	for (; start < end; start += header.next_afu) {
> +		if ((unsigned int)(end - start) <
> +			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> +			return -EINVAL;
> +
> +		hdr = (struct feature_header *)start;
> +		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> +		header.csr = readq(&afu_hdr->csr);
> +
> +		if (feature_is_UAFU(binfo)) {
> +			ret = parse_feature_uafu(binfo, hdr);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (!header.next_afu)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
>  static int parse_feature_fme(struct build_feature_devs_info *binfo,
>  			     struct feature_header *start)
>  {
> @@ -405,7 +458,7 @@ static int parse_feature_fiu(struct
> build_feature_devs_info *binfo,
>  			if (ret)
>  				return ret;
>  		} else {
> -			dev_info(binfo, "No AFUs detected on Port\n");
> +			dev_info(binfo, "No AFU detected on Port\n");
>  		}
> 
>  		break;
> @@ -426,7 +479,7 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
> 
>  	id = feature_id(start);
> 
> -	if (id == PORT_FEATURE_ID_UINT) {
> +	if ((binfo->current_type == PORT_ID) && (id ==
> PORT_FEATURE_ID_UINT))
> +{
>  		struct feature_port_uint *port_uint = start;
>  		struct feature_port_uint_cap uint_cap;
> 
> @@ -437,7 +490,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  		} else {
>  			dev_debug(binfo, "UAFU doesn't support interrupt\n");
>  		}
> -	} else if (id == PORT_FEATURE_ID_ERROR) {
> +	} else if ((binfo->current_type == PORT_ID) &&
> +			(id == PORT_FEATURE_ID_ERROR)) {
>  		struct feature_port_error *port_err = start;
>  		struct feature_port_err_capability port_err_cap;
> 
> @@ -449,7 +503,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  			dev_debug(&binfo, "Port error doesn't support
> interrupt\n");
>  		}
> 
> -	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
> +	} else if ((binfo->current_type == FME_ID) &&
> +			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
>  		struct feature_fme_err *fme_err = start;
>  		struct feature_fme_error_capability fme_err_cap;
> 
> @@ -497,9 +552,15 @@ static int parse_feature_private(struct
> build_feature_devs_info *binfo,
>  		return parse_feature_fme_private(binfo, hdr);
>  	case PORT_ID:
>  		return parse_feature_port_private(binfo, hdr);
> +	case AFU_ID:
> +		dev_err(binfo, "private feature %x belonging to AFU "
> +			"is not supported yet.\n", header.id);
> +		break;
>  	default:
> -		dev_err(binfo, "private feature %x belonging to AFU %d
> (unknown_type) is not supported yet.\n",
> +		dev_err(binfo, "private feature %x belonging to TYPE %d "
> +			"(unknown_type) is not supported yet.\n",
>  			header.id, binfo->current_type);
> +		break;
>  	}
>  	return 0;
>  }
> @@ -530,32 +591,57 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return ret;
>  }
> 
> -static int
> -parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
> +static int build_info_prepare(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
>  {
> +	if (!binfo || !dfl)
> +		return -EINVAL;
> +
> +	binfo->ioaddr = dfl->addr;
> +	binfo->ioend = (u8 *)dfl->addr + dfl->len;
> +	binfo->phys_addr = dfl->start;
> +
> +	return 0;
> +}
> +
> +static int parse_feature_list(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
> +{
> +	u8 *start, *end;
>  	struct feature_header *hdr, header;
> -	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
>  	int ret = 0;
> 
> +	ret = build_info_prepare(binfo, dfl);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 *)binfo->ioaddr;
> +	end = (u8 *)binfo->ioend;
> +
> +	/* walk through the device feature list via DFH's next DFH pointer. */
>  	for (; start < end; start += header.next_header_offset) {
>  		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
> -			dev_err(binfo, "The region is too small to contain a
> feature.\n");
> -			ret =  -EINVAL;
> +			dev_err(binfo, "The region is too small to "
> +				"contain a feature.\n");
> +			ret = -EINVAL;
>  			break;
>  		}
> 
>  		hdr = (struct feature_header *)start;
> -		header.csr = readq(hdr);
> +		header.csr = opae_readq(hdr);
> 
> -		dev_debug(binfo, "%s: address=0x%p, val=0x%llx,
> header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x,
> header.type=0x%x\n",
> -			__func__, hdr, (unsigned long long)header.csr,
> -			header.id, header.next_header_offset,
> -			header.end_of_list, header.type);
> +		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
> +			"header.id=0x%x, header.next_offset=0x%x, "
> +			"header.eol=0x%x, header.type=0x%x\n",
> +			__func__, hdr, header.csr, header.id,
> +			header.next_header_offset, header.end_of_list,
> +			header.type);
> 
>  		ret = parse_feature(binfo, hdr);
>  		if (ret)
>  			return ret;
> 
> +		/* stop parsing if EOL(End of List) is set or offset is 0 */
>  		if (header.end_of_list || !header.next_header_offset)
>  			break;
>  	}
> @@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info
> *binfo,
>  	return build_info_commit_dev(binfo);
>  }
> 
> -/* switch the memory mapping to BAR# @bar */ -static int
> parse_switch_to(struct build_feature_devs_info *binfo, int bar) -{
> -	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
> -
> -	if (!pci_data->region[bar].addr)
> -		return -ENOMEM;
> -
> -	binfo->ioaddr = pci_data->region[bar].addr;
> -	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data-
> >region[bar].len;
> -	binfo->phys_addr = pci_data->region[bar].phys_addr;
> -	binfo->current_bar = bar;
> -
> -	return 0;
> -}
> -
> -static int parse_ports_from_fme(struct build_feature_devs_info *binfo) -{
> -	struct feature_fme_header *fme_hdr;
> -	struct feature_fme_port port;
> -	int i = 0, ret = 0;
> -
> -	if (!binfo->pfme_hdr) {
> -		dev_info(binfo,  "VF is detected.\n");
> -		return ret;
> -	}
> -
> -	fme_hdr = binfo->pfme_hdr;
> -
> -	do {
> -		port.csr = readq(&fme_hdr->port[i]);
> -		if (!port.port_implemented)
> -			break;
> -
> -		/* skip port which only could be accessed via VF */
> -		if (port.afu_access_control == FME_AFU_ACCESS_VF)
> -			continue;
> -
> -		ret = parse_switch_to(binfo, port.port_bar);
> -		if (ret)
> -			break;
> -
> -		ret = parse_feature_list(binfo,
> -					 (u8 __iomem *)binfo->ioaddr +
> -					  port.port_offset);
> -		if (ret)
> -			break;
> -	} while (++i < MAX_FPGA_PORT_NUM);
> -
> -	return ret;
> -}
> -
> -static struct build_feature_devs_info * -build_info_alloc_and_init(struct
> ifpga_hw *hw) -{
> -	struct build_feature_devs_info *binfo;
> -
> -	binfo = zmalloc(sizeof(*binfo));
> -	if (!binfo)
> -		return binfo;
> -
> -	binfo->hw = hw;
> -	binfo->pci_data = hw->pci_data;
> -
> -	/* fpga feature list starts from BAR 0 */
> -	if (parse_switch_to(binfo, 0)) {
> -		free(binfo);
> -		return NULL;
> -	}
> -
> -	return binfo;
> -}
> -
>  static void build_info_free(struct build_feature_devs_info *binfo)  {
> -	free(binfo);
> +	opae_free(binfo);
>  }
> 
>  static void ifpga_print_device_feature_list(struct ifpga_hw *hw) @@ -648,6
> +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
>  	struct ifpga_feature *feature;
>  	int i;
> 
> +	if (fme->state == IFPGA_FME_UNUSED) {
> +		dev_info(hw, "FME is not present\n");
> +		return;
> +	}
> +
>  	dev_info(hw, "found fme_device, is in PF: %s\n",
>  		 is_ifpga_hw_pf(hw) ? "yes" : "no");
> 
> @@ -685,40 +703,408 @@ static void ifpga_print_device_feature_list(struct
> ifpga_hw *hw)
>  	}
>  }
> 
> -int ifpga_bus_enumerate(struct ifpga_hw *hw)
> +static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct
> +ifpga_hw *hw)
>  {
> -	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_info *info;
> +
> +	info = opae_zmalloc(sizeof(*info));
> +	if (!info)
> +		return NULL;
> +
> +	info->hw = hw;
> +	TAILQ_INIT(&info->dfls);
> +
> +	return info;
> +}
> +
> +static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info) {
> +	struct dfl_fpga_enum_dfl *tmp, *dfl;
> +
> +	if (!info)
> +		return;
> +
> +	/* remove all device feature lists in the list. */
> +	for (dfl = TAILQ_FIRST(&info->dfls);
> +		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
> +		dfl = tmp) {
> +		TAILQ_REMOVE(&info->dfls, dfl, node);
> +		opae_free(dfl);
> +	}
> +
> +	opae_free(info);
> +}
> +
> +static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
> +	u64 start, u64 len, void *addr)
> +{
> +	struct dfl_fpga_enum_dfl *dfl;
> +
> +	dfl = opae_zmalloc(sizeof(*dfl));
> +	if (!dfl)
> +		return -ENOMEM;
> +
> +	dfl->start = start;
> +	dfl->len = len;
> +	dfl->addr = addr;
> +
> +	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
> +
> +	return 0;
> +}
> +
> +#define PCI_CFG_SPACE_SIZE	256
> +#define PCI_CFG_SPACE_EXP_SIZE	4096
> +#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
> +#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
> +
> +static int
> +pci_find_next_ecap(int fd, int start, u32 cap) {
> +	u32 header;
> +	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
> +	int pos = PCI_CFG_SPACE_SIZE;
>  	int ret;
> 
> -	binfo = build_info_alloc_and_init(hw);
> +	if (start > 0)
> +		pos = start;
> +
> +	ret = pread(fd, &header, sizeof(header), pos);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * If we have no capabilities, this is indicated by cap ID,
> +	 * cap version and next pointer all being 0.
> +	 */
> +	if (header == 0)
> +		return 0;
> +
> +	while (ttl-- > 0) {
> +		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
> +			return pos;
> +
> +		pos = PCI_EXT_CAP_NEXT(header);
> +		if (pos < PCI_CFG_SPACE_SIZE)
> +			break;
> +		ret = pread(fd, &header, sizeof(header), pos);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define PCI_EXT_CAP_ID_VNDR	0x0B
> +#define PCI_VNDR_HEADER		4
> +#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
> +#define PCI_VENDOR_ID_INTEL 0x8086
> +#define PCI_VSEC_ID_INTEL_DFLS 0x43
> +#define PCI_VNDR_DFLS_CNT 0x8
> +#define PCI_VNDR_DFLS_RES 0xc
> +#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0) #define
> +PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
> +
> +static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	char path[64];
> +	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
> +	int fd, ret, dfl_res_off, voff = 0;
> +	u64 start, len;
> +	void *addr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->adapter || !hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
> +			hw->adapter->name);
> +	if ((unsigned int)ret >= sizeof(path))
> +		return -EINVAL;
> +
> +	fd = open(path, O_RDWR);
> +	if (fd < 0)
> +		return -EIO;
> +
> +	while ((voff = pci_find_next_ecap(fd, voff,
> +		PCI_EXT_CAP_ID_VNDR))) {
> +		vndr_hdr = 0;
> +		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
> +			voff + PCI_VNDR_HEADER);
> +		if (ret < 0)
> +			return -EIO;
> +		if (PCI_VNDR_HEADER_ID(vndr_hdr) ==
> PCI_VSEC_ID_INTEL_DFLS &&
> +			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
> +			break;
> +	}
> +
> +	if (!voff) {
> +		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	dfl_cnt = 0;
> +	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
> +	if (ret < 0)
> +		return -EIO;
> +
> +	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
> +	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
> +		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
> +		dfl_res = GENMASK(31, 0);
> +		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
> +		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
> +		if (bir >= PCI_MAX_RESOURCE) {
> +			dev_err(hw, "%s bad bir number %d\n",
> +				__func__, bir);
> +			return -EINVAL;
> +		}
> +
> +		len = pci_data->region[bir].len;
> +		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
> +		if (offset >= len) {
> +			dev_err(hw, "%s bad offset %u >= %zu\n",
> +				__func__, offset, len);
> +			return -EINVAL;
> +		}
> +
> +		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir,
> offset);
> +		len -= offset;
> +		start = pci_data->region[bir].phys_addr + offset;
> +		addr = pci_data->region[bir].addr + offset;
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	}
> +
> +	return 0;
> +}
> +
> +/* default method of finding dfls starting at offset 0 of bar 0 */
> +static int find_dfls_by_default(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	int port_num, bar, i, ret = 0;
> +	u64 start, len;
> +	void *addr;
> +	u32 offset;
> +	struct feature_header hdr;
> +	struct feature_fme_capability cap;
> +	struct feature_fme_port port;
> +	struct feature_fme_header *fme_hdr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	/* start to find Device Feature List from Bar 0 */
> +	addr = pci_data->region[0].addr;
> +	if (!addr)
> +		return -ENOMEM;
> +
> +	/*
> +	 * PF device has FME and Ports/AFUs, and VF device only has one
> +	 * Port/AFU. Check them and add related "Device Feature List" info
> +	 * for the next step enumeration.
> +	 */
> +	hdr.csr = opae_readq(addr);
> +	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id ==
> FEATURE_FIU_ID_FME)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +
> +		/*
> +		 * find more Device Feature Lists (e.g. Ports) per information
> +		 * indicated by FME module.
> +		 */
> +		fme_hdr = (struct feature_fme_header *)addr;
> +		cap.csr = opae_readq(&fme_hdr->capability);
> +		port_num = (int)cap.num_ports;
> +
> +		dev_info(hw, "port_num = %d\n", port_num);
> +		if (port_num > MAX_FPGA_PORT_NUM)
> +			port_num = MAX_FPGA_PORT_NUM;
> +
> +		for (i = 0; i < port_num; i++) {
> +			port.csr = opae_readq(&fme_hdr->port[i]);
> +
> +			/* skip ports which are not implemented. */
> +			if (!port.port_implemented)
> +				continue;
> +
> +			/* skip port which only could be accessed via VF */
> +			if (port.afu_access_control == FME_AFU_ACCESS_VF)
> +				continue;
> +
> +			/*
> +			 * add Port's Device Feature List information for next
> +			 * step enumeration.
> +			 */
> +			bar = (int)port.port_bar;
> +			offset = port.port_offset;
> +			if (bar >= PCI_MAX_RESOURCE) {
> +				dev_info(hw, "skipping BAR %d\n", bar);
> +				continue;

For this case, if bar >= PCI_MAX_RESOURCE, this is hardware issue, we can return error, 
But it has specific case in OFS is that if the bar = 7, it should be skipping it.

> +			} else {
> +				dev_info(hw, "BAR %d offset %u\n", bar,
> offset);
> +			}
> +
> +			len = pci_data->region[bar].len;
> +			if (offset >= len) {
> +				dev_warn(hw, "bad port offset %u >= %pa\n",
> +					 offset, &len);
> +				continue;
> +			}
> +
> +			len -= offset;
> +			start = pci_data->region[bar].phys_addr + offset;
> +			addr = pci_data->region[bar].addr + offset;
> +			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +		}
> +	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
> +		(hdr.id == FEATURE_FIU_ID_PORT)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else if (hdr.type == FEATURE_TYPE_AFU) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else {
> +		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
> +			 hdr.type, hdr.id);
> +		ret = -ENODEV;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info
> +*info) {
> +	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_dfl *dfl;
> +	int ret = 0;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +
> +	/* create and init build info for enumeration */
> +	binfo = opae_zmalloc(sizeof(*binfo));
>  	if (!binfo)
>  		return -ENOMEM;
> 
> -	ret = parse_feature_list(binfo, binfo->ioaddr);
> +	binfo->hw = info->hw;
> +	binfo->pci_data = info->hw->pci_data;
> +
> +	/*
> +	 * start enumeration for all feature devices based on Device Feature
> +	 * Lists.
> +	 */
> +	TAILQ_FOREACH(dfl, &info->dfls, node) {
> +		ret = parse_feature_list(binfo, dfl);
> +		if (ret)
> +			break;
> +	}
> +
> +	build_info_free(binfo);
> +
> +	return ret;
> +}
> +
> +int ifpga_bus_enumerate(struct ifpga_hw *hw) {
> +	struct dfl_fpga_enum_info *info;
> +	int ret;
> +
> +	/* allocate enumeration info */
> +	info = dfl_fpga_enum_info_alloc(hw);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	ret = find_dfls_by_vsec(info);
> +	if (ret < 0)
> +		ret = find_dfls_by_default(info);
> +
>  	if (ret)
>  		goto exit;
> 
> -	ret = parse_ports_from_fme(binfo);
> -	if (ret)
> +	/* start enumeration with prepared enumeration information */
> +	ret = dfl_fpga_feature_devs_enumerate(info);
> +	if (ret < 0) {
> +		dev_err(hw, "Enumeration failure\n");
>  		goto exit;
> +	}
> 
>  	ifpga_print_device_feature_list(hw);
> 
>  exit:
> -	build_info_free(binfo);
> +	dfl_fpga_enum_info_free(info);
> +
>  	return ret;
>  }
> 
> -int ifpga_bus_init(struct ifpga_hw *hw)
> +static void ifpga_print_acc_list(struct opae_adapter *adapter)
>  {
> +	struct opae_accelerator *acc;
> +	struct ifpga_afu_info *info;
> +	struct uuid guid;
> +	char buf[48];
>  	int i;
> +
> +	opae_adapter_for_each_acc(adapter, acc) {
> +		info = acc->data;
> +		if (!info)
> +			continue;
> +		acc->ops->get_uuid(acc, &guid);
> +		i = sprintf(buf, "%02x%02x%02x%02x-",
> +			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
> +		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
> +			guid.b[5], guid.b[4], guid.b[3],
> +			guid.b[2], guid.b[1], guid.b[0]);
> +		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
> +			acc->name, acc->index, info->region[0].addr,
> +			info->region[0].len, buf);
> +	}
> +}
> +
> +int ifpga_bus_init(struct ifpga_hw *hw) {
> +	int i, ret = 0;
>  	struct ifpga_port_hw *port;
> 
> -	fme_hw_init(&hw->fme);
> +	ret = fme_hw_init(&hw->fme);
> +	if (ret)
> +		return ret;
> +
>  	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
>  		port = &hw->port[i];
>  		port_hw_init(port);
>  	}
> +	ifpga_print_acc_list(hw->adapter);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> index 0813513..dbecc7b 100644
> --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> @@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
>  	if (fpga_wait_register_field(port_sftrst_ack, control,
>  				     &port_hdr->control, RST_POLL_TIMEOUT,
>  				     RST_POLL_INVL)) {
> -		dev_err(port, "timeout, fail to reset device\n");
> +		dev_err(port, "timeout, fail to reset FIM port\n");
>  		return -ETIMEDOUT;
>  	}
> 
> @@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list
> *list)
>  	struct ifpga_feature *feature;
> 
>  	TAILQ_FOREACH(feature, list, next) {
> -		if (feature->state != IFPGA_FEATURE_ATTACHED)
> +		if (feature->state != IFPGA_FEATURE_INITED)
>  			continue;
>  		if (feature->ops && feature->ops->uinit)
>  			feature->ops->uinit(feature);
> +		feature->state = IFPGA_FEATURE_ATTACHED;
>  	}
>  }
> 
> @@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
>  					ret = feature->ops->init(feature);
>  					if (ret)
>  						goto error;
> +					else
> +						feature->state =
> +
> 	IFPGA_FEATURE_INITED;
>  				}
>  			}
>  		}
> @@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
> 
>  int fme_hw_init(struct ifpga_fme_hw *fme)  {
> -	int ret;
> -
> -	if (fme->state != IFPGA_FME_IMPLEMENTED)
> -		return -ENODEV;
> -
> -	ret = feature_init(fme_feature_drvs, &fme->feature_list);
> -	if (ret)
> -		return ret;
> +	if (fme->state == IFPGA_FME_IMPLEMENTED)
> +		return feature_init(fme_feature_drvs, &fme->feature_list);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_hw.h
> b/drivers/raw/ifpga/base/ifpga_hw.h
> index ed5edc6..4d56deb 100644
> --- a/drivers/raw/ifpga/base/ifpga_hw.h
> +++ b/drivers/raw/ifpga/base/ifpga_hw.h
> @@ -15,6 +15,7 @@
>  enum ifpga_feature_state {
>  	IFPGA_FEATURE_UNUSED = 0,
>  	IFPGA_FEATURE_ATTACHED,
> +	IFPGA_FEATURE_INITED
>  };
> 
>  enum feature_type {
> @@ -134,6 +135,7 @@ struct ifpga_hw {
> 
>  	struct ifpga_fme_hw fme;
>  	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
> +	int num_afus;
>  };
> 
>  static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) diff --git
> a/drivers/raw/ifpga/base/opae_hw_api.c
> b/drivers/raw/ifpga/base/opae_hw_api.c
> index 11c9887..87256fc 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.c
> +++ b/drivers/raw/ifpga/base/opae_hw_api.c
> @@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator
> *acc,  int opae_acc_set_irq(struct opae_accelerator *acc,
>  		     u32 start, u32 count, s32 evtfds[])  {
> -	if (!acc || !acc->data)
> +	if (!acc)
>  		return -EINVAL;
> 
>  	if (start + count <= start)
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.h
> b/drivers/raw/ifpga/base/opae_hw_api.h
> index 7e04b56..fd40e09 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.h
> +++ b/drivers/raw/ifpga/base/opae_hw_api.h
> @@ -143,6 +143,7 @@ struct opae_accelerator {
>  	TAILQ_ENTRY(opae_accelerator) node;
>  	const char *name;
>  	int index;
> +	struct opae_adapter *adapter;
>  	struct opae_bridge *br;
>  	struct opae_manager *mgr;
>  	struct opae_accelerator_ops *ops;
> @@ -240,6 +241,7 @@ struct opae_adapter_data {
> 
>  struct opae_reg_region {
>  	u64 phys_addr;
> +#define AFU_REGION_SIZE  0x8000
>  	u64 len;
>  	u8 *addr;
>  };
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 94df56c..ceb18ae 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -47,11 +47,13 @@
>  #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
>  #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
>  #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
> +#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
>  /* VF Device */
>  #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
>  #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
>  #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
>  #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
> +#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
>  #define RTE_MAX_RAW_DEVICE           10
> 
>  static const struct rte_pci_id pci_ifpga_map[] = { @@ -63,6 +65,8 @@
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_DSC_1_X) },
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N3000),},
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N3000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N6000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N6000),},
>  	{ .vendor_id = 0, /* sentinel */ },
>  };
> 
> @@ -110,6 +114,7 @@ struct ifpga_rawdev *
> 
>  	return IFPGA_RAWDEV_NUM;
>  }
> +
>  static struct ifpga_rawdev *
>  ifpga_rawdev_allocate(struct rte_rawdev *rawdev)  { @@ -365,7 +370,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  		return -ENODEV;
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> +	if (!mgr || !mgr->sensor_list)
>  		return -ENODEV;
> 
>  	opae_mgr_for_each_sensor(mgr, sensor) { @@ -377,7 +382,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  			goto fail;
> 
>  		if (value == 0xdeadbeef) {
> -			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value
> %x\n",
> +			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s
> value %x\n",
>  					raw_dev->dev_id, sensor->name,
> value);
>  			continue;
>  		}
> @@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(  {
>  	struct opae_adapter *adapter;
>  	struct opae_manager *mgr;
> -	struct opae_board_info *info;
> +	struct opae_board_info *info = NULL;
>  	struct rte_afu_pr_conf *afu_pr_conf;
>  	int ret;
>  	struct uuid uuid;
> @@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
>  	}
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr) {
> -		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is
> NULL");
> -		return -1;
> -	}
> -
> -	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> -		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info
> fail!");
> -		return -1;
> +	if (mgr) {
> +		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> +			IFPGA_RAWDEV_PMD_ERR("ifpga manager
> get_board_info fail!");
> +			return -1;
> +		}
>  	}
> 
> -	if (info->lightweight) {
> +	if (info && info->lightweight) {
>  		/* set uuid to all 0, when fpga is lightweight image */
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
> @@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
>  			__func__,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
> -		}
> +	}
>  	return 0;
>  }
> 
> @@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
>  	if (ret) {
>  		ret = -ENOMEM;
> -		goto free_adapter_data;
> +		goto cleanup;
>  	}
> 
>  	rawdev->dev_ops = &ifpga_rawdev_ops;
> @@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	/* must enumerate the adapter before use it */
>  	ret = opae_adapter_enumerate(adapter);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	/* get opae_manager to rawdev */
>  	mgr = opae_adapter_get_mgr(adapter);
>  	if (mgr) {
> -		/* PF function */
> -		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
> +		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> +				fme_interrupt_handler, "fme_irq", mgr);
> +		if (ret)
> +			goto cleanup;
>  	}
> 
> -	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> -			fme_interrupt_handler, "fme_irq", mgr);
> -	if (ret)
> -		goto free_adapter_data;
> -
>  	ret = ifpga_monitor_start_func(dev);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	return ret;
> 
> -free_adapter_data:
> -	if (data)
> -		opae_adapter_data_free(data);
>  cleanup:
>  	if (rawdev)
>  		rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-18  8:29     ` [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-25  3:22       ` Zhang, Tianfei
  0 siblings, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-25  3:22 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Wednesday, May 18, 2022 4:29 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs
> 
> These APIs are introduced in DPDK 21.05 and have been tested in several
> release, experimental tag can be formally removed.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
It is better that you can add Acked Tag after I acked in maillist.
> ---
>  drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
>  drivers/raw/ifpga/version.map     |  7 ++----
>  2 files changed, 2 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h
> b/drivers/raw/ifpga/rte_pmd_ifpga.h
> index 47d66ba..3fa5d34 100644
> --- a/drivers/raw/ifpga/rte_pmd_ifpga.h
> +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
> @@ -68,9 +68,6 @@
>  } rte_pmd_ifpga_phy_info;
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
>   *
>   * @param pci_addr
> @@ -82,14 +79,10 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-ENODEV) if FPGA is not probed by ifpga driver.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get current RSU status of the specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -103,14 +96,10 @@
>   *   - (-ENODEV) if dev_id is invalid.
>   *   - (-ENOMEM) if share data is not initialized.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Set current RSU status of the specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -124,14 +113,10 @@
>   *   - (-ENODEV) if dev_id is invalid.
>   *   - (-ENOMEM) if share data is not initialized.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get FPGA property of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -144,14 +129,10 @@
>   *   - (-EBUSY) if FPGA is rebooting.
>   *   - (-EIO) if failed to access hardware.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get PHY information of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -164,14 +145,10 @@
>   *   - (-EBUSY) if FPGA is rebooting.
>   *   - (-EIO) if failed to access hardware.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Update image flash of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -187,15 +164,11 @@
>   *   - (-EBUSY) if FPGA is updating or rebooting.
>   *   - (-EIO) if failed to open image file.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
>  	uint64_t *status);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Stop flash update of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -208,14 +181,10 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-EAGAIN) if failed with force.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Check current Intel FPGA status and change it to reboot status if it is idle
>   *
>   * @param dev_id
> @@ -226,14 +195,10 @@
>   *   - (-ENOMEM) if share data is not initialized.
>   *   - (-EBUSY) if FPGA is updating or rebooting.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_reboot_try(uint16_t dev_id);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Trigger full reconfiguration of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -252,28 +217,20 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-EBUSY) if failed to access BMC register.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get PCI bus the Intel FPGA driver register to
>   *
>   * @return
>   *   - (valid pointer) if successful.
>   *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
>   */
> -__rte_experimental
>  const struct rte_pci_bus *
>  rte_pmd_ifpga_get_pci_bus(void);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Perform PR (partial reconfiguration) on specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -287,17 +244,12 @@
>   *   - (-EINVAL) if bad parameter or operation failed.
>   *   - (-ENOMEM) if failed to allocate memory.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Free software resources allocated by Intel FPGA PMD
>   */
> -__rte_experimental
>  void
>  rte_pmd_ifpga_cleanup(void);
> 
> diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
> index a1a6be2..ff71a45 100644
> --- a/drivers/raw/ifpga/version.map
> +++ b/drivers/raw/ifpga/version.map
> @@ -1,11 +1,6 @@
>  DPDK_22 {
> -	local: *;
> -};
> -
> -EXPERIMENTAL {
>  	global:
> 
> -	# added in 21.05
>  	rte_pmd_ifpga_get_dev_id;
>  	rte_pmd_ifpga_get_rsu_status;
>  	rte_pmd_ifpga_set_rsu_status;
> @@ -18,4 +13,6 @@ EXPERIMENTAL {
>  	rte_pmd_ifpga_get_pci_bus;
>  	rte_pmd_ifpga_partial_reconfigure;
>  	rte_pmd_ifpga_cleanup;
> +
> +	local: *;
>  };
> --
> 1.8.3.1

It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-18  8:29     ` [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-25  3:26       ` Zhang, Tianfei
  0 siblings, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-25  3:26 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Wednesday, May 18, 2022 4:29 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function
> 
> Move interrupt unregistration from ifpga destroy function to ifpga close
> function, so rte_rawdev_pmd_release function can release interrupt resource.

It is batter that you can add a little more explanation about why we move to ifpga close function.

> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index fe3fc43..94df56c 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(  static int
> ifpga_pci_find_next_ext_capability(unsigned int fd,
>  					      int start, uint32_t cap);
>  static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
> +static void fme_interrupt_handler(void *param);
> 
>  struct ifpga_rawdev *
>  ifpga_rawdev_get(const struct rte_rawdev *rawdev) @@ -740,8 +741,9 @@
> static int set_surprise_link_check_aer(  {
>  	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	struct opae_manager *mgr;
>  	char *vdev_name = NULL;
> -	int i = 0;
> +	int i, ret = 0;
> 
>  	if (dev) {
>  		ifpga_rdev = ifpga_rawdev_get(dev);
> @@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
>  		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
> +			mgr = opae_adapter_get_mgr(adapter);
> +			if (ifpga_rdev && mgr) {
> +				if (ifpga_unregister_msix_irq(ifpga_rdev,
> +					IFPGA_FME_IRQ, 0,
> +					fme_interrupt_handler, mgr) < 0)
> +					ret = -EINVAL;
> +			}
>  			opae_adapter_destroy(adapter);
>  			opae_adapter_data_free(adapter->data);
>  		}
>  	}
> 
> -	return dev ? 0:1;
> +	return ret;
>  }
> 
>  static int
> @@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  	int ret;
>  	struct rte_rawdev *rawdev;
>  	char name[RTE_RAWDEV_NAME_MAX_LEN];
> -	struct opae_adapter *adapter;
> -	struct opae_manager *mgr;
> -	struct ifpga_rawdev *dev;
> 
>  	if (!pci_dev) {
>  		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
> @@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
>  		return -EINVAL;
>  	}
> -	dev = ifpga_rawdev_get(rawdev);
> -
> -	adapter = ifpga_rawdev_get_priv(rawdev);
> -	if (!adapter)
> -		return -ENODEV;
> -
> -	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> -		return -ENODEV;
> -
> -	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
> -				fme_interrupt_handler, mgr) < 0)
> -		return -EINVAL;
> 
>  	/* rte_rawdev_close is called by pmd_release */
>  	ret = rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed
  2022-05-18  8:29     ` [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-25  4:09       ` Zhang, Tianfei
  0 siblings, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-25  4:09 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Wednesday, May 18, 2022 4:29 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed
> 
> Virtual devices created on ifpga raw device are not removed when ifpga is
> closed. To avoid such problem, ifpga virtual device remove function is
> implemented, virtual device is removed in raw device close function.

The git message  can be changed as below:

Virtual devices created on ifpga raw device will not be removed when ifpga device
has closed. To avoid resource leak problem, this patch introduces an ifpga virtual
device remove function, virtual devices will be destroyed after the ifpga raw device closed.

> 
> Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
> Acked-by: Rosen Xu <rosen.xu@intel.com>
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---
> ------
>  drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
>  2 files changed, 138 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 6d4117c..fe3fc43 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -134,6 +134,8 @@ struct ifpga_rawdev *
>  	for (i = 0; i < IFPGA_MAX_IRQ; i++)
>  		dev->intr_handle[i] = NULL;
>  	dev->poll_enabled = 0;
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++)
> +		dev->vdev_name[i] = NULL;
> 
>  	return dev;
>  }
> @@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(  static int
> ifpga_rawdev_close(struct rte_rawdev *dev)  {
> +	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	char *vdev_name = NULL;
> +	int i = 0;
> 
>  	if (dev) {
> -		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
> +		ifpga_rdev = ifpga_rawdev_get(dev);
> +		if (ifpga_rdev) {
> +			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +				vdev_name = ifpga_rdev->vdev_name[i];
> +				if (vdev_name)
> +					rte_vdev_uninit(vdev_name);
> +			}
> +			ifpga_monitor_stop_func(ifpga_rdev);
> +			ifpga_rdev->rawdev = NULL;
> +		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
>  			opae_adapter_destroy(adapter);
> @@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  		return -EINVAL;
>  	}
>  	dev = ifpga_rawdev_get(rawdev);
> -	if (dev)
> -		dev->rawdev = NULL;
> 
>  	adapter = ifpga_rawdev_get_priv(rawdev);
>  	if (!adapter)
> @@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char
> *key __rte_unused,
> 
>  	return 0;
>  }
> +
>  static int
> -ifpga_cfg_probe(struct rte_vdev_device *dev)
> +ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
> +	struct ifpga_vdev_args *args)
>  {
> -	struct rte_devargs *devargs;
> -	struct rte_kvargs *kvlist = NULL;
> -	struct rte_rawdev *rawdev = NULL;
> -	struct ifpga_rawdev *ifpga_dev;
> -	int port;
> +	struct rte_kvargs *kvlist;
>  	char *name = NULL;
> -	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> -	int ret = -1;
> +	int port = 0;
> +	int ret = -EINVAL;
> 
> -	devargs = dev->device.devargs;
> +	if (!devargs || !args)
> +		return ret;
> 
>  	kvlist = rte_kvargs_parse(devargs->args, valid_args);
>  	if (!kvlist) {
> -		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
> -		goto end;
> +		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
> +		return ret;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
>  		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
> -				       &ifpga_rawdev_get_string_arg,
> -				       &name) < 0) {
> +			&ifpga_rawdev_get_string_arg, &name) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
> -				     IFPGA_ARG_NAME);
> +				IFPGA_ARG_NAME);
>  			goto end;
> +		} else {
> +			strlcpy(args->bdf, name, sizeof(args->bdf));
> +			rte_free(name);
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
> -			  IFPGA_ARG_NAME);
> +			IFPGA_ARG_NAME);
>  		goto end;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
> -		if (rte_kvargs_process(kvlist,
> -			IFPGA_ARG_PORT,
> -			&rte_ifpga_get_integer32_arg,
> -			&port) < 0) {
> +		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
> +			&rte_ifpga_get_integer32_arg, &port) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
>  				IFPGA_ARG_PORT);
>  			goto end;
> +		} else {
> +			args->port = port;
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
> -			  IFPGA_ARG_PORT);
> +			IFPGA_ARG_PORT);
>  		goto end;
>  	}
> 
> +	ret = 0;
> +
> +end:
> +	if (kvlist)
> +		rte_kvargs_free(kvlist);
> +
> +	return ret;
> +}
> +
> +static int
> +ifpga_cfg_probe(struct rte_vdev_device *vdev) {
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	int i, n, ret = 0;
> +
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
>  	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> name);
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
>  	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
>  	if (!rawdev)
> -		goto end;
> +		return -ENODEV;
>  	ifpga_dev = ifpga_rawdev_get(rawdev);
>  	if (!ifpga_dev)
> -		goto end;
> +		return -ENODEV;
> 
> -	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> -	port, name);
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		if (ifpga_dev->vdev_name[i] == NULL) {
> +			n = strlen(vdev_name) + 1;
> +			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
> +			if (ifpga_dev->vdev_name[i] == NULL)
> +				return -ENOMEM;
> +			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
> +			break;
> +		}
> +	}
> 
> +	if (i >= IFPGA_MAX_VDEV) {
> +		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
> +		return -ENOENT;
> +	}
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
>  	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
> -			dev_name, devargs->args);
> -end:
> -	rte_kvargs_free(kvlist);
> -	free(name);
> +			dev_name, vdev->device.devargs->args);
> +	if (ret) {
> +		rte_free(ifpga_dev->vdev_name[i]);
> +		ifpga_dev->vdev_name[i] = NULL;
> +	}
> 
>  	return ret;
>  }
> @@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char
> *key __rte_unused,  static int  ifpga_cfg_remove(struct rte_vdev_device *vdev)
> {
> -	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
> -		vdev);
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	char *tmp_vdev = NULL;
> +	int i, ret = 0;
> 
> -	return 0;
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
> +	memset(dev_name, 0, sizeof(dev_name));
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
> +	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
> +	if (!rawdev)
> +		return -ENODEV;
> +	ifpga_dev = ifpga_rawdev_get(rawdev);
> +	if (!ifpga_dev)
> +		return -ENODEV;
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
> +	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME),
> dev_name);
> +
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		tmp_vdev = ifpga_dev->vdev_name[i];
> +		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
> +			free(tmp_vdev);
> +			ifpga_dev->vdev_name[i] = NULL;
> +			break;
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static struct rte_vdev_driver ifpga_cfg_driver = { diff --git
> a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
> index 857b734..eb9a9a5 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.h
> +++ b/drivers/raw/ifpga/ifpga_rawdev.h
> @@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
> 
>  #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
>  #define IFPGA_RAWDEV_NUM 32
> +#define IFPGA_MAX_VDEV 4
>  #define IFPGA_MAX_IRQ 12
> 
>  struct ifpga_rawdev {
> @@ -64,6 +65,13 @@ struct ifpga_rawdev {
>  	void *intr_handle[IFPGA_MAX_IRQ];
>  	/* enable monitor thread poll device's sensors or not */
>  	int poll_enabled;
> +	/* name of virtual devices created on raw device */
> +	char *vdev_name[IFPGA_MAX_VDEV];
> +};
> +
> +struct ifpga_vdev_args {
> +	char bdf[8];
> +	int port;
>  };

can we use a common macro definition for this immediate value 8?

> 
>  struct ifpga_rawdev *
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 0/5] Support OFS card
  2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
                       ` (3 preceding siblings ...)
  2022-05-18  8:29     ` [PATCH v2 4/4] raw/ifpga: support ofs card probe Wei Huang
@ 2022-05-26  3:32     ` Wei Huang
  2022-05-26  3:32       ` [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
                         ` (5 more replies)
  4 siblings, 6 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Changes from v2:
1. update commit log with Tianfei's comment.
2. use macro to define immediate value.
3. treat 7 as special PCI BAR index.
4. update ifpga documentation with OFS introduction.

Wei Huang (5):
  raw/ifpga: remove experimental tag from ifpga APIs
  raw/ifpga: remove vdev when ifpga is closed
  raw/ifpga: unregister interrupt in ifpga close function
  raw/ifpga: support ofs card probe
  guides/rawdevs: add description of ofs in ifpga doc

 doc/guides/rawdevs/ifpga.rst               | 114 ++++-
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 681 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           | 241 ++++++----
 drivers/raw/ifpga/ifpga_rawdev.h           |   8 +
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  48 --
 drivers/raw/ifpga/version.map              |   7 +-
 13 files changed, 855 insertions(+), 299 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
@ 2022-05-26  3:32       ` Wei Huang
  2022-05-26  6:29         ` Xu, Rosen
  2022-05-26  3:32       ` [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
                         ` (4 subsequent siblings)
  5 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

These APIs are introduced in DPDK 21.05 and have been tested in several
release, experimental tag can be formally removed.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
 drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
 drivers/raw/ifpga/version.map     |  7 ++----
 2 files changed, 2 insertions(+), 53 deletions(-)

diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 47d66ba..3fa5d34 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -68,9 +68,6 @@
 } rte_pmd_ifpga_phy_info;
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
  *
  * @param pci_addr
@@ -82,14 +79,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-ENODEV) if FPGA is not probed by ifpga driver.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -103,14 +96,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Set current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -124,14 +113,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get FPGA property of specified Intel FPGA device
  *
  * @param dev_id
@@ -144,14 +129,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PHY information of specified Intel FPGA device
  *
  * @param dev_id
@@ -164,14 +145,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Update image flash of specified Intel FPGA device
  *
  * @param dev_id
@@ -187,15 +164,11 @@
  *   - (-EBUSY) if FPGA is updating or rebooting.
  *   - (-EIO) if failed to open image file.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
 	uint64_t *status);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Stop flash update of specified Intel FPGA device
  *
  * @param dev_id
@@ -208,14 +181,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EAGAIN) if failed with force.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Check current Intel FPGA status and change it to reboot status if it is idle
  *
  * @param dev_id
@@ -226,14 +195,10 @@
  *   - (-ENOMEM) if share data is not initialized.
  *   - (-EBUSY) if FPGA is updating or rebooting.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reboot_try(uint16_t dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Trigger full reconfiguration of specified Intel FPGA device
  *
  * @param dev_id
@@ -252,28 +217,20 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PCI bus the Intel FPGA driver register to
  *
  * @return
  *   - (valid pointer) if successful.
  *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
  */
-__rte_experimental
 const struct rte_pci_bus *
 rte_pmd_ifpga_get_pci_bus(void);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Perform PR (partial reconfiguration) on specified Intel FPGA device
  *
  * @param dev_id
@@ -287,17 +244,12 @@
  *   - (-EINVAL) if bad parameter or operation failed.
  *   - (-ENOMEM) if failed to allocate memory.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Free software resources allocated by Intel FPGA PMD
  */
-__rte_experimental
 void
 rte_pmd_ifpga_cleanup(void);
 
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index a1a6be2..ff71a45 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -1,11 +1,6 @@
 DPDK_22 {
-	local: *;
-};
-
-EXPERIMENTAL {
 	global:
 
-	# added in 21.05
 	rte_pmd_ifpga_get_dev_id;
 	rte_pmd_ifpga_get_rsu_status;
 	rte_pmd_ifpga_set_rsu_status;
@@ -18,4 +13,6 @@ EXPERIMENTAL {
 	rte_pmd_ifpga_get_pci_bus;
 	rte_pmd_ifpga_partial_reconfigure;
 	rte_pmd_ifpga_cleanup;
+
+	local: *;
 };
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
  2022-05-26  3:32       ` [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-26  3:32       ` Wei Huang
  2022-05-26  6:34         ` Xu, Rosen
  2022-05-26  3:32       ` [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
                         ` (3 subsequent siblings)
  5 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Virtual devices created on ifpga raw device will not be removed
when ifpga device has closed. To avoid resource leak problem,
this patch introduces an ifpga virtual device remove function,
virtual devices will be destroyed after the ifpga raw device closed.

Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
---
v2: update commit log, use macro to replace immediate value.
---
 drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---------
 drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
 2 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 6d4117c..fe3fc43 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -134,6 +134,8 @@ struct ifpga_rawdev *
 	for (i = 0; i < IFPGA_MAX_IRQ; i++)
 		dev->intr_handle[i] = NULL;
 	dev->poll_enabled = 0;
+	for (i = 0; i < IFPGA_MAX_VDEV; i++)
+		dev->vdev_name[i] = NULL;
 
 	return dev;
 }
@@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(
 static int
 ifpga_rawdev_close(struct rte_rawdev *dev)
 {
+	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	char *vdev_name = NULL;
+	int i = 0;
 
 	if (dev) {
-		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
+		ifpga_rdev = ifpga_rawdev_get(dev);
+		if (ifpga_rdev) {
+			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+				vdev_name = ifpga_rdev->vdev_name[i];
+				if (vdev_name)
+					rte_vdev_uninit(vdev_name);
+			}
+			ifpga_monitor_stop_func(ifpga_rdev);
+			ifpga_rdev->rawdev = NULL;
+		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
 			opae_adapter_destroy(adapter);
@@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		return -EINVAL;
 	}
 	dev = ifpga_rawdev_get(rawdev);
-	if (dev)
-		dev->rawdev = NULL;
 
 	adapter = ifpga_rawdev_get_priv(rawdev);
 	if (!adapter)
@@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 
 	return 0;
 }
+
 static int
-ifpga_cfg_probe(struct rte_vdev_device *dev)
+ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
+	struct ifpga_vdev_args *args)
 {
-	struct rte_devargs *devargs;
-	struct rte_kvargs *kvlist = NULL;
-	struct rte_rawdev *rawdev = NULL;
-	struct ifpga_rawdev *ifpga_dev;
-	int port;
+	struct rte_kvargs *kvlist;
 	char *name = NULL;
-	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
-	int ret = -1;
+	int port = 0;
+	int ret = -EINVAL;
 
-	devargs = dev->device.devargs;
+	if (!devargs || !args)
+		return ret;
 
 	kvlist = rte_kvargs_parse(devargs->args, valid_args);
 	if (!kvlist) {
-		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
-		goto end;
+		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
+		return ret;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
 		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
-				       &ifpga_rawdev_get_string_arg,
-				       &name) < 0) {
+			&ifpga_rawdev_get_string_arg, &name) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
-				     IFPGA_ARG_NAME);
+				IFPGA_ARG_NAME);
 			goto end;
+		} else {
+			strlcpy(args->bdf, name, sizeof(args->bdf));
+			rte_free(name);
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_NAME);
+			IFPGA_ARG_NAME);
 		goto end;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
-		if (rte_kvargs_process(kvlist,
-			IFPGA_ARG_PORT,
-			&rte_ifpga_get_integer32_arg,
-			&port) < 0) {
+		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
+			&rte_ifpga_get_integer32_arg, &port) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
 				IFPGA_ARG_PORT);
 			goto end;
+		} else {
+			args->port = port;
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_PORT);
+			IFPGA_ARG_PORT);
 		goto end;
 	}
 
+	ret = 0;
+
+end:
+	if (kvlist)
+		rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+ifpga_cfg_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	int i, n, ret = 0;
+
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
 	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name);
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
 	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
 	if (!rawdev)
-		goto end;
+		return -ENODEV;
 	ifpga_dev = ifpga_rawdev_get(rawdev);
 	if (!ifpga_dev)
-		goto end;
+		return -ENODEV;
 
-	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
-	port, name);
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		if (ifpga_dev->vdev_name[i] == NULL) {
+			n = strlen(vdev_name) + 1;
+			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
+			if (ifpga_dev->vdev_name[i] == NULL)
+				return -ENOMEM;
+			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
+			break;
+		}
+	}
 
+	if (i >= IFPGA_MAX_VDEV) {
+		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
+		return -ENOENT;
+	}
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
 	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
-			dev_name, devargs->args);
-end:
-	rte_kvargs_free(kvlist);
-	free(name);
+			dev_name, vdev->device.devargs->args);
+	if (ret) {
+		rte_free(ifpga_dev->vdev_name[i]);
+		ifpga_dev->vdev_name[i] = NULL;
+	}
 
 	return ret;
 }
@@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 static int
 ifpga_cfg_remove(struct rte_vdev_device *vdev)
 {
-	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
-		vdev);
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	char *tmp_vdev = NULL;
+	int i, ret = 0;
 
-	return 0;
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
+	memset(dev_name, 0, sizeof(dev_name));
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
+	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
+	if (!rawdev)
+		return -ENODEV;
+	ifpga_dev = ifpga_rawdev_get(rawdev);
+	if (!ifpga_dev)
+		return -ENODEV;
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
+	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME), dev_name);
+
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		tmp_vdev = ifpga_dev->vdev_name[i];
+		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
+			free(tmp_vdev);
+			ifpga_dev->vdev_name[i] = NULL;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static struct rte_vdev_driver ifpga_cfg_driver = {
diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
index 857b734..eb9a9a5 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.h
+++ b/drivers/raw/ifpga/ifpga_rawdev.h
@@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
 
 #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
 #define IFPGA_RAWDEV_NUM 32
+#define IFPGA_MAX_VDEV 4
 #define IFPGA_MAX_IRQ 12
 
 struct ifpga_rawdev {
@@ -64,6 +65,13 @@ struct ifpga_rawdev {
 	void *intr_handle[IFPGA_MAX_IRQ];
 	/* enable monitor thread poll device's sensors or not */
 	int poll_enabled;
+	/* name of virtual devices created on raw device */
+	char *vdev_name[IFPGA_MAX_VDEV];
+};
+
+struct ifpga_vdev_args {
+	char bdf[8];
+	int port;
 };
 
 struct ifpga_rawdev *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
  2022-05-26  3:32       ` [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
  2022-05-26  3:32       ` [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-26  3:32       ` Wei Huang
  2022-05-26  6:41         ` Xu, Rosen
  2022-05-27  2:57         ` Zhang, Tianfei
  2022-05-26  3:32       ` [PATCH v3 4/5] raw/ifpga: support ofs card probe Wei Huang
                         ` (2 subsequent siblings)
  5 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

In original implementation, interrupts are unregistered in
ifpga_rawdev_destroy function. If application want to release
the ifpga driver resource by calling rte_rawdev_pmd_release,
interrupt resource will not be released.
Now interrupt unregistration is moved from ifpga destroy function
to ifpga close function, when rte_rawdev_pmd_release is called,
rte_rawdev_close will be called, then interrupts are unregistered.

Signed-off-by: Wei Huang <wei.huang@intel.com>
---
v2: update commit log
---
 drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index fe3fc43..94df56c 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(
 static int ifpga_pci_find_next_ext_capability(unsigned int fd,
 					      int start, uint32_t cap);
 static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
+static void fme_interrupt_handler(void *param);
 
 struct ifpga_rawdev *
 ifpga_rawdev_get(const struct rte_rawdev *rawdev)
@@ -740,8 +741,9 @@ static int set_surprise_link_check_aer(
 {
 	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	struct opae_manager *mgr;
 	char *vdev_name = NULL;
-	int i = 0;
+	int i, ret = 0;
 
 	if (dev) {
 		ifpga_rdev = ifpga_rawdev_get(dev);
@@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
 		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
+			mgr = opae_adapter_get_mgr(adapter);
+			if (ifpga_rdev && mgr) {
+				if (ifpga_unregister_msix_irq(ifpga_rdev,
+					IFPGA_FME_IRQ, 0,
+					fme_interrupt_handler, mgr) < 0)
+					ret = -EINVAL;
+			}
 			opae_adapter_destroy(adapter);
 			opae_adapter_data_free(adapter->data);
 		}
 	}
 
-	return dev ? 0:1;
+	return ret;
 }
 
 static int
@@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	int ret;
 	struct rte_rawdev *rawdev;
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
-	struct opae_adapter *adapter;
-	struct opae_manager *mgr;
-	struct ifpga_rawdev *dev;
 
 	if (!pci_dev) {
 		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
@@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
 		return -EINVAL;
 	}
-	dev = ifpga_rawdev_get(rawdev);
-
-	adapter = ifpga_rawdev_get_priv(rawdev);
-	if (!adapter)
-		return -ENODEV;
-
-	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
-		return -ENODEV;
-
-	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
-				fme_interrupt_handler, mgr) < 0)
-		return -EINVAL;
 
 	/* rte_rawdev_close is called by pmd_release */
 	ret = rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 4/5] raw/ifpga: support ofs card probe
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
                         ` (2 preceding siblings ...)
  2022-05-26  3:32       ` [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-26  3:32       ` Wei Huang
  2022-05-26  6:46         ` Xu, Rosen
  2022-05-27  3:10         ` Zhang, Tianfei
  2022-05-26  3:32       ` [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
  5 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

PAC N6000 is the first OFS platform, its device id is added to ifpga
device support list.

Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
Feature List) starts from BAR0 by default, port DFL location is indicated
in PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port
DFL location can be defined individually in PCIe VSEC (Vendor Specific
Extented Capabilities). In this patch, DFL definition is searched in VSEC,
the legacy DFL is used only when DFL VSEC is not present.

In original DFL enumeration process, AFU is expected to locate in port DFL,
but this is not the case in OFS implementation. In this patch, enumeration
can search AFU in any PF/VF which has no FME and port.

Signed-off-by: Wei Huang <wei.huang@intel.com>
---
v2: fix build error in UB2004-32
---
v3: update commit log with Tianfei's comment, treat 7 as special BAR index.
---
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 681 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
 9 files changed, 592 insertions(+), 192 deletions(-)

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index 4610ef1..f19cc26 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -13,15 +13,22 @@
 static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
 			      struct uuid *uuid)
 {
-	struct opae_bridge *br = acc->br;
-	struct ifpga_port_hw *port;
+	struct ifpga_afu_info *afu_info = acc->data;
+	struct opae_reg_region *region;
+	u64 val = 0;
 
-	if (!br || !br->data)
-		return -EINVAL;
+	if (!afu_info)
+		return -ENODEV;
 
-	port = br->data;
+	region = &afu_info->region[0];
+	if (uuid) {
+		val = readq(region->addr + sizeof(struct feature_header));
+		opae_memcpy(uuid->b, &val, sizeof(u64));
+		val = readq(region->addr + sizeof(struct feature_header) + 8);
+		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
+	}
 
-	return fpga_get_afu_uuid(port, uuid);
+	return 0;
 }
 
 static int ifpga_acc_set_irq(struct opae_accelerator *acc,
@@ -32,6 +39,9 @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
 	struct ifpga_port_hw *port;
 	struct fpga_uafu_irq_set irq_set;
 
+	if (!afu_info)
+		return -ENODEV;
+
 	if (!br || !br->data)
 		return -EINVAL;
 
@@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
 	struct ifpga_afu_info *afu_info = acc->data;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (info->index >= afu_info->num_regions)
 		return -EINVAL;
@@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
@@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h
index 8f62033..9a280eb 100644
--- a/drivers/raw/ifpga/base/ifpga_defines.h
+++ b/drivers/raw/ifpga/base/ifpga_defines.h
@@ -73,6 +73,7 @@
 enum fpga_id_type {
 	FME_ID,
 	PORT_ID,
+	AFU_ID,
 	FPGA_ID_MAX,
 };
 
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c b/drivers/raw/ifpga/base/ifpga_enumerate.c
index 48b8af4..0e09904 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.c
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
@@ -2,6 +2,10 @@
  * Copyright(c) 2010-2018 Intel Corporation
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
 #include "opae_hw_api.h"
 #include "ifpga_api.h"
 
@@ -9,6 +13,19 @@
 #include "ifpga_enumerate.h"
 #include "ifpga_feature_dev.h"
 
+struct dfl_fpga_enum_dfl {
+	u64 start;
+	u64 len;
+	void *addr;
+	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
+};
+
+TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl);
+struct dfl_fpga_enum_info {
+	struct ifpga_hw *hw;
+	struct dfl_fpga_enum_dfls dfls;
+};
+
 struct build_feature_devs_info {
 	struct opae_adapter_data_pci *pci_data;
 
@@ -21,7 +38,6 @@ struct build_feature_devs_info {
 	void *ioaddr;
 	void *ioend;
 	uint64_t phys_addr;
-	int current_bar;
 
 	void *pfme_hdr;
 
@@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
 			unsigned int size, unsigned int vec_start,
 			unsigned int vec_cnt)
 {
-	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
-			vec_cnt);
+	if (binfo->current_type != AFU_ID)
+		return build_info_add_sub_feature(binfo, start, fid, size,
+			vec_start, vec_cnt);
+	return 0;
 }
 
 /*
@@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
  */
 static bool feature_is_UAFU(struct build_feature_devs_info *binfo)
 {
-	if (binfo->current_type != PORT_ID)
-		return false;
+	if ((binfo->current_type == PORT_ID) ||
+		(binfo->current_type == AFU_ID))
+		return true;
 
-	return true;
+	return false;
 }
 
-static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
+static int parse_feature_uafu(struct build_feature_devs_info *binfo,
 				   struct feature_header *hdr)
 {
 	u64 id = PORT_FEATURE_ID_UAFU;
@@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	int ret;
 	int size;
 
+	if (binfo->acc_info) {
+		dev_info(binfo, "Sub AFU found @ %p.\n", start);
+		return 0;
+	}
+
 	capability.csr = readq(&port_hdr->capability);
 
-	size = capability.mmio_size << 10;
+	if (binfo->current_type == AFU_ID) {
+		size = AFU_REGION_SIZE;
+	} else {
+		capability.csr = readq(&port_hdr->capability);
+		size = capability.mmio_size << 10;
+	}
 
 	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
 	if (ret)
@@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	info->region[0].phys_addr = binfo->phys_addr +
 			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
 	info->region[0].len = size;
-	info->num_regions = 1;
+	info->num_regions = AFU_MAX_REGION;
 
 	binfo->acc_info = info;
 
 	return ret;
 }
 
-static int parse_feature_afus(struct build_feature_devs_info *binfo,
-			      struct feature_header *hdr)
-{
-	int ret;
-	struct feature_afu_header *afu_hdr, header;
-	u8 __iomem *start;
-	u8 __iomem *end = binfo->ioend;
-
-	start = (u8 __iomem *)hdr;
-	for (; start < end; start += header.next_afu) {
-		if ((unsigned int)(end - start) <
-			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
-			return -EINVAL;
-
-		hdr = (struct feature_header *)start;
-		afu_hdr = (struct feature_afu_header *)(hdr + 1);
-		header.csr = readq(&afu_hdr->csr);
-
-		if (feature_is_UAFU(binfo)) {
-			ret = parse_feature_port_uafu(binfo, hdr);
-			if (ret)
-				return ret;
-		}
-
-		if (!header.next_afu)
-			break;
-	}
-
-	return 0;
-}
-
 /* create and register proper private data */
 static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
@@ -235,13 +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	struct ifpga_fme_hw *fme;
 	struct ifpga_feature *feature;
 
-	if (!binfo->fiu)
-		return 0;
-
 	if (binfo->current_type == PORT_ID) {
-		/* return error if no valid acc info data structure */
-		if (!info)
-			return -EFAULT;
+		if (!binfo->fiu)
+			return 0;
 
 		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
 				       binfo->fiu);
@@ -254,7 +248,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 		port = &hw->port[binfo->current_port_id];
 		feature = get_feature_by_id(&port->feature_list,
 				PORT_FEATURE_ID_UINT);
-		if (feature)
+		if (feature && info)
 			info->num_irqs = feature->vec_cnt;
 
 		acc = opae_accelerator_alloc(hw->adapter->name,
@@ -264,17 +258,21 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 			return -ENOMEM;
 		}
 
+		acc->adapter = hw->adapter;
 		acc->br = br;
 		if (hw->adapter->mgr)
 			acc->mgr = hw->adapter->mgr;
 		acc->index = br->id;
 
 		fme = &hw->fme;
-		fme->nums_acc_region = info->num_regions;
+		fme->nums_acc_region = info ? info->num_regions : 0;
 
 		opae_adapter_add_acc(hw->adapter, acc);
 
 	} else if (binfo->current_type == FME_ID) {
+		if (!binfo->fiu)
+			return 0;
+
 		mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,
 				&ifpga_mgr_network_ops, binfo->fiu);
 		if (!mgr)
@@ -282,6 +280,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 
 		mgr->adapter = hw->adapter;
 		hw->adapter->mgr = mgr;
+	} else if (binfo->current_type == AFU_ID) {
+		if (!info)
+			return -EFAULT;
+
+		info->num_irqs = 0;
+		acc = opae_accelerator_alloc(hw->adapter->name,
+					&ifpga_acc_ops, info);
+		if (!acc)
+			return -ENOMEM;
+
+		acc->adapter = hw->adapter;
+		acc->br = NULL;
+		acc->mgr = NULL;
+		acc->index = hw->num_afus++;
+
+		opae_adapter_add_acc(hw->adapter, acc);
 	}
 
 	binfo->fiu = NULL;
@@ -295,11 +309,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
 	int ret;
 
+	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
+		return 0;
+
 	ret = build_info_commit_dev(binfo);
 	if (ret)
 		return ret;
 
 	binfo->current_type = type;
+	binfo->acc_info = NULL;
 
 	if (type == FME_ID) {
 		binfo->fiu = &binfo->hw->fme;
@@ -311,6 +329,41 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	return 0;
 }
 
+static int parse_feature_afus(struct build_feature_devs_info *binfo,
+			      struct feature_header *hdr)
+{
+	int ret;
+	struct feature_afu_header *afu_hdr, header;
+	u8 __iomem *start;
+	u8 __iomem *end = binfo->ioend;
+
+	ret = build_info_create_dev(binfo, AFU_ID, 0);
+	if (ret)
+		return ret;
+
+	start = (u8 __iomem *)hdr;
+	for (; start < end; start += header.next_afu) {
+		if ((unsigned int)(end - start) <
+			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
+			return -EINVAL;
+
+		hdr = (struct feature_header *)start;
+		afu_hdr = (struct feature_afu_header *)(hdr + 1);
+		header.csr = readq(&afu_hdr->csr);
+
+		if (feature_is_UAFU(binfo)) {
+			ret = parse_feature_uafu(binfo, hdr);
+			if (ret)
+				return ret;
+		}
+
+		if (!header.next_afu)
+			break;
+	}
+
+	return 0;
+}
+
 static int parse_feature_fme(struct build_feature_devs_info *binfo,
 			     struct feature_header *start)
 {
@@ -405,7 +458,7 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 			if (ret)
 				return ret;
 		} else {
-			dev_info(binfo, "No AFUs detected on Port\n");
+			dev_info(binfo, "No AFU detected on Port\n");
 		}
 
 		break;
@@ -426,7 +479,7 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 
 	id = feature_id(start);
 
-	if (id == PORT_FEATURE_ID_UINT) {
+	if ((binfo->current_type == PORT_ID) && (id == PORT_FEATURE_ID_UINT)) {
 		struct feature_port_uint *port_uint = start;
 		struct feature_port_uint_cap uint_cap;
 
@@ -437,7 +490,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 		} else {
 			dev_debug(binfo, "UAFU doesn't support interrupt\n");
 		}
-	} else if (id == PORT_FEATURE_ID_ERROR) {
+	} else if ((binfo->current_type == PORT_ID) &&
+			(id == PORT_FEATURE_ID_ERROR)) {
 		struct feature_port_error *port_err = start;
 		struct feature_port_err_capability port_err_cap;
 
@@ -449,7 +503,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 			dev_debug(&binfo, "Port error doesn't support interrupt\n");
 		}
 
-	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
+	} else if ((binfo->current_type == FME_ID) &&
+			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
 		struct feature_fme_err *fme_err = start;
 		struct feature_fme_error_capability fme_err_cap;
 
@@ -497,9 +552,15 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
 		return parse_feature_fme_private(binfo, hdr);
 	case PORT_ID:
 		return parse_feature_port_private(binfo, hdr);
+	case AFU_ID:
+		dev_err(binfo, "private feature %x belonging to AFU "
+			"is not supported yet.\n", header.id);
+		break;
 	default:
-		dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n",
+		dev_err(binfo, "private feature %x belonging to TYPE %d "
+			"(unknown_type) is not supported yet.\n",
 			header.id, binfo->current_type);
+		break;
 	}
 	return 0;
 }
@@ -530,32 +591,57 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return ret;
 }
 
-static int
-parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
+static int build_info_prepare(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
 {
+	if (!binfo || !dfl)
+		return -EINVAL;
+
+	binfo->ioaddr = dfl->addr;
+	binfo->ioend = (u8 *)dfl->addr + dfl->len;
+	binfo->phys_addr = dfl->start;
+
+	return 0;
+}
+
+static int parse_feature_list(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
+{
+	u8 *start, *end;
 	struct feature_header *hdr, header;
-	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
 	int ret = 0;
 
+	ret = build_info_prepare(binfo, dfl);
+	if (ret)
+		return ret;
+
+	start = (u8 *)binfo->ioaddr;
+	end = (u8 *)binfo->ioend;
+
+	/* walk through the device feature list via DFH's next DFH pointer. */
 	for (; start < end; start += header.next_header_offset) {
 		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
-			dev_err(binfo, "The region is too small to contain a feature.\n");
-			ret =  -EINVAL;
+			dev_err(binfo, "The region is too small to "
+				"contain a feature.\n");
+			ret = -EINVAL;
 			break;
 		}
 
 		hdr = (struct feature_header *)start;
-		header.csr = readq(hdr);
+		header.csr = opae_readq(hdr);
 
-		dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n",
-			__func__, hdr, (unsigned long long)header.csr,
-			header.id, header.next_header_offset,
-			header.end_of_list, header.type);
+		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
+			"header.id=0x%x, header.next_offset=0x%x, "
+			"header.eol=0x%x, header.type=0x%x\n",
+			__func__, hdr, header.csr, header.id,
+			header.next_header_offset, header.end_of_list,
+			header.type);
 
 		ret = parse_feature(binfo, hdr);
 		if (ret)
 			return ret;
 
+		/* stop parsing if EOL(End of List) is set or offset is 0 */
 		if (header.end_of_list || !header.next_header_offset)
 			break;
 	}
@@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return build_info_commit_dev(binfo);
 }
 
-/* switch the memory mapping to BAR# @bar */
-static int parse_switch_to(struct build_feature_devs_info *binfo, int bar)
-{
-	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
-
-	if (!pci_data->region[bar].addr)
-		return -ENOMEM;
-
-	binfo->ioaddr = pci_data->region[bar].addr;
-	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len;
-	binfo->phys_addr = pci_data->region[bar].phys_addr;
-	binfo->current_bar = bar;
-
-	return 0;
-}
-
-static int parse_ports_from_fme(struct build_feature_devs_info *binfo)
-{
-	struct feature_fme_header *fme_hdr;
-	struct feature_fme_port port;
-	int i = 0, ret = 0;
-
-	if (!binfo->pfme_hdr) {
-		dev_info(binfo,  "VF is detected.\n");
-		return ret;
-	}
-
-	fme_hdr = binfo->pfme_hdr;
-
-	do {
-		port.csr = readq(&fme_hdr->port[i]);
-		if (!port.port_implemented)
-			break;
-
-		/* skip port which only could be accessed via VF */
-		if (port.afu_access_control == FME_AFU_ACCESS_VF)
-			continue;
-
-		ret = parse_switch_to(binfo, port.port_bar);
-		if (ret)
-			break;
-
-		ret = parse_feature_list(binfo,
-					 (u8 __iomem *)binfo->ioaddr +
-					  port.port_offset);
-		if (ret)
-			break;
-	} while (++i < MAX_FPGA_PORT_NUM);
-
-	return ret;
-}
-
-static struct build_feature_devs_info *
-build_info_alloc_and_init(struct ifpga_hw *hw)
-{
-	struct build_feature_devs_info *binfo;
-
-	binfo = zmalloc(sizeof(*binfo));
-	if (!binfo)
-		return binfo;
-
-	binfo->hw = hw;
-	binfo->pci_data = hw->pci_data;
-
-	/* fpga feature list starts from BAR 0 */
-	if (parse_switch_to(binfo, 0)) {
-		free(binfo);
-		return NULL;
-	}
-
-	return binfo;
-}
-
 static void build_info_free(struct build_feature_devs_info *binfo)
 {
-	free(binfo);
+	opae_free(binfo);
 }
 
 static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
@@ -648,6 +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	struct ifpga_feature *feature;
 	int i;
 
+	if (fme->state == IFPGA_FME_UNUSED) {
+		dev_info(hw, "FME is not present\n");
+		return;
+	}
+
 	dev_info(hw, "found fme_device, is in PF: %s\n",
 		 is_ifpga_hw_pf(hw) ? "yes" : "no");
 
@@ -685,40 +703,411 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	}
 }
 
-int ifpga_bus_enumerate(struct ifpga_hw *hw)
+static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct ifpga_hw *hw)
 {
-	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_info *info;
+
+	info = opae_zmalloc(sizeof(*info));
+	if (!info)
+		return NULL;
+
+	info->hw = hw;
+	TAILQ_INIT(&info->dfls);
+
+	return info;
+}
+
+static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
+{
+	struct dfl_fpga_enum_dfl *tmp, *dfl;
+
+	if (!info)
+		return;
+
+	/* remove all device feature lists in the list. */
+	for (dfl = TAILQ_FIRST(&info->dfls);
+		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
+		dfl = tmp) {
+		TAILQ_REMOVE(&info->dfls, dfl, node);
+		opae_free(dfl);
+	}
+
+	opae_free(info);
+}
+
+static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
+	u64 start, u64 len, void *addr)
+{
+	struct dfl_fpga_enum_dfl *dfl;
+
+	dfl = opae_zmalloc(sizeof(*dfl));
+	if (!dfl)
+		return -ENOMEM;
+
+	dfl->start = start;
+	dfl->len = len;
+	dfl->addr = addr;
+
+	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
+
+	return 0;
+}
+
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+static int
+pci_find_next_ecap(int fd, int start, u32 cap)
+{
+	u32 header;
+	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+	int pos = PCI_CFG_SPACE_SIZE;
 	int ret;
 
-	binfo = build_info_alloc_and_init(hw);
+	if (start > 0)
+		pos = start;
+
+	ret = pread(fd, &header, sizeof(header), pos);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+		ret = pread(fd, &header, sizeof(header), pos);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PCI_EXT_CAP_ID_VNDR	0x0B
+#define PCI_VNDR_HEADER		4
+#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VSEC_ID_INTEL_DFLS 0x43
+#define PCI_VNDR_DFLS_CNT 0x8
+#define PCI_VNDR_DFLS_RES 0xc
+#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
+#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
+
+static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	char path[64];
+	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
+	int fd, ret, dfl_res_off, voff = 0;
+	u64 start, len;
+	void *addr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->adapter || !hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
+			hw->adapter->name);
+	if ((unsigned int)ret >= sizeof(path))
+		return -EINVAL;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -EIO;
+
+	while ((voff = pci_find_next_ecap(fd, voff,
+		PCI_EXT_CAP_ID_VNDR))) {
+		vndr_hdr = 0;
+		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
+			voff + PCI_VNDR_HEADER);
+		if (ret < 0)
+			return -EIO;
+		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
+			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
+			break;
+	}
+
+	if (!voff) {
+		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
+		return -ENODEV;
+	}
+
+	dfl_cnt = 0;
+	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
+	if (ret < 0)
+		return -EIO;
+
+	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
+	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
+		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
+		dfl_res = GENMASK(31, 0);
+		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
+		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
+		if (bir >= PCI_MAX_RESOURCE) {
+			dev_err(hw, "%s bad bir number %d\n",
+				__func__, bir);
+			return -EINVAL;
+		}
+
+		len = pci_data->region[bir].len;
+		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
+		if (offset >= len) {
+			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
+				__func__, offset, len);
+			return -EINVAL;
+		}
+
+		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
+		len -= offset;
+		start = pci_data->region[bir].phys_addr + offset;
+		addr = pci_data->region[bir].addr + offset;
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	}
+
+	return 0;
+}
+
+/* default method of finding dfls starting at offset 0 of bar 0 */
+static int
+find_dfls_by_default(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	int port_num, bar, i, ret = 0;
+	u64 start, len;
+	void *addr;
+	u32 offset;
+	struct feature_header hdr;
+	struct feature_fme_capability cap;
+	struct feature_fme_port port;
+	struct feature_fme_header *fme_hdr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	/* start to find Device Feature List from Bar 0 */
+	addr = pci_data->region[0].addr;
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * PF device has FME and Ports/AFUs, and VF device only has one
+	 * Port/AFU. Check them and add related "Device Feature List" info
+	 * for the next step enumeration.
+	 */
+	hdr.csr = opae_readq(addr);
+	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id == FEATURE_FIU_ID_FME)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+
+		/*
+		 * find more Device Feature Lists (e.g. Ports) per information
+		 * indicated by FME module.
+		 */
+		fme_hdr = (struct feature_fme_header *)addr;
+		cap.csr = opae_readq(&fme_hdr->capability);
+		port_num = (int)cap.num_ports;
+
+		dev_info(hw, "port_num = %d\n", port_num);
+		if (port_num > MAX_FPGA_PORT_NUM)
+			port_num = MAX_FPGA_PORT_NUM;
+
+		for (i = 0; i < port_num; i++) {
+			port.csr = opae_readq(&fme_hdr->port[i]);
+
+			/* skip ports which are not implemented. */
+			if (!port.port_implemented)
+				continue;
+
+			/* skip port which only could be accessed via VF */
+			if (port.afu_access_control == FME_AFU_ACCESS_VF)
+				continue;
+
+			/*
+			 * add Port's Device Feature List information for next
+			 * step enumeration.
+			 */
+			bar = (int)port.port_bar;
+			offset = port.port_offset;
+			if (bar == FME_PORT_OFST_BAR_SKIP) {
+				continue;
+			} else if (bar >= PCI_MAX_RESOURCE) {
+				dev_err(hw, "bad BAR %d for port %d\n", bar, i);
+				ret = -EINVAL;
+				break;
+			} else {
+				dev_info(hw, "BAR %d offset %u\n", bar, offset);
+			}
+
+			len = pci_data->region[bar].len;
+			if (offset >= len) {
+				dev_warn(hw, "bad port offset %u >= %pa\n",
+					 offset, &len);
+				continue;
+			}
+
+			len -= offset;
+			start = pci_data->region[bar].phys_addr + offset;
+			addr = pci_data->region[bar].addr + offset;
+			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+		}
+	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
+		(hdr.id == FEATURE_FIU_ID_PORT)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else if (hdr.type == FEATURE_TYPE_AFU) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else {
+		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
+			 hdr.type, hdr.id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
+{
+	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_dfl *dfl;
+	int ret = 0;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+
+	/* create and init build info for enumeration */
+	binfo = opae_zmalloc(sizeof(*binfo));
 	if (!binfo)
 		return -ENOMEM;
 
-	ret = parse_feature_list(binfo, binfo->ioaddr);
+	binfo->hw = info->hw;
+	binfo->pci_data = info->hw->pci_data;
+
+	/*
+	 * start enumeration for all feature devices based on Device Feature
+	 * Lists.
+	 */
+	TAILQ_FOREACH(dfl, &info->dfls, node) {
+		ret = parse_feature_list(binfo, dfl);
+		if (ret)
+			break;
+	}
+
+	build_info_free(binfo);
+
+	return ret;
+}
+
+int ifpga_bus_enumerate(struct ifpga_hw *hw)
+{
+	struct dfl_fpga_enum_info *info;
+	int ret;
+
+	/* allocate enumeration info */
+	info = dfl_fpga_enum_info_alloc(hw);
+	if (!info)
+		return -ENOMEM;
+
+	ret = find_dfls_by_vsec(info);
+	if (ret < 0)
+		ret = find_dfls_by_default(info);
+
 	if (ret)
 		goto exit;
 
-	ret = parse_ports_from_fme(binfo);
-	if (ret)
+	/* start enumeration with prepared enumeration information */
+	ret = dfl_fpga_feature_devs_enumerate(info);
+	if (ret < 0) {
+		dev_err(hw, "Enumeration failure\n");
 		goto exit;
+	}
 
 	ifpga_print_device_feature_list(hw);
 
 exit:
-	build_info_free(binfo);
+	dfl_fpga_enum_info_free(info);
+
 	return ret;
 }
 
-int ifpga_bus_init(struct ifpga_hw *hw)
+static void ifpga_print_acc_list(struct opae_adapter *adapter)
 {
+	struct opae_accelerator *acc;
+	struct ifpga_afu_info *info;
+	struct uuid guid;
+	char buf[48];
 	int i;
+
+	opae_adapter_for_each_acc(adapter, acc) {
+		info = acc->data;
+		if (!info)
+			continue;
+		acc->ops->get_uuid(acc, &guid);
+		i = sprintf(buf, "%02x%02x%02x%02x-",
+			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
+		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
+			guid.b[5], guid.b[4], guid.b[3],
+			guid.b[2], guid.b[1], guid.b[0]);
+		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
+			acc->name, acc->index, info->region[0].addr,
+			info->region[0].len, buf);
+	}
+}
+
+int ifpga_bus_init(struct ifpga_hw *hw)
+{
+	int i, ret = 0;
 	struct ifpga_port_hw *port;
 
-	fme_hw_init(&hw->fme);
+	ret = fme_hw_init(&hw->fme);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
 		port = &hw->port[i];
 		port_hw_init(port);
 	}
+	ifpga_print_acc_list(hw->adapter);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h b/drivers/raw/ifpga/base/ifpga_enumerate.h
index 95ed594..e6b04f0 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.h
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
@@ -5,6 +5,8 @@
 #ifndef _IFPGA_ENUMERATE_H_
 #define _IFPGA_ENUMERATE_H_
 
+#define FME_PORT_OFST_BAR_SKIP  7
+
 int ifpga_bus_init(struct ifpga_hw *hw);
 int ifpga_bus_uinit(struct ifpga_hw *hw);
 int ifpga_bus_enumerate(struct ifpga_hw *hw);
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c
index 0813513..dbecc7b 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
@@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
 	if (fpga_wait_register_field(port_sftrst_ack, control,
 				     &port_hdr->control, RST_POLL_TIMEOUT,
 				     RST_POLL_INVL)) {
-		dev_err(port, "timeout, fail to reset device\n");
+		dev_err(port, "timeout, fail to reset FIM port\n");
 		return -ETIMEDOUT;
 	}
 
@@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list *list)
 	struct ifpga_feature *feature;
 
 	TAILQ_FOREACH(feature, list, next) {
-		if (feature->state != IFPGA_FEATURE_ATTACHED)
+		if (feature->state != IFPGA_FEATURE_INITED)
 			continue;
 		if (feature->ops && feature->ops->uinit)
 			feature->ops->uinit(feature);
+		feature->state = IFPGA_FEATURE_ATTACHED;
 	}
 }
 
@@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
 					ret = feature->ops->init(feature);
 					if (ret)
 						goto error;
+					else
+						feature->state =
+							IFPGA_FEATURE_INITED;
 				}
 			}
 		}
@@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
 
 int fme_hw_init(struct ifpga_fme_hw *fme)
 {
-	int ret;
-
-	if (fme->state != IFPGA_FME_IMPLEMENTED)
-		return -ENODEV;
-
-	ret = feature_init(fme_feature_drvs, &fme->feature_list);
-	if (ret)
-		return ret;
+	if (fme->state == IFPGA_FME_IMPLEMENTED)
+		return feature_init(fme_feature_drvs, &fme->feature_list);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h
index ed5edc6..4d56deb 100644
--- a/drivers/raw/ifpga/base/ifpga_hw.h
+++ b/drivers/raw/ifpga/base/ifpga_hw.h
@@ -15,6 +15,7 @@
 enum ifpga_feature_state {
 	IFPGA_FEATURE_UNUSED = 0,
 	IFPGA_FEATURE_ATTACHED,
+	IFPGA_FEATURE_INITED
 };
 
 enum feature_type {
@@ -134,6 +135,7 @@ struct ifpga_hw {
 
 	struct ifpga_fme_hw fme;
 	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
+	int num_afus;
 };
 
 static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 11c9887..87256fc 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator *acc,
 int opae_acc_set_irq(struct opae_accelerator *acc,
 		     u32 start, u32 count, s32 evtfds[])
 {
-	if (!acc || !acc->data)
+	if (!acc)
 		return -EINVAL;
 
 	if (start + count <= start)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 7e04b56..fd40e09 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -143,6 +143,7 @@ struct opae_accelerator {
 	TAILQ_ENTRY(opae_accelerator) node;
 	const char *name;
 	int index;
+	struct opae_adapter *adapter;
 	struct opae_bridge *br;
 	struct opae_manager *mgr;
 	struct opae_accelerator_ops *ops;
@@ -240,6 +241,7 @@ struct opae_adapter_data {
 
 struct opae_reg_region {
 	u64 phys_addr;
+#define AFU_REGION_SIZE  0x8000
 	u64 len;
 	u8 *addr;
 };
diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 94df56c..ceb18ae 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -47,11 +47,13 @@
 #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
 #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
 #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
+#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
 /* VF Device */
 #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
 #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
 #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
 #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
+#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
 #define RTE_MAX_RAW_DEVICE           10
 
 static const struct rte_pci_id pci_ifpga_map[] = {
@@ -63,6 +65,8 @@
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),},
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N6000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N6000),},
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -110,6 +114,7 @@ struct ifpga_rawdev *
 
 	return IFPGA_RAWDEV_NUM;
 }
+
 static struct ifpga_rawdev *
 ifpga_rawdev_allocate(struct rte_rawdev *rawdev)
 {
@@ -365,7 +370,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 		return -ENODEV;
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
+	if (!mgr || !mgr->sensor_list)
 		return -ENODEV;
 
 	opae_mgr_for_each_sensor(mgr, sensor) {
@@ -377,7 +382,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 			goto fail;
 
 		if (value == 0xdeadbeef) {
-			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value %x\n",
+			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s value %x\n",
 					raw_dev->dev_id, sensor->name, value);
 			continue;
 		}
@@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(
 {
 	struct opae_adapter *adapter;
 	struct opae_manager *mgr;
-	struct opae_board_info *info;
+	struct opae_board_info *info = NULL;
 	struct rte_afu_pr_conf *afu_pr_conf;
 	int ret;
 	struct uuid uuid;
@@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
 	}
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr) {
-		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL");
-		return -1;
-	}
-
-	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
-		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
-		return -1;
+	if (mgr) {
+		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
+			IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
+			return -1;
+		}
 	}
 
-	if (info->lightweight) {
+	if (info && info->lightweight) {
 		/* set uuid to all 0, when fpga is lightweight image */
 		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
 		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
@@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
 			__func__,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
-		}
+	}
 	return 0;
 }
 
@@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
 	if (ret) {
 		ret = -ENOMEM;
-		goto free_adapter_data;
+		goto cleanup;
 	}
 
 	rawdev->dev_ops = &ifpga_rawdev_ops;
@@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	/* must enumerate the adapter before use it */
 	ret = opae_adapter_enumerate(adapter);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	/* get opae_manager to rawdev */
 	mgr = opae_adapter_get_mgr(adapter);
 	if (mgr) {
-		/* PF function */
-		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
+		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
+				fme_interrupt_handler, "fme_irq", mgr);
+		if (ret)
+			goto cleanup;
 	}
 
-	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
-			fme_interrupt_handler, "fme_irq", mgr);
-	if (ret)
-		goto free_adapter_data;
-
 	ret = ifpga_monitor_start_func(dev);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	return ret;
 
-free_adapter_data:
-	if (data)
-		opae_adapter_data_free(data);
 cleanup:
 	if (rawdev)
 		rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
                         ` (3 preceding siblings ...)
  2022-05-26  3:32       ` [PATCH v3 4/5] raw/ifpga: support ofs card probe Wei Huang
@ 2022-05-26  3:32       ` Wei Huang
  2022-05-26  6:47         ` Xu, Rosen
  2022-05-27  3:19         ` Zhang, Tianfei
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
  5 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-26  3:32 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

OFS (Open FPGA Stack) specification is introduced briefly.

Signed-off-by: Wei Huang <wei.huang@intel.com>
---
 doc/guides/rawdevs/ifpga.rst | 114 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 113 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst
index dbd0d6e..8809bfc 100644
--- a/doc/guides/rawdevs/ifpga.rst
+++ b/doc/guides/rawdevs/ifpga.rst
@@ -1,5 +1,5 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
-    Copyright(c) 2018 Intel Corporation.
+    Copyright(c) 2018-2022 Intel Corporation.
 
 IFPGA Rawdev Driver
 ======================
@@ -100,3 +100,115 @@ The following device parameters are supported:
 
   If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
   identifies AFU Bit Stream file.
+
+
+Open FPGA Stack
+=====================
+
+Open FPGA Stack (OFS) is a collection of RTL and open source software providing
+interfaces to access the instantiated RTL easily in an FPGA. OFS leverages the
+DFL for the implementation of the FPGA RTL design.
+
+OFS designs allow for the arrangement of software interfaces across multiple
+PCIe endpoints. Some of these interfaces may be PFs defined in the static region
+that connect to interfaces in an IP that is loaded via Partial Reconfiguration (PR).
+And some of these interfaces may be VFs defined in the PR region that can be
+reconfigured by the end-user. Furthermore, these PFs/VFs may use DFLs such that
+features may be discovered and accessed in user space (with the aid of a generic
+kernel driver like vfio-pci). The diagram below depicts an example design with two
+PFs and two VFs. In this example, it will export the management functions via PF0,
+PF1 will bind with virtio-net driver presenting itself as a network interface to
+the OS. The other functions, VF0 and VF1, leverage VFIO to export the MMIO space
+to an application or assign to a VM.::
+
+     +-----------------+  +--------------+  +-------------+  +------------+
+     | FPGA Management |  |   VirtIO     |  |  User App   |  | Virtual    |
+     |      App        |  |     App      |  |             |  | Machine    |
+     +--------+--------+  +------+-------+  +------+------+  +-----+------+
+              |                  |                 |               |
+     +--------+--------+  +------+-------+  +------+------+        |
+     |     DFL Driver  |  |VirtIO driver |  |    VFIO     |        |
+     +--------+--------+  +------+-------+  +------+------+        |
+              |                  |                 |               |
+              |                  |                 |               |
+     +--------+--------+  +------+-------+  +------+------+   +----+------+
+     |     PF0         |  |     PF1      |  |   PF0_VF0   |   |  PF0_VF1  |
+     +-----------------+  +--------------+  +-------------+   +-----------+
+
+As accelerators are specialized hardware, they are typically limited in the
+number installed in a given system. Many use cases require them to be shared
+across multiple software contexts or threads of software execution, either
+through partitioning of individual dedicated resources, or virtualization of
+shared resources. OFS provides several models to share the AFU resources via
+PR mechanism and hardware-based virtualization schemes.
+
+1. Legacy model.
+   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
+   a notion that the boundary between the AFU and the shell is also the unit of
+   PR for those FPGA platforms. This model is only able to handle a
+   single context, because it only has one PR engine, and one PR region which
+   has an associated Port device.
+2. Multiple VFs per PR slot.
+   In this model, available AFU resources may allow instantiation of many VFs
+   which have a dedicated PCIe function with their own dedicated MMIO space, or
+   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
+   card has implemented this model.
+   In this model, the AFU/PR slot was not connected to port device. For DFL's view,
+   the Next_AFU pointer in FIU feature header of port device points to NULL in this
+   model, so in AFU driver perspective, there is no AFU MMIO region managed by
+   AFU driver. On the other hand, each VF can start with an AFU feature header without
+   being connected to a FIU Port feature header.
+
+In multiple VFs per PR slot model, the port device can still be accessed using
+ioctls API which expose /dev/dfl-port.h device nodes, like port reset, get
+port info, whose APIs were mentioned in AFU section in this documentation. But
+it cannot access the AFU MMIO space via AFU ioctl APIs like DFL_FPGA_PORT_DMA_MAP
+because there is no AFU MMIO space managed in the AFU driver. Users can access
+the AFU resource by creating VF devices via PCIe SRIOV interface, and then access
+the VF via VFIO driver or assign the VF to VM.
+
+In multiple VFs per PR slot model, the steps to enable VFs are compatible with
+legacy mode which are mentioned in "FPGA virtualization - PCIe SRIOV" section
+in this documentation.
+
+OFS provides the diversity for accessing the AFU resource to RTL developer.
+An IP designer may choose to add more than one PF for interfacing with IP
+on the FPGA and choose different model to access the AFU resource.
+
+There is one reference architecture design using the "Multiple VFs per PR slot"
+model for OFS as illustrated below. In this reference design, it exports the
+FPGA management functions via PF0. PF1 will bind with virtio-net driver
+presenting itself as a network interface to the OS. PF2 will bind to the
+vfio-pci driver allowing the user space software to discover and interface
+with the specific workload like diagnostic test. To access the AFU resource,
+it uses SR-IOV to partition workload interfaces across various VFs.::
+
+                              +----------------------+
+                              |   PF/VF mux/demux    |
+                              +--+--+-----+------+-+-+
+                                 |  |     |      | |
+        +------------------------+  |     |      | |
+  PF0   |                 +---------+   +-+      | |
+    +---+---+             |         +---+----+   | |
+    |  DFH  |             |         |   DFH  |   | |
+    +-------+       +-----+----+    +--------+   | |
+    |  FME  |       |  VirtIO  |    |  Test  |   | |
+    +---+---+       +----------+    +--------+   | |
+        |                PF1            PF2      | |
+        |                                        | |
+        |                             +----------+ |
+        |                             |           ++
+        |                             |           |
+        |                             | PF0_VF0   | PF0_VF1
+        |           +-----------------+-----------+------------+
+        |           |           +-----+-----------+--------+   |
+        |           |           |     |           |        |   |
+        |           | +------+  |  +--+ -+     +--+---+    |   |
+        |           | | Port |  |  | DFH |     |  DFH |    |   |
+        +-----------+ +------+  |  +-----+     +------+    |   |
+                    |           |  | DEV |     |  DEV |    |   |
+                    |           |  +-----+     +------+    |   |
+                    |           |            PR Slot       |   |
+                    |           +--------------------------+   |
+                    | Port Gasket                              |
+                    +------------------------------------------+
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-26  3:32       ` [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-26  6:29         ` Xu, Rosen
  0 siblings, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-05-26  6:29 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi Wei,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs
> 
> These APIs are introduced in DPDK 21.05 and have been tested in several
> release, experimental tag can be formally removed.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
> ---
>  drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
>  drivers/raw/ifpga/version.map     |  7 ++----
>  2 files changed, 2 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h
> b/drivers/raw/ifpga/rte_pmd_ifpga.h
> index 47d66ba..3fa5d34 100644
> --- a/drivers/raw/ifpga/rte_pmd_ifpga.h
> +++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
> @@ -68,9 +68,6 @@
>  } rte_pmd_ifpga_phy_info;
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
>   *
>   * @param pci_addr
> @@ -82,14 +79,10 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-ENODEV) if FPGA is not probed by ifpga driver.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get current RSU status of the specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -103,14 +96,10 @@
>   *   - (-ENODEV) if dev_id is invalid.
>   *   - (-ENOMEM) if share data is not initialized.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t
> *prog);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Set current RSU status of the specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -124,14 +113,10 @@
>   *   - (-ENODEV) if dev_id is invalid.
>   *   - (-ENOMEM) if share data is not initialized.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t
> prog);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get FPGA property of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -144,14 +129,10 @@
>   *   - (-EBUSY) if FPGA is rebooting.
>   *   - (-EIO) if failed to access hardware.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get PHY information of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -164,14 +145,10 @@
>   *   - (-EBUSY) if FPGA is rebooting.
>   *   - (-EIO) if failed to access hardware.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info
> *info);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Update image flash of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -187,15 +164,11 @@
>   *   - (-EBUSY) if FPGA is updating or rebooting.
>   *   - (-EIO) if failed to open image file.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
>  	uint64_t *status);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Stop flash update of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -208,14 +181,10 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-EAGAIN) if failed with force.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Check current Intel FPGA status and change it to reboot status if it is idle
>   *
>   * @param dev_id
> @@ -226,14 +195,10 @@
>   *   - (-ENOMEM) if share data is not initialized.
>   *   - (-EBUSY) if FPGA is updating or rebooting.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_reboot_try(uint16_t dev_id);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Trigger full reconfiguration of specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -252,28 +217,20 @@
>   *   - (-EINVAL) if bad parameter.
>   *   - (-EBUSY) if failed to access BMC register.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Get PCI bus the Intel FPGA driver register to
>   *
>   * @return
>   *   - (valid pointer) if successful.
>   *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
>   */
> -__rte_experimental
>  const struct rte_pci_bus *
>  rte_pmd_ifpga_get_pci_bus(void);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Perform PR (partial reconfiguration) on specified Intel FPGA device
>   *
>   * @param dev_id
> @@ -287,17 +244,12 @@
>   *   - (-EINVAL) if bad parameter or operation failed.
>   *   - (-ENOMEM) if failed to allocate memory.
>   */
> -__rte_experimental
>  int
>  rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char
> *file);
> 
>  /**
> - * @warning
> - * @b EXPERIMENTAL: this API may change, or be removed, without prior
> notice
> - *
>   * Free software resources allocated by Intel FPGA PMD
>   */
> -__rte_experimental
>  void
>  rte_pmd_ifpga_cleanup(void);
> 
> diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
> index a1a6be2..ff71a45 100644
> --- a/drivers/raw/ifpga/version.map
> +++ b/drivers/raw/ifpga/version.map
> @@ -1,11 +1,6 @@
>  DPDK_22 {
> -	local: *;
> -};
> -
> -EXPERIMENTAL {
>  	global:
> 
> -	# added in 21.05
>  	rte_pmd_ifpga_get_dev_id;
>  	rte_pmd_ifpga_get_rsu_status;
>  	rte_pmd_ifpga_set_rsu_status;
> @@ -18,4 +13,6 @@ EXPERIMENTAL {
>  	rte_pmd_ifpga_get_pci_bus;
>  	rte_pmd_ifpga_partial_reconfigure;
>  	rte_pmd_ifpga_cleanup;
> +
> +	local: *;
>  };
> --
> 1.8.3.1

Reviewed-by Rosen Xu <rosen.xu@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-05-26  3:32       ` [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-26  6:34         ` Xu, Rosen
  0 siblings, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-05-26  6:34 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi Wei,

My comments.

Thanks,
Rosen
> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed
> 
> Virtual devices created on ifpga raw device will not be removed when ifpga
> device has closed. To avoid resource leak problem, this patch introduces an
> ifpga virtual device remove function, virtual devices will be destroyed after
> the ifpga raw device closed.
> 
> Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: update commit log, use macro to replace immediate value.
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 166
> ++++++++++++++++++++++++++++++---------
>  drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
>  2 files changed, 138 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 6d4117c..fe3fc43 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -134,6 +134,8 @@ struct ifpga_rawdev *
>  	for (i = 0; i < IFPGA_MAX_IRQ; i++)
>  		dev->intr_handle[i] = NULL;
>  	dev->poll_enabled = 0;
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++)
> +		dev->vdev_name[i] = NULL;
> 
>  	return dev;
>  }
> @@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(  static int
> ifpga_rawdev_close(struct rte_rawdev *dev)  {
> +	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	char *vdev_name = NULL;
> +	int i = 0;
> 
>  	if (dev) {
> -		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
> +		ifpga_rdev = ifpga_rawdev_get(dev);
> +		if (ifpga_rdev) {
> +			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +				vdev_name = ifpga_rdev->vdev_name[i];
> +				if (vdev_name)
> +					rte_vdev_uninit(vdev_name);
> +			}
> +			ifpga_monitor_stop_func(ifpga_rdev);
> +			ifpga_rdev->rawdev = NULL;
> +		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
>  			opae_adapter_destroy(adapter);
> @@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		return -EINVAL;
>  	}
>  	dev = ifpga_rawdev_get(rawdev);
> -	if (dev)
> -		dev->rawdev = NULL;
> 
>  	adapter = ifpga_rawdev_get_priv(rawdev);
>  	if (!adapter)
> @@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const
> char *key __rte_unused,
> 
>  	return 0;
>  }
> +
>  static int
> -ifpga_cfg_probe(struct rte_vdev_device *dev)
> +ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
> +	struct ifpga_vdev_args *args)
>  {
> -	struct rte_devargs *devargs;
> -	struct rte_kvargs *kvlist = NULL;
> -	struct rte_rawdev *rawdev = NULL;
> -	struct ifpga_rawdev *ifpga_dev;
> -	int port;
> +	struct rte_kvargs *kvlist;
>  	char *name = NULL;
> -	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> -	int ret = -1;
> +	int port = 0;
> +	int ret = -EINVAL;
> 
> -	devargs = dev->device.devargs;
> +	if (!devargs || !args)
> +		return ret;
> 
>  	kvlist = rte_kvargs_parse(devargs->args, valid_args);
>  	if (!kvlist) {
> -		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing
> param");
> -		goto end;
> +		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
> +		return ret;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
>  		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
> -				       &ifpga_rawdev_get_string_arg,
> -				       &name) < 0) {
> +			&ifpga_rawdev_get_string_arg, &name) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
> -				     IFPGA_ARG_NAME);
> +				IFPGA_ARG_NAME);
>  			goto end;
> +		} else {
> +			strlcpy(args->bdf, name, sizeof(args->bdf));
> +			rte_free(name);
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga
> bus",
> -			  IFPGA_ARG_NAME);
> +			IFPGA_ARG_NAME);
>  		goto end;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
> -		if (rte_kvargs_process(kvlist,
> -			IFPGA_ARG_PORT,
> -			&rte_ifpga_get_integer32_arg,
> -			&port) < 0) {
> +		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
> +			&rte_ifpga_get_integer32_arg, &port) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
>  				IFPGA_ARG_PORT);
>  			goto end;
> +		} else {
> +			args->port = port;
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga
> bus",
> -			  IFPGA_ARG_PORT);
> +			IFPGA_ARG_PORT);
>  		goto end;
>  	}
> 
> +	ret = 0;
> +
> +end:
> +	if (kvlist)
> +		rte_kvargs_free(kvlist);
> +
> +	return ret;
> +}
> +
> +static int
> +ifpga_cfg_probe(struct rte_vdev_device *vdev) {
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	int i, n, ret = 0;
> +
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
>  	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> name);
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
>  	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
>  	if (!rawdev)
> -		goto end;
> +		return -ENODEV;
>  	ifpga_dev = ifpga_rawdev_get(rawdev);
>  	if (!ifpga_dev)
> -		goto end;
> +		return -ENODEV;
> 
> -	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> -	port, name);
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		if (ifpga_dev->vdev_name[i] == NULL) {
> +			n = strlen(vdev_name) + 1;
> +			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
> +			if (ifpga_dev->vdev_name[i] == NULL)
> +				return -ENOMEM;
> +			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
> +			break;
> +		}
> +	}
> 
> +	if (i >= IFPGA_MAX_VDEV) {
> +		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual
> device!");
> +		return -ENOENT;
> +	}
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
>  	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
> -			dev_name, devargs->args);
> -end:
> -	rte_kvargs_free(kvlist);
> -	free(name);
> +			dev_name, vdev->device.devargs->args);
> +	if (ret) {
> +		rte_free(ifpga_dev->vdev_name[i]);
> +		ifpga_dev->vdev_name[i] = NULL;
> +	}
> 
>  	return ret;
>  }
> @@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const
> char *key __rte_unused,  static int  ifpga_cfg_remove(struct
> rte_vdev_device *vdev)  {
> -	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
> -		vdev);
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	char *tmp_vdev = NULL;
> +	int i, ret = 0;
> 
> -	return 0;
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
> +	memset(dev_name, 0, sizeof(dev_name));
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
> +	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
> +	if (!rawdev)
> +		return -ENODEV;
> +	ifpga_dev = ifpga_rawdev_get(rawdev);
> +	if (!ifpga_dev)
> +		return -ENODEV;
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
> +	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME),
> dev_name);
> +
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		tmp_vdev = ifpga_dev->vdev_name[i];
> +		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
> +			free(tmp_vdev);
> +			ifpga_dev->vdev_name[i] = NULL;
> +			break;
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static struct rte_vdev_driver ifpga_cfg_driver = { diff --git
> a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
> index 857b734..eb9a9a5 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.h
> +++ b/drivers/raw/ifpga/ifpga_rawdev.h
> @@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
> 
>  #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
>  #define IFPGA_RAWDEV_NUM 32
> +#define IFPGA_MAX_VDEV 4
>  #define IFPGA_MAX_IRQ 12
> 
>  struct ifpga_rawdev {
> @@ -64,6 +65,13 @@ struct ifpga_rawdev {
>  	void *intr_handle[IFPGA_MAX_IRQ];
>  	/* enable monitor thread poll device's sensors or not */
>  	int poll_enabled;
> +	/* name of virtual devices created on raw device */
> +	char *vdev_name[IFPGA_MAX_VDEV];
> +};
> +
> +struct ifpga_vdev_args {
> +	char bdf[8];
It seems like a PCIe bdf name, can you replace the constant with PCI_PRI_STR_SIZE?
> +	int port;
>  };
> 
>  struct ifpga_rawdev *
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-26  3:32       ` [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-26  6:41         ` Xu, Rosen
  2022-05-27  2:57         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-05-26  6:41 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi Wei,

It's a little bit hard to find the connections between functions you changed and raw API.
Could you add more explanations about the Function Call in the functions you mentioned below?

Thanks,
Rosen

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function
> 
> In original implementation, interrupts are unregistered in
> ifpga_rawdev_destroy function. If application want to release the ifpga
> driver resource by calling rte_rawdev_pmd_release, interrupt resource will
> not be released.
> Now interrupt unregistration is moved from ifpga destroy function to ifpga
> close function, when rte_rawdev_pmd_release is called, rte_rawdev_close
> will be called, then interrupts are unregistered.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: update commit log
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index fe3fc43..94df56c 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(  static int
> ifpga_pci_find_next_ext_capability(unsigned int fd,
>  					      int start, uint32_t cap);
>  static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
> +static void fme_interrupt_handler(void *param);
> 
>  struct ifpga_rawdev *
>  ifpga_rawdev_get(const struct rte_rawdev *rawdev) @@ -740,8 +741,9 @@
> static int set_surprise_link_check_aer(  {
>  	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	struct opae_manager *mgr;
>  	char *vdev_name = NULL;
> -	int i = 0;
> +	int i, ret = 0;
> 
>  	if (dev) {
>  		ifpga_rdev = ifpga_rawdev_get(dev);
> @@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
>  		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
> +			mgr = opae_adapter_get_mgr(adapter);
> +			if (ifpga_rdev && mgr) {
> +				if (ifpga_unregister_msix_irq(ifpga_rdev,
> +					IFPGA_FME_IRQ, 0,
> +					fme_interrupt_handler, mgr) < 0)
> +					ret = -EINVAL;
> +			}
>  			opae_adapter_destroy(adapter);
>  			opae_adapter_data_free(adapter->data);
>  		}
>  	}
> 
> -	return dev ? 0:1;
> +	return ret;
>  }
> 
>  static int
> @@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	int ret;
>  	struct rte_rawdev *rawdev;
>  	char name[RTE_RAWDEV_NAME_MAX_LEN];
> -	struct opae_adapter *adapter;
> -	struct opae_manager *mgr;
> -	struct ifpga_rawdev *dev;
> 
>  	if (!pci_dev) {
>  		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
> @@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)",
> name);
>  		return -EINVAL;
>  	}
> -	dev = ifpga_rawdev_get(rawdev);
> -
> -	adapter = ifpga_rawdev_get_priv(rawdev);
> -	if (!adapter)
> -		return -ENODEV;
> -
> -	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> -		return -ENODEV;
> -
> -	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
> -				fme_interrupt_handler, mgr) < 0)
> -		return -EINVAL;
> 
>  	/* rte_rawdev_close is called by pmd_release */
>  	ret = rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 4/5] raw/ifpga: support ofs card probe
  2022-05-26  3:32       ` [PATCH v3 4/5] raw/ifpga: support ofs card probe Wei Huang
@ 2022-05-26  6:46         ` Xu, Rosen
  2022-05-27  3:10         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-05-26  6:46 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi Wei,

Pls close compile warnings. Thanks a lot.

Thanks,
Rosen

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 4/5] raw/ifpga: support ofs card probe
> 
> PAC N6000 is the first OFS platform, its device id is added to ifpga device
> support list.
> 
> Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
> Feature List) starts from BAR0 by default, port DFL location is indicated in
> PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port
> DFL location can be defined individually in PCIe VSEC (Vendor Specific
> Extented Capabilities). In this patch, DFL definition is searched in VSEC, the
> legacy DFL is used only when DFL VSEC is not present.
> 
> In original DFL enumeration process, AFU is expected to locate in port DFL,
> but this is not the case in OFS implementation. In this patch, enumeration can
> search AFU in any PF/VF which has no FME and port.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: fix build error in UB2004-32
> ---
> v3: update commit log with Tianfei's comment, treat 7 as special BAR index.
> ---
>  drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
>  drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
>  drivers/raw/ifpga/base/ifpga_enumerate.c   | 681
> ++++++++++++++++++++++-------
>  drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
>  drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
>  drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
>  drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
>  drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
>  drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
>  9 files changed, 592 insertions(+), 192 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_api.c
> b/drivers/raw/ifpga/base/ifpga_api.c
> index 4610ef1..f19cc26 100644
> --- a/drivers/raw/ifpga/base/ifpga_api.c
> +++ b/drivers/raw/ifpga/base/ifpga_api.c
> @@ -13,15 +13,22 @@
>  static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
>  			      struct uuid *uuid)
>  {
> -	struct opae_bridge *br = acc->br;
> -	struct ifpga_port_hw *port;
> +	struct ifpga_afu_info *afu_info = acc->data;
> +	struct opae_reg_region *region;
> +	u64 val = 0;
> 
> -	if (!br || !br->data)
> -		return -EINVAL;
> +	if (!afu_info)
> +		return -ENODEV;
> 
> -	port = br->data;
> +	region = &afu_info->region[0];
> +	if (uuid) {
> +		val = readq(region->addr + sizeof(struct feature_header));
> +		opae_memcpy(uuid->b, &val, sizeof(u64));
> +		val = readq(region->addr + sizeof(struct feature_header) + 8);
> +		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
> +	}
> 
> -	return fpga_get_afu_uuid(port, uuid);
> +	return 0;
>  }
> 
>  static int ifpga_acc_set_irq(struct opae_accelerator *acc, @@ -32,6 +39,9
> @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
>  	struct ifpga_port_hw *port;
>  	struct fpga_uafu_irq_set irq_set;
> 
> +	if (!afu_info)
> +		return -ENODEV;
> +
>  	if (!br || !br->data)
>  		return -EINVAL;
> 
> @@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct
> opae_accelerator *acc,
>  	struct ifpga_afu_info *afu_info = acc->data;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (info->index >= afu_info->num_regions)
>  		return -EINVAL;
> @@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc,
> unsigned int region_idx,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> @@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator
> *acc,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> diff --git a/drivers/raw/ifpga/base/ifpga_defines.h
> b/drivers/raw/ifpga/base/ifpga_defines.h
> index 8f62033..9a280eb 100644
> --- a/drivers/raw/ifpga/base/ifpga_defines.h
> +++ b/drivers/raw/ifpga/base/ifpga_defines.h
> @@ -73,6 +73,7 @@
>  enum fpga_id_type {
>  	FME_ID,
>  	PORT_ID,
> +	AFU_ID,
>  	FPGA_ID_MAX,
>  };
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c
> b/drivers/raw/ifpga/base/ifpga_enumerate.c
> index 48b8af4..0e09904 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.c
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
> @@ -2,6 +2,10 @@
>   * Copyright(c) 2010-2018 Intel Corporation
>   */
> 
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <unistd.h>
> +
>  #include "opae_hw_api.h"
>  #include "ifpga_api.h"
> 
> @@ -9,6 +13,19 @@
>  #include "ifpga_enumerate.h"
>  #include "ifpga_feature_dev.h"
> 
> +struct dfl_fpga_enum_dfl {
> +	u64 start;
> +	u64 len;
> +	void *addr;
> +	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
> +};
> +
> +TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl); struct
> +dfl_fpga_enum_info {
> +	struct ifpga_hw *hw;
> +	struct dfl_fpga_enum_dfls dfls;
> +};
> +
>  struct build_feature_devs_info {
>  	struct opae_adapter_data_pci *pci_data;
> 
> @@ -21,7 +38,6 @@ struct build_feature_devs_info {
>  	void *ioaddr;
>  	void *ioend;
>  	uint64_t phys_addr;
> -	int current_bar;
> 
>  	void *pfme_hdr;
> 
> @@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
>  			unsigned int size, unsigned int vec_start,
>  			unsigned int vec_cnt)
>  {
> -	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
> -			vec_cnt);
> +	if (binfo->current_type != AFU_ID)
> +		return build_info_add_sub_feature(binfo, start, fid, size,
> +			vec_start, vec_cnt);
> +	return 0;
>  }
> 
>  /*
> @@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
>   */
>  static bool feature_is_UAFU(struct build_feature_devs_info *binfo)  {
> -	if (binfo->current_type != PORT_ID)
> -		return false;
> +	if ((binfo->current_type == PORT_ID) ||
> +		(binfo->current_type == AFU_ID))
> +		return true;
> 
> -	return true;
> +	return false;
>  }
> 
> -static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
> +static int parse_feature_uafu(struct build_feature_devs_info *binfo,
>  				   struct feature_header *hdr)
>  {
>  	u64 id = PORT_FEATURE_ID_UAFU;
> @@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	int ret;
>  	int size;
> 
> +	if (binfo->acc_info) {
> +		dev_info(binfo, "Sub AFU found @ %p.\n", start);
> +		return 0;
> +	}
> +
>  	capability.csr = readq(&port_hdr->capability);
> 
> -	size = capability.mmio_size << 10;
> +	if (binfo->current_type == AFU_ID) {
> +		size = AFU_REGION_SIZE;
> +	} else {
> +		capability.csr = readq(&port_hdr->capability);
> +		size = capability.mmio_size << 10;
> +	}
> 
>  	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
>  	if (ret)
> @@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	info->region[0].phys_addr = binfo->phys_addr +
>  			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
>  	info->region[0].len = size;
> -	info->num_regions = 1;
> +	info->num_regions = AFU_MAX_REGION;
> 
>  	binfo->acc_info = info;
> 
>  	return ret;
>  }
> 
> -static int parse_feature_afus(struct build_feature_devs_info *binfo,
> -			      struct feature_header *hdr)
> -{
> -	int ret;
> -	struct feature_afu_header *afu_hdr, header;
> -	u8 __iomem *start;
> -	u8 __iomem *end = binfo->ioend;
> -
> -	start = (u8 __iomem *)hdr;
> -	for (; start < end; start += header.next_afu) {
> -		if ((unsigned int)(end - start) <
> -			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> -			return -EINVAL;
> -
> -		hdr = (struct feature_header *)start;
> -		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> -		header.csr = readq(&afu_hdr->csr);
> -
> -		if (feature_is_UAFU(binfo)) {
> -			ret = parse_feature_port_uafu(binfo, hdr);
> -			if (ret)
> -				return ret;
> -		}
> -
> -		if (!header.next_afu)
> -			break;
> -	}
> -
> -	return 0;
> -}
> -
>  /* create and register proper private data */  static int
> build_info_commit_dev(struct build_feature_devs_info *binfo)  { @@ -
> 235,13 +233,9 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	struct ifpga_fme_hw *fme;
>  	struct ifpga_feature *feature;
> 
> -	if (!binfo->fiu)
> -		return 0;
> -
>  	if (binfo->current_type == PORT_ID) {
> -		/* return error if no valid acc info data structure */
> -		if (!info)
> -			return -EFAULT;
> +		if (!binfo->fiu)
> +			return 0;
> 
>  		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
>  				       binfo->fiu);
> @@ -254,7 +248,7 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  		port = &hw->port[binfo->current_port_id];
>  		feature = get_feature_by_id(&port->feature_list,
>  				PORT_FEATURE_ID_UINT);
> -		if (feature)
> +		if (feature && info)
>  			info->num_irqs = feature->vec_cnt;
> 
>  		acc = opae_accelerator_alloc(hw->adapter->name,
> @@ -264,17 +258,21 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  			return -ENOMEM;
>  		}
> 
> +		acc->adapter = hw->adapter;
>  		acc->br = br;
>  		if (hw->adapter->mgr)
>  			acc->mgr = hw->adapter->mgr;
>  		acc->index = br->id;
> 
>  		fme = &hw->fme;
> -		fme->nums_acc_region = info->num_regions;
> +		fme->nums_acc_region = info ? info->num_regions : 0;
> 
>  		opae_adapter_add_acc(hw->adapter, acc);
> 
>  	} else if (binfo->current_type == FME_ID) {
> +		if (!binfo->fiu)
> +			return 0;
> +
>  		mgr = opae_manager_alloc(hw->adapter->name,
> &ifpga_mgr_ops,
>  				&ifpga_mgr_network_ops, binfo->fiu);
>  		if (!mgr)
> @@ -282,6 +280,22 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
> 
>  		mgr->adapter = hw->adapter;
>  		hw->adapter->mgr = mgr;
> +	} else if (binfo->current_type == AFU_ID) {
> +		if (!info)
> +			return -EFAULT;
> +
> +		info->num_irqs = 0;
> +		acc = opae_accelerator_alloc(hw->adapter->name,
> +					&ifpga_acc_ops, info);
> +		if (!acc)
> +			return -ENOMEM;
> +
> +		acc->adapter = hw->adapter;
> +		acc->br = NULL;
> +		acc->mgr = NULL;
> +		acc->index = hw->num_afus++;
> +
> +		opae_adapter_add_acc(hw->adapter, acc);
>  	}
> 
>  	binfo->fiu = NULL;
> @@ -295,11 +309,15 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)  {
>  	int ret;
> 
> +	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
> +		return 0;
> +
>  	ret = build_info_commit_dev(binfo);
>  	if (ret)
>  		return ret;
> 
>  	binfo->current_type = type;
> +	binfo->acc_info = NULL;
> 
>  	if (type == FME_ID) {
>  		binfo->fiu = &binfo->hw->fme;
> @@ -311,6 +329,41 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	return 0;
>  }
> 
> +static int parse_feature_afus(struct build_feature_devs_info *binfo,
> +			      struct feature_header *hdr)
> +{
> +	int ret;
> +	struct feature_afu_header *afu_hdr, header;
> +	u8 __iomem *start;
> +	u8 __iomem *end = binfo->ioend;
> +
> +	ret = build_info_create_dev(binfo, AFU_ID, 0);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 __iomem *)hdr;
> +	for (; start < end; start += header.next_afu) {
> +		if ((unsigned int)(end - start) <
> +			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> +			return -EINVAL;
> +
> +		hdr = (struct feature_header *)start;
> +		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> +		header.csr = readq(&afu_hdr->csr);
> +
> +		if (feature_is_UAFU(binfo)) {
> +			ret = parse_feature_uafu(binfo, hdr);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (!header.next_afu)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
>  static int parse_feature_fme(struct build_feature_devs_info *binfo,
>  			     struct feature_header *start)
>  {
> @@ -405,7 +458,7 @@ static int parse_feature_fiu(struct
> build_feature_devs_info *binfo,
>  			if (ret)
>  				return ret;
>  		} else {
> -			dev_info(binfo, "No AFUs detected on Port\n");
> +			dev_info(binfo, "No AFU detected on Port\n");
>  		}
> 
>  		break;
> @@ -426,7 +479,7 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
> 
>  	id = feature_id(start);
> 
> -	if (id == PORT_FEATURE_ID_UINT) {
> +	if ((binfo->current_type == PORT_ID) && (id ==
> PORT_FEATURE_ID_UINT))
> +{
>  		struct feature_port_uint *port_uint = start;
>  		struct feature_port_uint_cap uint_cap;
> 
> @@ -437,7 +490,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  		} else {
>  			dev_debug(binfo, "UAFU doesn't support
> interrupt\n");
>  		}
> -	} else if (id == PORT_FEATURE_ID_ERROR) {
> +	} else if ((binfo->current_type == PORT_ID) &&
> +			(id == PORT_FEATURE_ID_ERROR)) {
>  		struct feature_port_error *port_err = start;
>  		struct feature_port_err_capability port_err_cap;
> 
> @@ -449,7 +503,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  			dev_debug(&binfo, "Port error doesn't support
> interrupt\n");
>  		}
> 
> -	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
> +	} else if ((binfo->current_type == FME_ID) &&
> +			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
>  		struct feature_fme_err *fme_err = start;
>  		struct feature_fme_error_capability fme_err_cap;
> 
> @@ -497,9 +552,15 @@ static int parse_feature_private(struct
> build_feature_devs_info *binfo,
>  		return parse_feature_fme_private(binfo, hdr);
>  	case PORT_ID:
>  		return parse_feature_port_private(binfo, hdr);
> +	case AFU_ID:
> +		dev_err(binfo, "private feature %x belonging to AFU "
> +			"is not supported yet.\n", header.id);
> +		break;
>  	default:
> -		dev_err(binfo, "private feature %x belonging to AFU %d
> (unknown_type) is not supported yet.\n",
> +		dev_err(binfo, "private feature %x belonging to TYPE %d "
> +			"(unknown_type) is not supported yet.\n",
>  			header.id, binfo->current_type);
> +		break;
>  	}
>  	return 0;
>  }
> @@ -530,32 +591,57 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return ret;
>  }
> 
> -static int
> -parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem
> *start)
> +static int build_info_prepare(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
>  {
> +	if (!binfo || !dfl)
> +		return -EINVAL;
> +
> +	binfo->ioaddr = dfl->addr;
> +	binfo->ioend = (u8 *)dfl->addr + dfl->len;
> +	binfo->phys_addr = dfl->start;
> +
> +	return 0;
> +}
> +
> +static int parse_feature_list(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
> +{
> +	u8 *start, *end;
>  	struct feature_header *hdr, header;
> -	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
>  	int ret = 0;
> 
> +	ret = build_info_prepare(binfo, dfl);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 *)binfo->ioaddr;
> +	end = (u8 *)binfo->ioend;
> +
> +	/* walk through the device feature list via DFH's next DFH pointer. */
>  	for (; start < end; start += header.next_header_offset) {
>  		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
> -			dev_err(binfo, "The region is too small to contain a
> feature.\n");
> -			ret =  -EINVAL;
> +			dev_err(binfo, "The region is too small to "
> +				"contain a feature.\n");
> +			ret = -EINVAL;
>  			break;
>  		}
> 
>  		hdr = (struct feature_header *)start;
> -		header.csr = readq(hdr);
> +		header.csr = opae_readq(hdr);
> 
> -		dev_debug(binfo, "%s: address=0x%p, val=0x%llx,
> header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x,
> header.type=0x%x\n",
> -			__func__, hdr, (unsigned long long)header.csr,
> -			header.id, header.next_header_offset,
> -			header.end_of_list, header.type);
> +		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
> +			"header.id=0x%x, header.next_offset=0x%x, "
> +			"header.eol=0x%x, header.type=0x%x\n",
> +			__func__, hdr, header.csr, header.id,
> +			header.next_header_offset, header.end_of_list,
> +			header.type);
> 
>  		ret = parse_feature(binfo, hdr);
>  		if (ret)
>  			return ret;
> 
> +		/* stop parsing if EOL(End of List) is set or offset is 0 */
>  		if (header.end_of_list || !header.next_header_offset)
>  			break;
>  	}
> @@ -563,82 +649,9 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return build_info_commit_dev(binfo);
>  }
> 
> -/* switch the memory mapping to BAR# @bar */ -static int
> parse_switch_to(struct build_feature_devs_info *binfo, int bar) -{
> -	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
> -
> -	if (!pci_data->region[bar].addr)
> -		return -ENOMEM;
> -
> -	binfo->ioaddr = pci_data->region[bar].addr;
> -	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data-
> >region[bar].len;
> -	binfo->phys_addr = pci_data->region[bar].phys_addr;
> -	binfo->current_bar = bar;
> -
> -	return 0;
> -}
> -
> -static int parse_ports_from_fme(struct build_feature_devs_info *binfo) -{
> -	struct feature_fme_header *fme_hdr;
> -	struct feature_fme_port port;
> -	int i = 0, ret = 0;
> -
> -	if (!binfo->pfme_hdr) {
> -		dev_info(binfo,  "VF is detected.\n");
> -		return ret;
> -	}
> -
> -	fme_hdr = binfo->pfme_hdr;
> -
> -	do {
> -		port.csr = readq(&fme_hdr->port[i]);
> -		if (!port.port_implemented)
> -			break;
> -
> -		/* skip port which only could be accessed via VF */
> -		if (port.afu_access_control == FME_AFU_ACCESS_VF)
> -			continue;
> -
> -		ret = parse_switch_to(binfo, port.port_bar);
> -		if (ret)
> -			break;
> -
> -		ret = parse_feature_list(binfo,
> -					 (u8 __iomem *)binfo->ioaddr +
> -					  port.port_offset);
> -		if (ret)
> -			break;
> -	} while (++i < MAX_FPGA_PORT_NUM);
> -
> -	return ret;
> -}
> -
> -static struct build_feature_devs_info * -build_info_alloc_and_init(struct
> ifpga_hw *hw) -{
> -	struct build_feature_devs_info *binfo;
> -
> -	binfo = zmalloc(sizeof(*binfo));
> -	if (!binfo)
> -		return binfo;
> -
> -	binfo->hw = hw;
> -	binfo->pci_data = hw->pci_data;
> -
> -	/* fpga feature list starts from BAR 0 */
> -	if (parse_switch_to(binfo, 0)) {
> -		free(binfo);
> -		return NULL;
> -	}
> -
> -	return binfo;
> -}
> -
>  static void build_info_free(struct build_feature_devs_info *binfo)  {
> -	free(binfo);
> +	opae_free(binfo);
>  }
> 
>  static void ifpga_print_device_feature_list(struct ifpga_hw *hw) @@ -648,6
> +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
>  	struct ifpga_feature *feature;
>  	int i;
> 
> +	if (fme->state == IFPGA_FME_UNUSED) {
> +		dev_info(hw, "FME is not present\n");
> +		return;
> +	}
> +
>  	dev_info(hw, "found fme_device, is in PF: %s\n",
>  		 is_ifpga_hw_pf(hw) ? "yes" : "no");
> 
> @@ -685,40 +703,411 @@ static void ifpga_print_device_feature_list(struct
> ifpga_hw *hw)
>  	}
>  }
> 
> -int ifpga_bus_enumerate(struct ifpga_hw *hw)
> +static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct
> +ifpga_hw *hw)
>  {
> -	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_info *info;
> +
> +	info = opae_zmalloc(sizeof(*info));
> +	if (!info)
> +		return NULL;
> +
> +	info->hw = hw;
> +	TAILQ_INIT(&info->dfls);
> +
> +	return info;
> +}
> +
> +static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info) {
> +	struct dfl_fpga_enum_dfl *tmp, *dfl;
> +
> +	if (!info)
> +		return;
> +
> +	/* remove all device feature lists in the list. */
> +	for (dfl = TAILQ_FIRST(&info->dfls);
> +		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
> +		dfl = tmp) {
> +		TAILQ_REMOVE(&info->dfls, dfl, node);
> +		opae_free(dfl);
> +	}
> +
> +	opae_free(info);
> +}
> +
> +static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
> +	u64 start, u64 len, void *addr)
> +{
> +	struct dfl_fpga_enum_dfl *dfl;
> +
> +	dfl = opae_zmalloc(sizeof(*dfl));
> +	if (!dfl)
> +		return -ENOMEM;
> +
> +	dfl->start = start;
> +	dfl->len = len;
> +	dfl->addr = addr;
> +
> +	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
> +
> +	return 0;
> +}
> +
> +#define PCI_CFG_SPACE_SIZE	256
> +#define PCI_CFG_SPACE_EXP_SIZE	4096
> +#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
> +#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
> +
> +static int
> +pci_find_next_ecap(int fd, int start, u32 cap) {
> +	u32 header;
> +	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
> +	int pos = PCI_CFG_SPACE_SIZE;
>  	int ret;
> 
> -	binfo = build_info_alloc_and_init(hw);
> +	if (start > 0)
> +		pos = start;
> +
> +	ret = pread(fd, &header, sizeof(header), pos);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * If we have no capabilities, this is indicated by cap ID,
> +	 * cap version and next pointer all being 0.
> +	 */
> +	if (header == 0)
> +		return 0;
> +
> +	while (ttl-- > 0) {
> +		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
> +			return pos;
> +
> +		pos = PCI_EXT_CAP_NEXT(header);
> +		if (pos < PCI_CFG_SPACE_SIZE)
> +			break;
> +		ret = pread(fd, &header, sizeof(header), pos);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define PCI_EXT_CAP_ID_VNDR	0x0B
> +#define PCI_VNDR_HEADER		4
> +#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
> +#define PCI_VENDOR_ID_INTEL 0x8086
> +#define PCI_VSEC_ID_INTEL_DFLS 0x43
> +#define PCI_VNDR_DFLS_CNT 0x8
> +#define PCI_VNDR_DFLS_RES 0xc
> +#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0) #define
> +PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
> +
> +static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	char path[64];
> +	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
> +	int fd, ret, dfl_res_off, voff = 0;
> +	u64 start, len;
> +	void *addr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->adapter || !hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
> +			hw->adapter->name);
> +	if ((unsigned int)ret >= sizeof(path))
> +		return -EINVAL;
> +
> +	fd = open(path, O_RDWR);
> +	if (fd < 0)
> +		return -EIO;
> +
> +	while ((voff = pci_find_next_ecap(fd, voff,
> +		PCI_EXT_CAP_ID_VNDR))) {
> +		vndr_hdr = 0;
> +		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
> +			voff + PCI_VNDR_HEADER);
> +		if (ret < 0)
> +			return -EIO;
> +		if (PCI_VNDR_HEADER_ID(vndr_hdr) ==
> PCI_VSEC_ID_INTEL_DFLS &&
> +			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
> +			break;
> +	}
> +
> +	if (!voff) {
> +		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	dfl_cnt = 0;
> +	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff +
> PCI_VNDR_DFLS_CNT);
> +	if (ret < 0)
> +		return -EIO;
> +
> +	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
> +	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE)
> {
> +		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
> +		dfl_res = GENMASK(31, 0);
> +		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
> +		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
> +		if (bir >= PCI_MAX_RESOURCE) {
> +			dev_err(hw, "%s bad bir number %d\n",
> +				__func__, bir);
> +			return -EINVAL;
> +		}
> +
> +		len = pci_data->region[bir].len;
> +		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
> +		if (offset >= len) {
> +			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
> +				__func__, offset, len);
> +			return -EINVAL;
> +		}
> +
> +		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir,
> offset);
> +		len -= offset;
> +		start = pci_data->region[bir].phys_addr + offset;
> +		addr = pci_data->region[bir].addr + offset;
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	}
> +
> +	return 0;
> +}
> +
> +/* default method of finding dfls starting at offset 0 of bar 0 */
> +static int find_dfls_by_default(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	int port_num, bar, i, ret = 0;
> +	u64 start, len;
> +	void *addr;
> +	u32 offset;
> +	struct feature_header hdr;
> +	struct feature_fme_capability cap;
> +	struct feature_fme_port port;
> +	struct feature_fme_header *fme_hdr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	/* start to find Device Feature List from Bar 0 */
> +	addr = pci_data->region[0].addr;
> +	if (!addr)
> +		return -ENOMEM;
> +
> +	/*
> +	 * PF device has FME and Ports/AFUs, and VF device only has one
> +	 * Port/AFU. Check them and add related "Device Feature List" info
> +	 * for the next step enumeration.
> +	 */
> +	hdr.csr = opae_readq(addr);
> +	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id ==
> FEATURE_FIU_ID_FME)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +
> +		/*
> +		 * find more Device Feature Lists (e.g. Ports) per information
> +		 * indicated by FME module.
> +		 */
> +		fme_hdr = (struct feature_fme_header *)addr;
> +		cap.csr = opae_readq(&fme_hdr->capability);
> +		port_num = (int)cap.num_ports;
> +
> +		dev_info(hw, "port_num = %d\n", port_num);
> +		if (port_num > MAX_FPGA_PORT_NUM)
> +			port_num = MAX_FPGA_PORT_NUM;
> +
> +		for (i = 0; i < port_num; i++) {
> +			port.csr = opae_readq(&fme_hdr->port[i]);
> +
> +			/* skip ports which are not implemented. */
> +			if (!port.port_implemented)
> +				continue;
> +
> +			/* skip port which only could be accessed via VF */
> +			if (port.afu_access_control == FME_AFU_ACCESS_VF)
> +				continue;
> +
> +			/*
> +			 * add Port's Device Feature List information for next
> +			 * step enumeration.
> +			 */
> +			bar = (int)port.port_bar;
> +			offset = port.port_offset;
> +			if (bar == FME_PORT_OFST_BAR_SKIP) {
> +				continue;
> +			} else if (bar >= PCI_MAX_RESOURCE) {
> +				dev_err(hw, "bad BAR %d for port %d\n", bar,
> i);
> +				ret = -EINVAL;
> +				break;
> +			} else {
> +				dev_info(hw, "BAR %d offset %u\n", bar,
> offset);
> +			}
> +
> +			len = pci_data->region[bar].len;
> +			if (offset >= len) {
> +				dev_warn(hw, "bad port
> offset %u >= %pa\n",
> +					 offset, &len);
> +				continue;
> +			}
> +
> +			len -= offset;
> +			start = pci_data->region[bar].phys_addr + offset;
> +			addr = pci_data->region[bar].addr + offset;
> +			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +		}
> +	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
> +		(hdr.id == FEATURE_FIU_ID_PORT)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else if (hdr.type == FEATURE_TYPE_AFU) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else {
> +		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
> +			 hdr.type, hdr.id);
> +		ret = -ENODEV;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info
> +*info) {
> +	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_dfl *dfl;
> +	int ret = 0;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +
> +	/* create and init build info for enumeration */
> +	binfo = opae_zmalloc(sizeof(*binfo));
>  	if (!binfo)
>  		return -ENOMEM;
> 
> -	ret = parse_feature_list(binfo, binfo->ioaddr);
> +	binfo->hw = info->hw;
> +	binfo->pci_data = info->hw->pci_data;
> +
> +	/*
> +	 * start enumeration for all feature devices based on Device Feature
> +	 * Lists.
> +	 */
> +	TAILQ_FOREACH(dfl, &info->dfls, node) {
> +		ret = parse_feature_list(binfo, dfl);
> +		if (ret)
> +			break;
> +	}
> +
> +	build_info_free(binfo);
> +
> +	return ret;
> +}
> +
> +int ifpga_bus_enumerate(struct ifpga_hw *hw) {
> +	struct dfl_fpga_enum_info *info;
> +	int ret;
> +
> +	/* allocate enumeration info */
> +	info = dfl_fpga_enum_info_alloc(hw);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	ret = find_dfls_by_vsec(info);
> +	if (ret < 0)
> +		ret = find_dfls_by_default(info);
> +
>  	if (ret)
>  		goto exit;
> 
> -	ret = parse_ports_from_fme(binfo);
> -	if (ret)
> +	/* start enumeration with prepared enumeration information */
> +	ret = dfl_fpga_feature_devs_enumerate(info);
> +	if (ret < 0) {
> +		dev_err(hw, "Enumeration failure\n");
>  		goto exit;
> +	}
> 
>  	ifpga_print_device_feature_list(hw);
> 
>  exit:
> -	build_info_free(binfo);
> +	dfl_fpga_enum_info_free(info);
> +
>  	return ret;
>  }
> 
> -int ifpga_bus_init(struct ifpga_hw *hw)
> +static void ifpga_print_acc_list(struct opae_adapter *adapter)
>  {
> +	struct opae_accelerator *acc;
> +	struct ifpga_afu_info *info;
> +	struct uuid guid;
> +	char buf[48];
>  	int i;
> +
> +	opae_adapter_for_each_acc(adapter, acc) {
> +		info = acc->data;
> +		if (!info)
> +			continue;
> +		acc->ops->get_uuid(acc, &guid);
> +		i = sprintf(buf, "%02x%02x%02x%02x-",
> +			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
> +		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
> +			guid.b[5], guid.b[4], guid.b[3],
> +			guid.b[2], guid.b[1], guid.b[0]);
> +		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64",
> guid:%s\n",
> +			acc->name, acc->index, info->region[0].addr,
> +			info->region[0].len, buf);
> +	}
> +}
> +
> +int ifpga_bus_init(struct ifpga_hw *hw) {
> +	int i, ret = 0;
>  	struct ifpga_port_hw *port;
> 
> -	fme_hw_init(&hw->fme);
> +	ret = fme_hw_init(&hw->fme);
> +	if (ret)
> +		return ret;
> +
>  	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
>  		port = &hw->port[i];
>  		port_hw_init(port);
>  	}
> +	ifpga_print_acc_list(hw->adapter);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h
> b/drivers/raw/ifpga/base/ifpga_enumerate.h
> index 95ed594..e6b04f0 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.h
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
> @@ -5,6 +5,8 @@
>  #ifndef _IFPGA_ENUMERATE_H_
>  #define _IFPGA_ENUMERATE_H_
> 
> +#define FME_PORT_OFST_BAR_SKIP  7
> +
>  int ifpga_bus_init(struct ifpga_hw *hw);  int ifpga_bus_uinit(struct ifpga_hw
> *hw);  int ifpga_bus_enumerate(struct ifpga_hw *hw); diff --git
> a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> index 0813513..dbecc7b 100644
> --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> @@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
>  	if (fpga_wait_register_field(port_sftrst_ack, control,
>  				     &port_hdr->control, RST_POLL_TIMEOUT,
>  				     RST_POLL_INVL)) {
> -		dev_err(port, "timeout, fail to reset device\n");
> +		dev_err(port, "timeout, fail to reset FIM port\n");
>  		return -ETIMEDOUT;
>  	}
> 
> @@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list
> *list)
>  	struct ifpga_feature *feature;
> 
>  	TAILQ_FOREACH(feature, list, next) {
> -		if (feature->state != IFPGA_FEATURE_ATTACHED)
> +		if (feature->state != IFPGA_FEATURE_INITED)
>  			continue;
>  		if (feature->ops && feature->ops->uinit)
>  			feature->ops->uinit(feature);
> +		feature->state = IFPGA_FEATURE_ATTACHED;
>  	}
>  }
> 
> @@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
>  					ret = feature->ops->init(feature);
>  					if (ret)
>  						goto error;
> +					else
> +						feature->state =
> +
> 	IFPGA_FEATURE_INITED;
>  				}
>  			}
>  		}
> @@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
> 
>  int fme_hw_init(struct ifpga_fme_hw *fme)  {
> -	int ret;
> -
> -	if (fme->state != IFPGA_FME_IMPLEMENTED)
> -		return -ENODEV;
> -
> -	ret = feature_init(fme_feature_drvs, &fme->feature_list);
> -	if (ret)
> -		return ret;
> +	if (fme->state == IFPGA_FME_IMPLEMENTED)
> +		return feature_init(fme_feature_drvs, &fme->feature_list);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_hw.h
> b/drivers/raw/ifpga/base/ifpga_hw.h
> index ed5edc6..4d56deb 100644
> --- a/drivers/raw/ifpga/base/ifpga_hw.h
> +++ b/drivers/raw/ifpga/base/ifpga_hw.h
> @@ -15,6 +15,7 @@
>  enum ifpga_feature_state {
>  	IFPGA_FEATURE_UNUSED = 0,
>  	IFPGA_FEATURE_ATTACHED,
> +	IFPGA_FEATURE_INITED
>  };
> 
>  enum feature_type {
> @@ -134,6 +135,7 @@ struct ifpga_hw {
> 
>  	struct ifpga_fme_hw fme;
>  	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
> +	int num_afus;
>  };
> 
>  static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) diff --git
> a/drivers/raw/ifpga/base/opae_hw_api.c
> b/drivers/raw/ifpga/base/opae_hw_api.c
> index 11c9887..87256fc 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.c
> +++ b/drivers/raw/ifpga/base/opae_hw_api.c
> @@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct
> opae_accelerator *acc,  int opae_acc_set_irq(struct opae_accelerator *acc,
>  		     u32 start, u32 count, s32 evtfds[])  {
> -	if (!acc || !acc->data)
> +	if (!acc)
>  		return -EINVAL;
> 
>  	if (start + count <= start)
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.h
> b/drivers/raw/ifpga/base/opae_hw_api.h
> index 7e04b56..fd40e09 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.h
> +++ b/drivers/raw/ifpga/base/opae_hw_api.h
> @@ -143,6 +143,7 @@ struct opae_accelerator {
>  	TAILQ_ENTRY(opae_accelerator) node;
>  	const char *name;
>  	int index;
> +	struct opae_adapter *adapter;
>  	struct opae_bridge *br;
>  	struct opae_manager *mgr;
>  	struct opae_accelerator_ops *ops;
> @@ -240,6 +241,7 @@ struct opae_adapter_data {
> 
>  struct opae_reg_region {
>  	u64 phys_addr;
> +#define AFU_REGION_SIZE  0x8000
>  	u64 len;
>  	u8 *addr;
>  };
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 94df56c..ceb18ae 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -47,11 +47,13 @@
>  #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
>  #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
>  #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
> +#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
>  /* VF Device */
>  #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
>  #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
>  #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
>  #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
> +#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
>  #define RTE_MAX_RAW_DEVICE           10
> 
>  static const struct rte_pci_id pci_ifpga_map[] = { @@ -63,6 +65,8 @@
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_DSC_1_X) },
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N3000),},
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N3000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N6000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N6000),},
>  	{ .vendor_id = 0, /* sentinel */ },
>  };
> 
> @@ -110,6 +114,7 @@ struct ifpga_rawdev *
> 
>  	return IFPGA_RAWDEV_NUM;
>  }
> +
>  static struct ifpga_rawdev *
>  ifpga_rawdev_allocate(struct rte_rawdev *rawdev)  { @@ -365,7 +370,7
> @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  		return -ENODEV;
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> +	if (!mgr || !mgr->sensor_list)
>  		return -ENODEV;
> 
>  	opae_mgr_for_each_sensor(mgr, sensor) { @@ -377,7 +382,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  			goto fail;
> 
>  		if (value == 0xdeadbeef) {
> -			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s
> value %x\n",
> +			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d
> sensor %s value %x\n",
>  					raw_dev->dev_id, sensor->name,
> value);
>  			continue;
>  		}
> @@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(  {
>  	struct opae_adapter *adapter;
>  	struct opae_manager *mgr;
> -	struct opae_board_info *info;
> +	struct opae_board_info *info = NULL;
>  	struct rte_afu_pr_conf *afu_pr_conf;
>  	int ret;
>  	struct uuid uuid;
> @@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
>  	}
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr) {
> -		IFPGA_RAWDEV_PMD_ERR("opae_manager of
> opae_adapter is NULL");
> -		return -1;
> -	}
> -
> -	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> -		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info
> fail!");
> -		return -1;
> +	if (mgr) {
> +		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> +			IFPGA_RAWDEV_PMD_ERR("ifpga manager
> get_board_info fail!");
> +			return -1;
> +		}
>  	}
> 
> -	if (info->lightweight) {
> +	if (info && info->lightweight) {
>  		/* set uuid to all 0, when fpga is lightweight image */
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0,
> sizeof(u64));
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0,
> sizeof(u64)); @@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
>  			__func__,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
> -		}
> +	}
>  	return 0;
>  }
> 
> @@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
>  	if (ret) {
>  		ret = -ENOMEM;
> -		goto free_adapter_data;
> +		goto cleanup;
>  	}
> 
>  	rawdev->dev_ops = &ifpga_rawdev_ops;
> @@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	/* must enumerate the adapter before use it */
>  	ret = opae_adapter_enumerate(adapter);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	/* get opae_manager to rawdev */
>  	mgr = opae_adapter_get_mgr(adapter);
>  	if (mgr) {
> -		/* PF function */
> -		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
> +		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> +				fme_interrupt_handler, "fme_irq", mgr);
> +		if (ret)
> +			goto cleanup;
>  	}
> 
> -	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> -			fme_interrupt_handler, "fme_irq", mgr);
> -	if (ret)
> -		goto free_adapter_data;
> -
>  	ret = ifpga_monitor_start_func(dev);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	return ret;
> 
> -free_adapter_data:
> -	if (data)
> -		opae_adapter_data_free(data);
>  cleanup:
>  	if (rawdev)
>  		rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-26  3:32       ` [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
@ 2022-05-26  6:47         ` Xu, Rosen
  2022-05-27  3:19         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-05-26  6:47 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi Wei,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc
> 
> OFS (Open FPGA Stack) specification is introduced briefly.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
>  doc/guides/rawdevs/ifpga.rst | 114
> ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 113 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst
> index dbd0d6e..8809bfc 100644
> --- a/doc/guides/rawdevs/ifpga.rst
> +++ b/doc/guides/rawdevs/ifpga.rst
> @@ -1,5 +1,5 @@
>  ..  SPDX-License-Identifier: BSD-3-Clause
> -    Copyright(c) 2018 Intel Corporation.
> +    Copyright(c) 2018-2022 Intel Corporation.
> 
>  IFPGA Rawdev Driver
>  ======================
> @@ -100,3 +100,115 @@ The following device parameters are supported:
> 
>    If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
>    identifies AFU Bit Stream file.
> +
> +
> +Open FPGA Stack
> +=====================
> +
> +Open FPGA Stack (OFS) is a collection of RTL and open source software
> +providing interfaces to access the instantiated RTL easily in an FPGA.
> +OFS leverages the DFL for the implementation of the FPGA RTL design.
> +
> +OFS designs allow for the arrangement of software interfaces across
> +multiple PCIe endpoints. Some of these interfaces may be PFs defined in
> +the static region that connect to interfaces in an IP that is loaded via Partial
> Reconfiguration (PR).
> +And some of these interfaces may be VFs defined in the PR region that
> +can be reconfigured by the end-user. Furthermore, these PFs/VFs may use
> +DFLs such that features may be discovered and accessed in user space
> +(with the aid of a generic kernel driver like vfio-pci). The diagram
> +below depicts an example design with two PFs and two VFs. In this
> +example, it will export the management functions via PF0,
> +PF1 will bind with virtio-net driver presenting itself as a network
> +interface to the OS. The other functions, VF0 and VF1, leverage VFIO to
> +export the MMIO space to an application or assign to a VM.::
> +
> +     +-----------------+  +--------------+  +-------------+  +------------+
> +     | FPGA Management |  |   VirtIO     |  |  User App   |  | Virtual    |
> +     |      App        |  |     App      |  |             |  | Machine    |
> +     +--------+--------+  +------+-------+  +------+------+  +-----+------+
> +              |                  |                 |               |
> +     +--------+--------+  +------+-------+  +------+------+        |
> +     |     DFL Driver  |  |VirtIO driver |  |    VFIO     |        |
> +     +--------+--------+  +------+-------+  +------+------+        |
> +              |                  |                 |               |
> +              |                  |                 |               |
> +     +--------+--------+  +------+-------+  +------+------+   +----+------+
> +     |     PF0         |  |     PF1      |  |   PF0_VF0   |   |  PF0_VF1  |
> +     +-----------------+  +--------------+  +-------------+   +-----------+
> +
> +As accelerators are specialized hardware, they are typically limited in
> +the number installed in a given system. Many use cases require them to
> +be shared across multiple software contexts or threads of software
> +execution, either through partitioning of individual dedicated
> +resources, or virtualization of shared resources. OFS provides several
> +models to share the AFU resources via PR mechanism and hardware-based
> virtualization schemes.
> +
> +1. Legacy model.
> +   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
> +   a notion that the boundary between the AFU and the shell is also the unit
> of
> +   PR for those FPGA platforms. This model is only able to handle a
> +   single context, because it only has one PR engine, and one PR region
> which
> +   has an associated Port device.
> +2. Multiple VFs per PR slot.
> +   In this model, available AFU resources may allow instantiation of many VFs
> +   which have a dedicated PCIe function with their own dedicated MMIO
> space, or
> +   partition a region of MMIO space on a single PCIe function. Intel PAC
> N6000
> +   card has implemented this model.
> +   In this model, the AFU/PR slot was not connected to port device. For DFL's
> view,
> +   the Next_AFU pointer in FIU feature header of port device points to NULL
> in this
> +   model, so in AFU driver perspective, there is no AFU MMIO region
> managed by
> +   AFU driver. On the other hand, each VF can start with an AFU feature
> header without
> +   being connected to a FIU Port feature header.
> +
> +In multiple VFs per PR slot model, the port device can still be
> +accessed using ioctls API which expose /dev/dfl-port.h device nodes,
> +like port reset, get port info, whose APIs were mentioned in AFU
> +section in this documentation. But it cannot access the AFU MMIO space
> +via AFU ioctl APIs like DFL_FPGA_PORT_DMA_MAP because there is no
> AFU
> +MMIO space managed in the AFU driver. Users can access the AFU resource
> +by creating VF devices via PCIe SRIOV interface, and then access the VF via
> VFIO driver or assign the VF to VM.
> +
> +In multiple VFs per PR slot model, the steps to enable VFs are
> +compatible with legacy mode which are mentioned in "FPGA virtualization
> +- PCIe SRIOV" section in this documentation.
> +
> +OFS provides the diversity for accessing the AFU resource to RTL developer.
> +An IP designer may choose to add more than one PF for interfacing with
> +IP on the FPGA and choose different model to access the AFU resource.
> +
> +There is one reference architecture design using the "Multiple VFs per PR
> slot"
> +model for OFS as illustrated below. In this reference design, it
> +exports the FPGA management functions via PF0. PF1 will bind with
> +virtio-net driver presenting itself as a network interface to the OS.
> +PF2 will bind to the vfio-pci driver allowing the user space software
> +to discover and interface with the specific workload like diagnostic
> +test. To access the AFU resource, it uses SR-IOV to partition workload
> interfaces across various VFs.::
> +
> +                              +----------------------+
> +                              |   PF/VF mux/demux    |
> +                              +--+--+-----+------+-+-+
> +                                 |  |     |      | |
> +        +------------------------+  |     |      | |
> +  PF0   |                 +---------+   +-+      | |
> +    +---+---+             |         +---+----+   | |
> +    |  DFH  |             |         |   DFH  |   | |
> +    +-------+       +-----+----+    +--------+   | |
> +    |  FME  |       |  VirtIO  |    |  Test  |   | |
> +    +---+---+       +----------+    +--------+   | |
> +        |                PF1            PF2      | |
> +        |                                        | |
> +        |                             +----------+ |
> +        |                             |           ++
> +        |                             |           |
> +        |                             | PF0_VF0   | PF0_VF1
> +        |           +-----------------+-----------+------------+
> +        |           |           +-----+-----------+--------+   |
> +        |           |           |     |           |        |   |
> +        |           | +------+  |  +--+ -+     +--+---+    |   |
> +        |           | | Port |  |  | DFH |     |  DFH |    |   |
> +        +-----------+ +------+  |  +-----+     +------+    |   |
> +                    |           |  | DEV |     |  DEV |    |   |
> +                    |           |  +-----+     +------+    |   |
> +                    |           |            PR Slot       |   |
> +                    |           +--------------------------+   |
> +                    | Port Gasket                              |
> +                    +------------------------------------------+
> --
> 1.8.3.1

Reviewed-by Rosen Xu <rosen.xu@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-26  3:32       ` [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
  2022-05-26  6:41         ` Xu, Rosen
@ 2022-05-27  2:57         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-27  2:57 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33 AM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function
> 
> In original implementation, interrupts are unregistered in ifpga_rawdev_destroy
> function. If application want to release the ifpga driver resource by calling
> rte_rawdev_pmd_release, interrupt resource will not be released.
> Now interrupt unregistration is moved from ifpga destroy function to ifpga close
> function, when rte_rawdev_pmd_release is called, rte_rawdev_close will be
> called, then interrupts are unregistered.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: update commit log
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index fe3fc43..94df56c 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(  static int
> ifpga_pci_find_next_ext_capability(unsigned int fd,
>  					      int start, uint32_t cap);
>  static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
> +static void fme_interrupt_handler(void *param);
> 
>  struct ifpga_rawdev *
>  ifpga_rawdev_get(const struct rte_rawdev *rawdev) @@ -740,8 +741,9 @@
> static int set_surprise_link_check_aer(  {
>  	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	struct opae_manager *mgr;
>  	char *vdev_name = NULL;
> -	int i = 0;
> +	int i, ret = 0;
> 
>  	if (dev) {
>  		ifpga_rdev = ifpga_rawdev_get(dev);
> @@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
>  		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
> +			mgr = opae_adapter_get_mgr(adapter);
> +			if (ifpga_rdev && mgr) {
> +				if (ifpga_unregister_msix_irq(ifpga_rdev,
> +					IFPGA_FME_IRQ, 0,
> +					fme_interrupt_handler, mgr) < 0)
> +					ret = -EINVAL;
> +			}
>  			opae_adapter_destroy(adapter);
>  			opae_adapter_data_free(adapter->data);
>  		}
>  	}
> 
> -	return dev ? 0:1;
> +	return ret;
>  }
> 
>  static int
> @@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  	int ret;
>  	struct rte_rawdev *rawdev;
>  	char name[RTE_RAWDEV_NAME_MAX_LEN];
> -	struct opae_adapter *adapter;
> -	struct opae_manager *mgr;
> -	struct ifpga_rawdev *dev;
> 
>  	if (!pci_dev) {
>  		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
> @@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
>  		return -EINVAL;
>  	}
> -	dev = ifpga_rawdev_get(rawdev);
> -
> -	adapter = ifpga_rawdev_get_priv(rawdev);
> -	if (!adapter)
> -		return -ENODEV;
> -
> -	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> -		return -ENODEV;
> -
> -	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
> -				fme_interrupt_handler, mgr) < 0)
> -		return -EINVAL;
> 
>  	/* rte_rawdev_close is called by pmd_release */
>  	ret = rte_rawdev_pmd_release(rawdev);
> --

Hi Wei,
It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 4/5] raw/ifpga: support ofs card probe
  2022-05-26  3:32       ` [PATCH v3 4/5] raw/ifpga: support ofs card probe Wei Huang
  2022-05-26  6:46         ` Xu, Rosen
@ 2022-05-27  3:10         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-27  3:10 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33 AM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 4/5] raw/ifpga: support ofs card probe
> 
> PAC N6000 is the first OFS platform, its device id is added to ifpga device support
> list.
> 
> Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
> Feature List) starts from BAR0 by default, port DFL location is indicated in
> PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port DFL
> location can be defined individually in PCIe VSEC (Vendor Specific Extented
> Capabilities). In this patch, DFL definition is searched in VSEC, the legacy DFL is
> used only when DFL VSEC is not present.
> 
> In original DFL enumeration process, AFU is expected to locate in port DFL, but
> this is not the case in OFS implementation. In this patch, enumeration can search
> AFU in any PF/VF which has no FME and port.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: fix build error in UB2004-32
> ---
> v3: update commit log with Tianfei's comment, treat 7 as special BAR index.
> ---
>  drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
>  drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
>  drivers/raw/ifpga/base/ifpga_enumerate.c   | 681 ++++++++++++++++++++++--
> -----
>  drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
>  drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
>  drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
>  drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
>  drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
>  drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
>  9 files changed, 592 insertions(+), 192 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_api.c
> b/drivers/raw/ifpga/base/ifpga_api.c
> index 4610ef1..f19cc26 100644
> --- a/drivers/raw/ifpga/base/ifpga_api.c
> +++ b/drivers/raw/ifpga/base/ifpga_api.c
> @@ -13,15 +13,22 @@
>  static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
>  			      struct uuid *uuid)
>  {
> -	struct opae_bridge *br = acc->br;
> -	struct ifpga_port_hw *port;
> +	struct ifpga_afu_info *afu_info = acc->data;
> +	struct opae_reg_region *region;
> +	u64 val = 0;
> 
> -	if (!br || !br->data)
> -		return -EINVAL;
> +	if (!afu_info)
> +		return -ENODEV;
> 
> -	port = br->data;
> +	region = &afu_info->region[0];
> +	if (uuid) {
> +		val = readq(region->addr + sizeof(struct feature_header));
> +		opae_memcpy(uuid->b, &val, sizeof(u64));
> +		val = readq(region->addr + sizeof(struct feature_header) + 8);
> +		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
> +	}
> 
> -	return fpga_get_afu_uuid(port, uuid);
> +	return 0;
>  }
> 
>  static int ifpga_acc_set_irq(struct opae_accelerator *acc, @@ -32,6 +39,9 @@
> static int ifpga_acc_set_irq(struct opae_accelerator *acc,
>  	struct ifpga_port_hw *port;
>  	struct fpga_uafu_irq_set irq_set;
> 
> +	if (!afu_info)
> +		return -ENODEV;
> +
>  	if (!br || !br->data)
>  		return -EINVAL;
> 
> @@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct
> opae_accelerator *acc,
>  	struct ifpga_afu_info *afu_info = acc->data;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (info->index >= afu_info->num_regions)
>  		return -EINVAL;
> @@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc,
> unsigned int region_idx,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> @@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> diff --git a/drivers/raw/ifpga/base/ifpga_defines.h
> b/drivers/raw/ifpga/base/ifpga_defines.h
> index 8f62033..9a280eb 100644
> --- a/drivers/raw/ifpga/base/ifpga_defines.h
> +++ b/drivers/raw/ifpga/base/ifpga_defines.h
> @@ -73,6 +73,7 @@
>  enum fpga_id_type {
>  	FME_ID,
>  	PORT_ID,
> +	AFU_ID,
>  	FPGA_ID_MAX,
>  };
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c
> b/drivers/raw/ifpga/base/ifpga_enumerate.c
> index 48b8af4..0e09904 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.c
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
> @@ -2,6 +2,10 @@
>   * Copyright(c) 2010-2018 Intel Corporation
>   */
> 
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <unistd.h>
> +
>  #include "opae_hw_api.h"
>  #include "ifpga_api.h"
> 
> @@ -9,6 +13,19 @@
>  #include "ifpga_enumerate.h"
>  #include "ifpga_feature_dev.h"
> 
> +struct dfl_fpga_enum_dfl {
> +	u64 start;
> +	u64 len;
> +	void *addr;
> +	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
> +};
> +
> +TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl); struct
> +dfl_fpga_enum_info {
> +	struct ifpga_hw *hw;
> +	struct dfl_fpga_enum_dfls dfls;
> +};
> +
>  struct build_feature_devs_info {
>  	struct opae_adapter_data_pci *pci_data;
> 
> @@ -21,7 +38,6 @@ struct build_feature_devs_info {
>  	void *ioaddr;
>  	void *ioend;
>  	uint64_t phys_addr;
> -	int current_bar;
> 
>  	void *pfme_hdr;
> 
> @@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
>  			unsigned int size, unsigned int vec_start,
>  			unsigned int vec_cnt)
>  {
> -	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
> -			vec_cnt);
> +	if (binfo->current_type != AFU_ID)
> +		return build_info_add_sub_feature(binfo, start, fid, size,
> +			vec_start, vec_cnt);
> +	return 0;
>  }
> 
>  /*
> @@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
>   */
>  static bool feature_is_UAFU(struct build_feature_devs_info *binfo)  {
> -	if (binfo->current_type != PORT_ID)
> -		return false;
> +	if ((binfo->current_type == PORT_ID) ||
> +		(binfo->current_type == AFU_ID))
> +		return true;
> 
> -	return true;
> +	return false;
>  }
> 
> -static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
> +static int parse_feature_uafu(struct build_feature_devs_info *binfo,
>  				   struct feature_header *hdr)
>  {
>  	u64 id = PORT_FEATURE_ID_UAFU;
> @@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	int ret;
>  	int size;
> 
> +	if (binfo->acc_info) {
> +		dev_info(binfo, "Sub AFU found @ %p.\n", start);
> +		return 0;
> +	}
> +
>  	capability.csr = readq(&port_hdr->capability);
> 
> -	size = capability.mmio_size << 10;
> +	if (binfo->current_type == AFU_ID) {
> +		size = AFU_REGION_SIZE;
> +	} else {
> +		capability.csr = readq(&port_hdr->capability);
> +		size = capability.mmio_size << 10;
> +	}
> 
>  	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
>  	if (ret)
> @@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	info->region[0].phys_addr = binfo->phys_addr +
>  			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
>  	info->region[0].len = size;
> -	info->num_regions = 1;
> +	info->num_regions = AFU_MAX_REGION;
> 
>  	binfo->acc_info = info;
> 
>  	return ret;
>  }
> 
> -static int parse_feature_afus(struct build_feature_devs_info *binfo,
> -			      struct feature_header *hdr)
> -{
> -	int ret;
> -	struct feature_afu_header *afu_hdr, header;
> -	u8 __iomem *start;
> -	u8 __iomem *end = binfo->ioend;
> -
> -	start = (u8 __iomem *)hdr;
> -	for (; start < end; start += header.next_afu) {
> -		if ((unsigned int)(end - start) <
> -			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> -			return -EINVAL;
> -
> -		hdr = (struct feature_header *)start;
> -		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> -		header.csr = readq(&afu_hdr->csr);
> -
> -		if (feature_is_UAFU(binfo)) {
> -			ret = parse_feature_port_uafu(binfo, hdr);
> -			if (ret)
> -				return ret;
> -		}
> -
> -		if (!header.next_afu)
> -			break;
> -	}
> -
> -	return 0;
> -}
> -
>  /* create and register proper private data */  static int
> build_info_commit_dev(struct build_feature_devs_info *binfo)  { @@ -235,13
> +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info
> *binfo)
>  	struct ifpga_fme_hw *fme;
>  	struct ifpga_feature *feature;
> 
> -	if (!binfo->fiu)
> -		return 0;
> -
>  	if (binfo->current_type == PORT_ID) {
> -		/* return error if no valid acc info data structure */
> -		if (!info)
> -			return -EFAULT;
> +		if (!binfo->fiu)
> +			return 0;
> 
>  		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
>  				       binfo->fiu);
> @@ -254,7 +248,7 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  		port = &hw->port[binfo->current_port_id];
>  		feature = get_feature_by_id(&port->feature_list,
>  				PORT_FEATURE_ID_UINT);
> -		if (feature)
> +		if (feature && info)
>  			info->num_irqs = feature->vec_cnt;
> 
>  		acc = opae_accelerator_alloc(hw->adapter->name,
> @@ -264,17 +258,21 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  			return -ENOMEM;
>  		}
> 
> +		acc->adapter = hw->adapter;
>  		acc->br = br;
>  		if (hw->adapter->mgr)
>  			acc->mgr = hw->adapter->mgr;
>  		acc->index = br->id;
> 
>  		fme = &hw->fme;
> -		fme->nums_acc_region = info->num_regions;
> +		fme->nums_acc_region = info ? info->num_regions : 0;
> 
>  		opae_adapter_add_acc(hw->adapter, acc);
> 
>  	} else if (binfo->current_type == FME_ID) {
> +		if (!binfo->fiu)
> +			return 0;
> +
>  		mgr = opae_manager_alloc(hw->adapter->name,
> &ifpga_mgr_ops,
>  				&ifpga_mgr_network_ops, binfo->fiu);
>  		if (!mgr)
> @@ -282,6 +280,22 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
> 
>  		mgr->adapter = hw->adapter;
>  		hw->adapter->mgr = mgr;
> +	} else if (binfo->current_type == AFU_ID) {
> +		if (!info)
> +			return -EFAULT;
> +
> +		info->num_irqs = 0;
> +		acc = opae_accelerator_alloc(hw->adapter->name,
> +					&ifpga_acc_ops, info);
> +		if (!acc)
> +			return -ENOMEM;
> +
> +		acc->adapter = hw->adapter;
> +		acc->br = NULL;
> +		acc->mgr = NULL;
> +		acc->index = hw->num_afus++;
> +
> +		opae_adapter_add_acc(hw->adapter, acc);
>  	}
> 
>  	binfo->fiu = NULL;
> @@ -295,11 +309,15 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)  {
>  	int ret;
> 
> +	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
> +		return 0;
> +
>  	ret = build_info_commit_dev(binfo);
>  	if (ret)
>  		return ret;
> 
>  	binfo->current_type = type;
> +	binfo->acc_info = NULL;
> 
>  	if (type == FME_ID) {
>  		binfo->fiu = &binfo->hw->fme;
> @@ -311,6 +329,41 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	return 0;
>  }
> 
> +static int parse_feature_afus(struct build_feature_devs_info *binfo,
> +			      struct feature_header *hdr)
> +{
> +	int ret;
> +	struct feature_afu_header *afu_hdr, header;
> +	u8 __iomem *start;
> +	u8 __iomem *end = binfo->ioend;
> +
> +	ret = build_info_create_dev(binfo, AFU_ID, 0);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 __iomem *)hdr;
> +	for (; start < end; start += header.next_afu) {
> +		if ((unsigned int)(end - start) <
> +			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> +			return -EINVAL;
> +
> +		hdr = (struct feature_header *)start;
> +		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> +		header.csr = readq(&afu_hdr->csr);
> +
> +		if (feature_is_UAFU(binfo)) {
> +			ret = parse_feature_uafu(binfo, hdr);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (!header.next_afu)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
>  static int parse_feature_fme(struct build_feature_devs_info *binfo,
>  			     struct feature_header *start)
>  {
> @@ -405,7 +458,7 @@ static int parse_feature_fiu(struct
> build_feature_devs_info *binfo,
>  			if (ret)
>  				return ret;
>  		} else {
> -			dev_info(binfo, "No AFUs detected on Port\n");
> +			dev_info(binfo, "No AFU detected on Port\n");
>  		}
> 
>  		break;
> @@ -426,7 +479,7 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
> 
>  	id = feature_id(start);
> 
> -	if (id == PORT_FEATURE_ID_UINT) {
> +	if ((binfo->current_type == PORT_ID) && (id ==
> PORT_FEATURE_ID_UINT))
> +{
>  		struct feature_port_uint *port_uint = start;
>  		struct feature_port_uint_cap uint_cap;
> 
> @@ -437,7 +490,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  		} else {
>  			dev_debug(binfo, "UAFU doesn't support interrupt\n");
>  		}
> -	} else if (id == PORT_FEATURE_ID_ERROR) {
> +	} else if ((binfo->current_type == PORT_ID) &&
> +			(id == PORT_FEATURE_ID_ERROR)) {
>  		struct feature_port_error *port_err = start;
>  		struct feature_port_err_capability port_err_cap;
> 
> @@ -449,7 +503,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  			dev_debug(&binfo, "Port error doesn't support
> interrupt\n");
>  		}
> 
> -	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
> +	} else if ((binfo->current_type == FME_ID) &&
> +			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
>  		struct feature_fme_err *fme_err = start;
>  		struct feature_fme_error_capability fme_err_cap;
> 
> @@ -497,9 +552,15 @@ static int parse_feature_private(struct
> build_feature_devs_info *binfo,
>  		return parse_feature_fme_private(binfo, hdr);
>  	case PORT_ID:
>  		return parse_feature_port_private(binfo, hdr);
> +	case AFU_ID:
> +		dev_err(binfo, "private feature %x belonging to AFU "
> +			"is not supported yet.\n", header.id);
> +		break;
>  	default:
> -		dev_err(binfo, "private feature %x belonging to AFU %d
> (unknown_type) is not supported yet.\n",
> +		dev_err(binfo, "private feature %x belonging to TYPE %d "
> +			"(unknown_type) is not supported yet.\n",
>  			header.id, binfo->current_type);
> +		break;
>  	}
>  	return 0;
>  }
> @@ -530,32 +591,57 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return ret;
>  }
> 
> -static int
> -parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
> +static int build_info_prepare(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
>  {
> +	if (!binfo || !dfl)
> +		return -EINVAL;
> +
> +	binfo->ioaddr = dfl->addr;
> +	binfo->ioend = (u8 *)dfl->addr + dfl->len;
> +	binfo->phys_addr = dfl->start;
> +
> +	return 0;
> +}
> +
> +static int parse_feature_list(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
> +{
> +	u8 *start, *end;
>  	struct feature_header *hdr, header;
> -	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
>  	int ret = 0;
> 
> +	ret = build_info_prepare(binfo, dfl);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 *)binfo->ioaddr;
> +	end = (u8 *)binfo->ioend;
> +
> +	/* walk through the device feature list via DFH's next DFH pointer. */
>  	for (; start < end; start += header.next_header_offset) {
>  		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
> -			dev_err(binfo, "The region is too small to contain a
> feature.\n");
> -			ret =  -EINVAL;
> +			dev_err(binfo, "The region is too small to "
> +				"contain a feature.\n");
> +			ret = -EINVAL;
>  			break;
>  		}
> 
>  		hdr = (struct feature_header *)start;
> -		header.csr = readq(hdr);
> +		header.csr = opae_readq(hdr);
> 
> -		dev_debug(binfo, "%s: address=0x%p, val=0x%llx,
> header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x,
> header.type=0x%x\n",
> -			__func__, hdr, (unsigned long long)header.csr,
> -			header.id, header.next_header_offset,
> -			header.end_of_list, header.type);
> +		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
> +			"header.id=0x%x, header.next_offset=0x%x, "
> +			"header.eol=0x%x, header.type=0x%x\n",
> +			__func__, hdr, header.csr, header.id,
> +			header.next_header_offset, header.end_of_list,
> +			header.type);
> 
>  		ret = parse_feature(binfo, hdr);
>  		if (ret)
>  			return ret;
> 
> +		/* stop parsing if EOL(End of List) is set or offset is 0 */
>  		if (header.end_of_list || !header.next_header_offset)
>  			break;
>  	}
> @@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info
> *binfo,
>  	return build_info_commit_dev(binfo);
>  }
> 
> -/* switch the memory mapping to BAR# @bar */ -static int
> parse_switch_to(struct build_feature_devs_info *binfo, int bar) -{
> -	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
> -
> -	if (!pci_data->region[bar].addr)
> -		return -ENOMEM;
> -
> -	binfo->ioaddr = pci_data->region[bar].addr;
> -	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data-
> >region[bar].len;
> -	binfo->phys_addr = pci_data->region[bar].phys_addr;
> -	binfo->current_bar = bar;
> -
> -	return 0;
> -}
> -
> -static int parse_ports_from_fme(struct build_feature_devs_info *binfo) -{
> -	struct feature_fme_header *fme_hdr;
> -	struct feature_fme_port port;
> -	int i = 0, ret = 0;
> -
> -	if (!binfo->pfme_hdr) {
> -		dev_info(binfo,  "VF is detected.\n");
> -		return ret;
> -	}
> -
> -	fme_hdr = binfo->pfme_hdr;
> -
> -	do {
> -		port.csr = readq(&fme_hdr->port[i]);
> -		if (!port.port_implemented)
> -			break;
> -
> -		/* skip port which only could be accessed via VF */
> -		if (port.afu_access_control == FME_AFU_ACCESS_VF)
> -			continue;
> -
> -		ret = parse_switch_to(binfo, port.port_bar);
> -		if (ret)
> -			break;
> -
> -		ret = parse_feature_list(binfo,
> -					 (u8 __iomem *)binfo->ioaddr +
> -					  port.port_offset);
> -		if (ret)
> -			break;
> -	} while (++i < MAX_FPGA_PORT_NUM);
> -
> -	return ret;
> -}
> -
> -static struct build_feature_devs_info * -build_info_alloc_and_init(struct
> ifpga_hw *hw) -{
> -	struct build_feature_devs_info *binfo;
> -
> -	binfo = zmalloc(sizeof(*binfo));
> -	if (!binfo)
> -		return binfo;
> -
> -	binfo->hw = hw;
> -	binfo->pci_data = hw->pci_data;
> -
> -	/* fpga feature list starts from BAR 0 */
> -	if (parse_switch_to(binfo, 0)) {
> -		free(binfo);
> -		return NULL;
> -	}
> -
> -	return binfo;
> -}
> -
>  static void build_info_free(struct build_feature_devs_info *binfo)  {
> -	free(binfo);
> +	opae_free(binfo);
>  }
> 
>  static void ifpga_print_device_feature_list(struct ifpga_hw *hw) @@ -648,6
> +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
>  	struct ifpga_feature *feature;
>  	int i;
> 
> +	if (fme->state == IFPGA_FME_UNUSED) {
> +		dev_info(hw, "FME is not present\n");
> +		return;
> +	}
> +
>  	dev_info(hw, "found fme_device, is in PF: %s\n",
>  		 is_ifpga_hw_pf(hw) ? "yes" : "no");
> 
> @@ -685,40 +703,411 @@ static void ifpga_print_device_feature_list(struct
> ifpga_hw *hw)
>  	}
>  }
> 
> -int ifpga_bus_enumerate(struct ifpga_hw *hw)
> +static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct
> +ifpga_hw *hw)
>  {
> -	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_info *info;
> +
> +	info = opae_zmalloc(sizeof(*info));
> +	if (!info)
> +		return NULL;
> +
> +	info->hw = hw;
> +	TAILQ_INIT(&info->dfls);
> +
> +	return info;
> +}
> +
> +static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info) {
> +	struct dfl_fpga_enum_dfl *tmp, *dfl;
> +
> +	if (!info)
> +		return;
> +
> +	/* remove all device feature lists in the list. */
> +	for (dfl = TAILQ_FIRST(&info->dfls);
> +		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
> +		dfl = tmp) {
> +		TAILQ_REMOVE(&info->dfls, dfl, node);
> +		opae_free(dfl);
> +	}
> +
> +	opae_free(info);
> +}
> +
> +static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
> +	u64 start, u64 len, void *addr)
> +{
> +	struct dfl_fpga_enum_dfl *dfl;
> +
> +	dfl = opae_zmalloc(sizeof(*dfl));
> +	if (!dfl)
> +		return -ENOMEM;
> +
> +	dfl->start = start;
> +	dfl->len = len;
> +	dfl->addr = addr;
> +
> +	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
> +
> +	return 0;
> +}
> +
> +#define PCI_CFG_SPACE_SIZE	256
> +#define PCI_CFG_SPACE_EXP_SIZE	4096
> +#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
> +#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
> +
> +static int
> +pci_find_next_ecap(int fd, int start, u32 cap) {
> +	u32 header;
> +	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
> +	int pos = PCI_CFG_SPACE_SIZE;
>  	int ret;
> 
> -	binfo = build_info_alloc_and_init(hw);
> +	if (start > 0)
> +		pos = start;
> +
> +	ret = pread(fd, &header, sizeof(header), pos);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * If we have no capabilities, this is indicated by cap ID,
> +	 * cap version and next pointer all being 0.
> +	 */
> +	if (header == 0)
> +		return 0;
> +
> +	while (ttl-- > 0) {
> +		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
> +			return pos;
> +
> +		pos = PCI_EXT_CAP_NEXT(header);
> +		if (pos < PCI_CFG_SPACE_SIZE)
> +			break;
> +		ret = pread(fd, &header, sizeof(header), pos);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define PCI_EXT_CAP_ID_VNDR	0x0B
> +#define PCI_VNDR_HEADER		4
> +#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
> +#define PCI_VENDOR_ID_INTEL 0x8086
> +#define PCI_VSEC_ID_INTEL_DFLS 0x43
> +#define PCI_VNDR_DFLS_CNT 0x8
> +#define PCI_VNDR_DFLS_RES 0xc
> +#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0) #define
> +PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
> +
> +static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	char path[64];
> +	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
> +	int fd, ret, dfl_res_off, voff = 0;
> +	u64 start, len;
> +	void *addr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->adapter || !hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
> +			hw->adapter->name);
> +	if ((unsigned int)ret >= sizeof(path))
> +		return -EINVAL;
> +
> +	fd = open(path, O_RDWR);
> +	if (fd < 0)
> +		return -EIO;
> +
> +	while ((voff = pci_find_next_ecap(fd, voff,
> +		PCI_EXT_CAP_ID_VNDR))) {
> +		vndr_hdr = 0;
> +		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
> +			voff + PCI_VNDR_HEADER);
> +		if (ret < 0)
> +			return -EIO;
> +		if (PCI_VNDR_HEADER_ID(vndr_hdr) ==
> PCI_VSEC_ID_INTEL_DFLS &&
> +			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
> +			break;
> +	}
> +
> +	if (!voff) {
> +		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	dfl_cnt = 0;
> +	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
> +	if (ret < 0)
> +		return -EIO;
> +
> +	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
> +	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
> +		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
> +		dfl_res = GENMASK(31, 0);
> +		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
> +		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
> +		if (bir >= PCI_MAX_RESOURCE) {
> +			dev_err(hw, "%s bad bir number %d\n",
> +				__func__, bir);
> +			return -EINVAL;
> +		}
> +
> +		len = pci_data->region[bir].len;
> +		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
> +		if (offset >= len) {
> +			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
> +				__func__, offset, len);
> +			return -EINVAL;
> +		}
> +
> +		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir,
> offset);
> +		len -= offset;
> +		start = pci_data->region[bir].phys_addr + offset;
> +		addr = pci_data->region[bir].addr + offset;
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	}
> +
> +	return 0;
> +}
> +
> +/* default method of finding dfls starting at offset 0 of bar 0 */
> +static int find_dfls_by_default(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	int port_num, bar, i, ret = 0;
> +	u64 start, len;
> +	void *addr;
> +	u32 offset;
> +	struct feature_header hdr;
> +	struct feature_fme_capability cap;
> +	struct feature_fme_port port;
> +	struct feature_fme_header *fme_hdr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	/* start to find Device Feature List from Bar 0 */
> +	addr = pci_data->region[0].addr;
> +	if (!addr)
> +		return -ENOMEM;
> +
> +	/*
> +	 * PF device has FME and Ports/AFUs, and VF device only has one
> +	 * Port/AFU. Check them and add related "Device Feature List" info
> +	 * for the next step enumeration.
> +	 */
> +	hdr.csr = opae_readq(addr);
> +	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id ==
> FEATURE_FIU_ID_FME)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +
> +		/*
> +		 * find more Device Feature Lists (e.g. Ports) per information
> +		 * indicated by FME module.
> +		 */
> +		fme_hdr = (struct feature_fme_header *)addr;
> +		cap.csr = opae_readq(&fme_hdr->capability);
> +		port_num = (int)cap.num_ports;
> +
> +		dev_info(hw, "port_num = %d\n", port_num);
> +		if (port_num > MAX_FPGA_PORT_NUM)
> +			port_num = MAX_FPGA_PORT_NUM;
> +
> +		for (i = 0; i < port_num; i++) {
> +			port.csr = opae_readq(&fme_hdr->port[i]);
> +
> +			/* skip ports which are not implemented. */
> +			if (!port.port_implemented)
> +				continue;
> +
> +			/* skip port which only could be accessed via VF */
> +			if (port.afu_access_control == FME_AFU_ACCESS_VF)
> +				continue;
> +
> +			/*
> +			 * add Port's Device Feature List information for next
> +			 * step enumeration.
> +			 */
> +			bar = (int)port.port_bar;
> +			offset = port.port_offset;
> +			if (bar == FME_PORT_OFST_BAR_SKIP) {
> +				continue;
> +			} else if (bar >= PCI_MAX_RESOURCE) {
> +				dev_err(hw, "bad BAR %d for port %d\n", bar,
> i);
> +				ret = -EINVAL;
> +				break;
> +			} else {
> +				dev_info(hw, "BAR %d offset %u\n", bar,
> offset);
> +			}
> +
> +			len = pci_data->region[bar].len;
> +			if (offset >= len) {
> +				dev_warn(hw, "bad port offset %u >= %pa\n",
> +					 offset, &len);
> +				continue;
> +			}
> +
> +			len -= offset;
> +			start = pci_data->region[bar].phys_addr + offset;
> +			addr = pci_data->region[bar].addr + offset;
> +			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +		}
> +	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
> +		(hdr.id == FEATURE_FIU_ID_PORT)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else if (hdr.type == FEATURE_TYPE_AFU) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else {
> +		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
> +			 hdr.type, hdr.id);
> +		ret = -ENODEV;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info
> +*info) {
> +	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_dfl *dfl;
> +	int ret = 0;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +
> +	/* create and init build info for enumeration */
> +	binfo = opae_zmalloc(sizeof(*binfo));
>  	if (!binfo)
>  		return -ENOMEM;
> 
> -	ret = parse_feature_list(binfo, binfo->ioaddr);
> +	binfo->hw = info->hw;
> +	binfo->pci_data = info->hw->pci_data;
> +
> +	/*
> +	 * start enumeration for all feature devices based on Device Feature
> +	 * Lists.
> +	 */
> +	TAILQ_FOREACH(dfl, &info->dfls, node) {
> +		ret = parse_feature_list(binfo, dfl);
> +		if (ret)
> +			break;
> +	}
> +
> +	build_info_free(binfo);
> +
> +	return ret;
> +}
> +
> +int ifpga_bus_enumerate(struct ifpga_hw *hw) {
> +	struct dfl_fpga_enum_info *info;
> +	int ret;
> +
> +	/* allocate enumeration info */
> +	info = dfl_fpga_enum_info_alloc(hw);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	ret = find_dfls_by_vsec(info);
> +	if (ret < 0)
> +		ret = find_dfls_by_default(info);
> +
>  	if (ret)
>  		goto exit;
> 
> -	ret = parse_ports_from_fme(binfo);
> -	if (ret)
> +	/* start enumeration with prepared enumeration information */
> +	ret = dfl_fpga_feature_devs_enumerate(info);
> +	if (ret < 0) {
> +		dev_err(hw, "Enumeration failure\n");
>  		goto exit;
> +	}
> 
>  	ifpga_print_device_feature_list(hw);
> 
>  exit:
> -	build_info_free(binfo);
> +	dfl_fpga_enum_info_free(info);
> +
>  	return ret;
>  }
> 
> -int ifpga_bus_init(struct ifpga_hw *hw)
> +static void ifpga_print_acc_list(struct opae_adapter *adapter)
>  {
> +	struct opae_accelerator *acc;
> +	struct ifpga_afu_info *info;
> +	struct uuid guid;
> +	char buf[48];
>  	int i;
> +
> +	opae_adapter_for_each_acc(adapter, acc) {
> +		info = acc->data;
> +		if (!info)
> +			continue;
> +		acc->ops->get_uuid(acc, &guid);
> +		i = sprintf(buf, "%02x%02x%02x%02x-",
> +			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
> +		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
> +			guid.b[5], guid.b[4], guid.b[3],
> +			guid.b[2], guid.b[1], guid.b[0]);
> +		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
> +			acc->name, acc->index, info->region[0].addr,
> +			info->region[0].len, buf);
> +	}
> +}
> +
> +int ifpga_bus_init(struct ifpga_hw *hw) {
> +	int i, ret = 0;
>  	struct ifpga_port_hw *port;
> 
> -	fme_hw_init(&hw->fme);
> +	ret = fme_hw_init(&hw->fme);
> +	if (ret)
> +		return ret;
> +
>  	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
>  		port = &hw->port[i];
>  		port_hw_init(port);
>  	}
> +	ifpga_print_acc_list(hw->adapter);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h
> b/drivers/raw/ifpga/base/ifpga_enumerate.h
> index 95ed594..e6b04f0 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.h
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
> @@ -5,6 +5,8 @@
>  #ifndef _IFPGA_ENUMERATE_H_
>  #define _IFPGA_ENUMERATE_H_
> 
> +#define FME_PORT_OFST_BAR_SKIP  7
> +
>  int ifpga_bus_init(struct ifpga_hw *hw);  int ifpga_bus_uinit(struct ifpga_hw
> *hw);  int ifpga_bus_enumerate(struct ifpga_hw *hw); diff --git
> a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> index 0813513..dbecc7b 100644
> --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> @@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
>  	if (fpga_wait_register_field(port_sftrst_ack, control,
>  				     &port_hdr->control, RST_POLL_TIMEOUT,
>  				     RST_POLL_INVL)) {
> -		dev_err(port, "timeout, fail to reset device\n");
> +		dev_err(port, "timeout, fail to reset FIM port\n");
>  		return -ETIMEDOUT;
>  	}
> 
> @@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list
> *list)
>  	struct ifpga_feature *feature;
> 
>  	TAILQ_FOREACH(feature, list, next) {
> -		if (feature->state != IFPGA_FEATURE_ATTACHED)
> +		if (feature->state != IFPGA_FEATURE_INITED)
>  			continue;
>  		if (feature->ops && feature->ops->uinit)
>  			feature->ops->uinit(feature);
> +		feature->state = IFPGA_FEATURE_ATTACHED;
>  	}
>  }
> 
> @@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
>  					ret = feature->ops->init(feature);
>  					if (ret)
>  						goto error;
> +					else
> +						feature->state =
> +
> 	IFPGA_FEATURE_INITED;
>  				}
>  			}
>  		}
> @@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
> 
>  int fme_hw_init(struct ifpga_fme_hw *fme)  {
> -	int ret;
> -
> -	if (fme->state != IFPGA_FME_IMPLEMENTED)
> -		return -ENODEV;
> -
> -	ret = feature_init(fme_feature_drvs, &fme->feature_list);
> -	if (ret)
> -		return ret;
> +	if (fme->state == IFPGA_FME_IMPLEMENTED)
> +		return feature_init(fme_feature_drvs, &fme->feature_list);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_hw.h
> b/drivers/raw/ifpga/base/ifpga_hw.h
> index ed5edc6..4d56deb 100644
> --- a/drivers/raw/ifpga/base/ifpga_hw.h
> +++ b/drivers/raw/ifpga/base/ifpga_hw.h
> @@ -15,6 +15,7 @@
>  enum ifpga_feature_state {
>  	IFPGA_FEATURE_UNUSED = 0,
>  	IFPGA_FEATURE_ATTACHED,
> +	IFPGA_FEATURE_INITED
>  };
> 
>  enum feature_type {
> @@ -134,6 +135,7 @@ struct ifpga_hw {
> 
>  	struct ifpga_fme_hw fme;
>  	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
> +	int num_afus;
>  };
> 
>  static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) diff --git
> a/drivers/raw/ifpga/base/opae_hw_api.c
> b/drivers/raw/ifpga/base/opae_hw_api.c
> index 11c9887..87256fc 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.c
> +++ b/drivers/raw/ifpga/base/opae_hw_api.c
> @@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator
> *acc,  int opae_acc_set_irq(struct opae_accelerator *acc,
>  		     u32 start, u32 count, s32 evtfds[])  {
> -	if (!acc || !acc->data)
> +	if (!acc)
>  		return -EINVAL;
> 
>  	if (start + count <= start)
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.h
> b/drivers/raw/ifpga/base/opae_hw_api.h
> index 7e04b56..fd40e09 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.h
> +++ b/drivers/raw/ifpga/base/opae_hw_api.h
> @@ -143,6 +143,7 @@ struct opae_accelerator {
>  	TAILQ_ENTRY(opae_accelerator) node;
>  	const char *name;
>  	int index;
> +	struct opae_adapter *adapter;
>  	struct opae_bridge *br;
>  	struct opae_manager *mgr;
>  	struct opae_accelerator_ops *ops;
> @@ -240,6 +241,7 @@ struct opae_adapter_data {
> 
>  struct opae_reg_region {
>  	u64 phys_addr;
> +#define AFU_REGION_SIZE  0x8000
>  	u64 len;
>  	u8 *addr;
>  };
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 94df56c..ceb18ae 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -47,11 +47,13 @@
>  #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
>  #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
>  #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
> +#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
>  /* VF Device */
>  #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
>  #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
>  #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
>  #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
> +#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
>  #define RTE_MAX_RAW_DEVICE           10
> 
>  static const struct rte_pci_id pci_ifpga_map[] = { @@ -63,6 +65,8 @@
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_DSC_1_X) },
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N3000),},
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N3000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N6000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N6000),},
>  	{ .vendor_id = 0, /* sentinel */ },
>  };
> 
> @@ -110,6 +114,7 @@ struct ifpga_rawdev *
> 
>  	return IFPGA_RAWDEV_NUM;
>  }
> +
>  static struct ifpga_rawdev *
>  ifpga_rawdev_allocate(struct rte_rawdev *rawdev)  { @@ -365,7 +370,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  		return -ENODEV;
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> +	if (!mgr || !mgr->sensor_list)
>  		return -ENODEV;
> 
>  	opae_mgr_for_each_sensor(mgr, sensor) { @@ -377,7 +382,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  			goto fail;
> 
>  		if (value == 0xdeadbeef) {
> -			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value
> %x\n",
> +			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s
> value %x\n",
>  					raw_dev->dev_id, sensor->name,
> value);
>  			continue;
>  		}
> @@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(  {
>  	struct opae_adapter *adapter;
>  	struct opae_manager *mgr;
> -	struct opae_board_info *info;
> +	struct opae_board_info *info = NULL;
>  	struct rte_afu_pr_conf *afu_pr_conf;
>  	int ret;
>  	struct uuid uuid;
> @@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
>  	}
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr) {
> -		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is
> NULL");
> -		return -1;
> -	}
> -
> -	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> -		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info
> fail!");
> -		return -1;
> +	if (mgr) {
> +		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> +			IFPGA_RAWDEV_PMD_ERR("ifpga manager
> get_board_info fail!");
> +			return -1;
> +		}
>  	}
> 
> -	if (info->lightweight) {
> +	if (info && info->lightweight) {
>  		/* set uuid to all 0, when fpga is lightweight image */
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
> @@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
>  			__func__,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
> -		}
> +	}
>  	return 0;
>  }
> 
> @@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
>  	if (ret) {
>  		ret = -ENOMEM;
> -		goto free_adapter_data;
> +		goto cleanup;
>  	}
> 
>  	rawdev->dev_ops = &ifpga_rawdev_ops;
> @@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	/* must enumerate the adapter before use it */
>  	ret = opae_adapter_enumerate(adapter);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	/* get opae_manager to rawdev */
>  	mgr = opae_adapter_get_mgr(adapter);
>  	if (mgr) {
> -		/* PF function */
> -		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
> +		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> +				fme_interrupt_handler, "fme_irq", mgr);
> +		if (ret)
> +			goto cleanup;
>  	}
> 
> -	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> -			fme_interrupt_handler, "fme_irq", mgr);
> -	if (ret)
> -		goto free_adapter_data;
> -
>  	ret = ifpga_monitor_start_func(dev);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	return ret;
> 
> -free_adapter_data:
> -	if (data)
> -		opae_adapter_data_free(data);
>  cleanup:
>  	if (rawdev)
>  		rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1

It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-26  3:32       ` [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
  2022-05-26  6:47         ` Xu, Rosen
@ 2022-05-27  3:19         ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-27  3:19 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Thursday, May 26, 2022 11:33 AM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc
> 
> OFS (Open FPGA Stack) specification is introduced briefly.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
>  doc/guides/rawdevs/ifpga.rst | 114
> ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 113 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst index
> dbd0d6e..8809bfc 100644
> --- a/doc/guides/rawdevs/ifpga.rst
> +++ b/doc/guides/rawdevs/ifpga.rst
> @@ -1,5 +1,5 @@
>  ..  SPDX-License-Identifier: BSD-3-Clause
> -    Copyright(c) 2018 Intel Corporation.
> +    Copyright(c) 2018-2022 Intel Corporation.
> 
>  IFPGA Rawdev Driver
>  ======================
> @@ -100,3 +100,115 @@ The following device parameters are supported:
> 
>    If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
>    identifies AFU Bit Stream file.
> +
> +
> +Open FPGA Stack
> +=====================
> +
> +Open FPGA Stack (OFS) is a collection of RTL and open source software
> +providing interfaces to access the instantiated RTL easily in an FPGA.
> +OFS leverages the DFL for the implementation of the FPGA RTL design.
> +
> +OFS designs allow for the arrangement of software interfaces across
> +multiple PCIe endpoints. Some of these interfaces may be PFs defined in
> +the static region that connect to interfaces in an IP that is loaded via Partial
> Reconfiguration (PR).
> +And some of these interfaces may be VFs defined in the PR region that
> +can be reconfigured by the end-user. Furthermore, these PFs/VFs may use
> +DFLs such that features may be discovered and accessed in user space
> +(with the aid of a generic kernel driver like vfio-pci). The diagram
> +below depicts an example design with two PFs and two VFs. In this
> +example, it will export the management functions via PF0,
> +PF1 will bind with virtio-net driver presenting itself as a network
> +interface to the OS. The other functions, VF0 and VF1, leverage VFIO to
> +export the MMIO space to an application or assign to a VM.::
> +
> +     +-----------------+  +--------------+  +-------------+  +------------+
> +     | FPGA Management |  |   VirtIO     |  |  User App   |  | Virtual    |
> +     |      App        |  |     App      |  |             |  | Machine    |
> +     +--------+--------+  +------+-------+  +------+------+  +-----+------+
> +              |                  |                 |               |
> +     +--------+--------+  +------+-------+  +------+------+        |
> +     |     DFL Driver  |  |VirtIO driver |  |    VFIO     |        |
> +     +--------+--------+  +------+-------+  +------+------+        |
> +              |                  |                 |               |
> +              |                  |                 |               |
> +     +--------+--------+  +------+-------+  +------+------+   +----+------+
> +     |     PF0         |  |     PF1      |  |   PF0_VF0   |   |  PF0_VF1  |
> +     +-----------------+  +--------------+  +-------------+   +-----------+
> +
This diagram those Applications are DPDK application?

> +As accelerators are specialized hardware, they are typically limited in
> +the number installed in a given system. Many use cases require them to
> +be shared across multiple software contexts or threads of software
> +execution, either through partitioning of individual dedicated
> +resources, or virtualization of shared resources. OFS provides several
> +models to share the AFU resources via PR mechanism and hardware-based
> virtualization schemes.
> +
> +1. Legacy model.
> +   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
> +   a notion that the boundary between the AFU and the shell is also the unit of
> +   PR for those FPGA platforms. This model is only able to handle a
> +   single context, because it only has one PR engine, and one PR region which
> +   has an associated Port device.
> +2. Multiple VFs per PR slot.
> +   In this model, available AFU resources may allow instantiation of many VFs
> +   which have a dedicated PCIe function with their own dedicated MMIO space,
> or
> +   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
> +   card has implemented this model.
> +   In this model, the AFU/PR slot was not connected to port device. For DFL's
> view,
> +   the Next_AFU pointer in FIU feature header of port device points to NULL in
> this
> +   model, so in AFU driver perspective, there is no AFU MMIO region managed
> by
> +   AFU driver. On the other hand, each VF can start with an AFU feature header
> without
> +   being connected to a FIU Port feature header.
> +
> +In multiple VFs per PR slot model, the port device can still be
> +accessed using ioctls API which expose /dev/dfl-port.h device nodes,
> +like port reset, get port info, whose APIs were mentioned in AFU
> +section in this documentation. But it cannot access the AFU MMIO space
> +via AFU ioctl APIs like DFL_FPGA_PORT_DMA_MAP because there is no AFU
> +MMIO space managed in the AFU driver. Users can access the AFU resource
> +by creating VF devices via PCIe SRIOV interface, and then access the VF via
> VFIO driver or assign the VF to VM.

This section is not mentioned for DPDK?

> +
> +In multiple VFs per PR slot model, the steps to enable VFs are
> +compatible with legacy mode which are mentioned in "FPGA virtualization
> +- PCIe SRIOV" section in this documentation.

The same of above.

I think we can add a little description how to leverage the  virtualization for DPDK usage for PAC card.
> +
> +OFS provides the diversity for accessing the AFU resource to RTL developer.
> +An IP designer may choose to add more than one PF for interfacing with
> +IP on the FPGA and choose different model to access the AFU resource.
> +
> +There is one reference architecture design using the "Multiple VFs per PR slot"
> +model for OFS as illustrated below. In this reference design, it
> +exports the FPGA management functions via PF0. PF1 will bind with
> +virtio-net driver presenting itself as a network interface to the OS.
> +PF2 will bind to the vfio-pci driver allowing the user space software
> +to discover and interface with the specific workload like diagnostic
> +test. To access the AFU resource, it uses SR-IOV to partition workload
> interfaces across various VFs.::
> +
> +                              +----------------------+
> +                              |   PF/VF mux/demux    |
> +                              +--+--+-----+------+-+-+
> +                                 |  |     |      | |
> +        +------------------------+  |     |      | |
> +  PF0   |                 +---------+   +-+      | |
> +    +---+---+             |         +---+----+   | |
> +    |  DFH  |             |         |   DFH  |   | |
> +    +-------+       +-----+----+    +--------+   | |
> +    |  FME  |       |  VirtIO  |    |  Test  |   | |
> +    +---+---+       +----------+    +--------+   | |
> +        |                PF1            PF2      | |
> +        |                                        | |
> +        |                             +----------+ |
> +        |                             |           ++
> +        |                             |           |
> +        |                             | PF0_VF0   | PF0_VF1
> +        |           +-----------------+-----------+------------+
> +        |           |           +-----+-----------+--------+   |
> +        |           |           |     |           |        |   |
> +        |           | +------+  |  +--+ -+     +--+---+    |   |
> +        |           | | Port |  |  | DFH |     |  DFH |    |   |
> +        +-----------+ +------+  |  +-----+     +------+    |   |
> +                    |           |  | DEV |     |  DEV |    |   |
> +                    |           |  +-----+     +------+    |   |
> +                    |           |            PR Slot       |   |
> +                    |           +--------------------------+   |
> +                    | Port Gasket                              |
> +                    +------------------------------------------+
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 0/5] Support OFS card
  2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
                         ` (4 preceding siblings ...)
  2022-05-26  3:32       ` [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
@ 2022-05-27  8:33       ` Wei Huang
  2022-05-27  8:33         ` [PATCH v4 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
                           ` (5 more replies)
  5 siblings, 6 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Changes from v3:
1. replace constant with PCI_PRI_STR_SIZE per Rosen's comment.
2. update commit log with more explanations about the function call.
3. fix typo and coding style issue.
4. update ifpga documentation per Tianfei's comment.

Wei Huang (5):
  raw/ifpga: remove experimental tag from ifpga APIs
  raw/ifpga: remove vdev when ifpga is closed
  raw/ifpga: unregister interrupt in ifpga close function
  raw/ifpga: support ofs card probe
  guides/rawdevs: add description of ofs in ifpga doc

 doc/guides/rawdevs/ifpga.rst               | 105 ++++-
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 680 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           | 241 ++++++----
 drivers/raw/ifpga/ifpga_rawdev.h           |   8 +
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  48 --
 drivers/raw/ifpga/version.map              |   7 +-
 13 files changed, 845 insertions(+), 299 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 1/5] raw/ifpga: remove experimental tag from ifpga APIs
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
@ 2022-05-27  8:33         ` Wei Huang
  2022-05-27  8:33         ` [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
                           ` (4 subsequent siblings)
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

These APIs are introduced in DPDK 21.05 and have been tested in several
release, experimental tag can be formally removed.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
 drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
 drivers/raw/ifpga/version.map     |  7 ++----
 2 files changed, 2 insertions(+), 53 deletions(-)

diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 47d66ba..3fa5d34 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -68,9 +68,6 @@
 } rte_pmd_ifpga_phy_info;
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
  *
  * @param pci_addr
@@ -82,14 +79,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-ENODEV) if FPGA is not probed by ifpga driver.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -103,14 +96,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Set current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -124,14 +113,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get FPGA property of specified Intel FPGA device
  *
  * @param dev_id
@@ -144,14 +129,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PHY information of specified Intel FPGA device
  *
  * @param dev_id
@@ -164,14 +145,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Update image flash of specified Intel FPGA device
  *
  * @param dev_id
@@ -187,15 +164,11 @@
  *   - (-EBUSY) if FPGA is updating or rebooting.
  *   - (-EIO) if failed to open image file.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
 	uint64_t *status);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Stop flash update of specified Intel FPGA device
  *
  * @param dev_id
@@ -208,14 +181,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EAGAIN) if failed with force.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Check current Intel FPGA status and change it to reboot status if it is idle
  *
  * @param dev_id
@@ -226,14 +195,10 @@
  *   - (-ENOMEM) if share data is not initialized.
  *   - (-EBUSY) if FPGA is updating or rebooting.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reboot_try(uint16_t dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Trigger full reconfiguration of specified Intel FPGA device
  *
  * @param dev_id
@@ -252,28 +217,20 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PCI bus the Intel FPGA driver register to
  *
  * @return
  *   - (valid pointer) if successful.
  *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
  */
-__rte_experimental
 const struct rte_pci_bus *
 rte_pmd_ifpga_get_pci_bus(void);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Perform PR (partial reconfiguration) on specified Intel FPGA device
  *
  * @param dev_id
@@ -287,17 +244,12 @@
  *   - (-EINVAL) if bad parameter or operation failed.
  *   - (-ENOMEM) if failed to allocate memory.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Free software resources allocated by Intel FPGA PMD
  */
-__rte_experimental
 void
 rte_pmd_ifpga_cleanup(void);
 
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index a1a6be2..ff71a45 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -1,11 +1,6 @@
 DPDK_22 {
-	local: *;
-};
-
-EXPERIMENTAL {
 	global:
 
-	# added in 21.05
 	rte_pmd_ifpga_get_dev_id;
 	rte_pmd_ifpga_get_rsu_status;
 	rte_pmd_ifpga_set_rsu_status;
@@ -18,4 +13,6 @@ EXPERIMENTAL {
 	rte_pmd_ifpga_get_pci_bus;
 	rte_pmd_ifpga_partial_reconfigure;
 	rte_pmd_ifpga_cleanup;
+
+	local: *;
 };
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
  2022-05-27  8:33         ` [PATCH v4 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-05-27  8:33         ` Wei Huang
  2022-06-06  6:46           ` Zhang, Tianfei
  2022-06-07  6:02           ` Xu, Rosen
  2022-05-27  8:33         ` [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
                           ` (3 subsequent siblings)
  5 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Virtual devices created on ifpga raw device will not be removed
when ifpga device has closed. To avoid resource leak problem,
this patch introduces an ifpga virtual device remove function,
virtual devices will be destroyed after the ifpga raw device closed.

Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
---
v2: update commit log with Tianfei's comment
---
v3: replace constant with PCI_PRI_STR_SIZE per Rosen's comment
---
 drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---------
 drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
 2 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 6d4117c..fe3fc43 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -134,6 +134,8 @@ struct ifpga_rawdev *
 	for (i = 0; i < IFPGA_MAX_IRQ; i++)
 		dev->intr_handle[i] = NULL;
 	dev->poll_enabled = 0;
+	for (i = 0; i < IFPGA_MAX_VDEV; i++)
+		dev->vdev_name[i] = NULL;
 
 	return dev;
 }
@@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(
 static int
 ifpga_rawdev_close(struct rte_rawdev *dev)
 {
+	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	char *vdev_name = NULL;
+	int i = 0;
 
 	if (dev) {
-		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
+		ifpga_rdev = ifpga_rawdev_get(dev);
+		if (ifpga_rdev) {
+			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+				vdev_name = ifpga_rdev->vdev_name[i];
+				if (vdev_name)
+					rte_vdev_uninit(vdev_name);
+			}
+			ifpga_monitor_stop_func(ifpga_rdev);
+			ifpga_rdev->rawdev = NULL;
+		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
 			opae_adapter_destroy(adapter);
@@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		return -EINVAL;
 	}
 	dev = ifpga_rawdev_get(rawdev);
-	if (dev)
-		dev->rawdev = NULL;
 
 	adapter = ifpga_rawdev_get_priv(rawdev);
 	if (!adapter)
@@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 
 	return 0;
 }
+
 static int
-ifpga_cfg_probe(struct rte_vdev_device *dev)
+ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
+	struct ifpga_vdev_args *args)
 {
-	struct rte_devargs *devargs;
-	struct rte_kvargs *kvlist = NULL;
-	struct rte_rawdev *rawdev = NULL;
-	struct ifpga_rawdev *ifpga_dev;
-	int port;
+	struct rte_kvargs *kvlist;
 	char *name = NULL;
-	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
-	int ret = -1;
+	int port = 0;
+	int ret = -EINVAL;
 
-	devargs = dev->device.devargs;
+	if (!devargs || !args)
+		return ret;
 
 	kvlist = rte_kvargs_parse(devargs->args, valid_args);
 	if (!kvlist) {
-		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
-		goto end;
+		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
+		return ret;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
 		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
-				       &ifpga_rawdev_get_string_arg,
-				       &name) < 0) {
+			&ifpga_rawdev_get_string_arg, &name) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
-				     IFPGA_ARG_NAME);
+				IFPGA_ARG_NAME);
 			goto end;
+		} else {
+			strlcpy(args->bdf, name, sizeof(args->bdf));
+			rte_free(name);
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_NAME);
+			IFPGA_ARG_NAME);
 		goto end;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
-		if (rte_kvargs_process(kvlist,
-			IFPGA_ARG_PORT,
-			&rte_ifpga_get_integer32_arg,
-			&port) < 0) {
+		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
+			&rte_ifpga_get_integer32_arg, &port) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
 				IFPGA_ARG_PORT);
 			goto end;
+		} else {
+			args->port = port;
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_PORT);
+			IFPGA_ARG_PORT);
 		goto end;
 	}
 
+	ret = 0;
+
+end:
+	if (kvlist)
+		rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+ifpga_cfg_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	int i, n, ret = 0;
+
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
 	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name);
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
 	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
 	if (!rawdev)
-		goto end;
+		return -ENODEV;
 	ifpga_dev = ifpga_rawdev_get(rawdev);
 	if (!ifpga_dev)
-		goto end;
+		return -ENODEV;
 
-	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
-	port, name);
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		if (ifpga_dev->vdev_name[i] == NULL) {
+			n = strlen(vdev_name) + 1;
+			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
+			if (ifpga_dev->vdev_name[i] == NULL)
+				return -ENOMEM;
+			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
+			break;
+		}
+	}
 
+	if (i >= IFPGA_MAX_VDEV) {
+		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
+		return -ENOENT;
+	}
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
 	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
-			dev_name, devargs->args);
-end:
-	rte_kvargs_free(kvlist);
-	free(name);
+			dev_name, vdev->device.devargs->args);
+	if (ret) {
+		rte_free(ifpga_dev->vdev_name[i]);
+		ifpga_dev->vdev_name[i] = NULL;
+	}
 
 	return ret;
 }
@@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 static int
 ifpga_cfg_remove(struct rte_vdev_device *vdev)
 {
-	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
-		vdev);
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	char *tmp_vdev = NULL;
+	int i, ret = 0;
 
-	return 0;
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
+	memset(dev_name, 0, sizeof(dev_name));
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
+	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
+	if (!rawdev)
+		return -ENODEV;
+	ifpga_dev = ifpga_rawdev_get(rawdev);
+	if (!ifpga_dev)
+		return -ENODEV;
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
+	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME), dev_name);
+
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		tmp_vdev = ifpga_dev->vdev_name[i];
+		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
+			free(tmp_vdev);
+			ifpga_dev->vdev_name[i] = NULL;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static struct rte_vdev_driver ifpga_cfg_driver = {
diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
index 857b734..4c19119 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.h
+++ b/drivers/raw/ifpga/ifpga_rawdev.h
@@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
 
 #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
 #define IFPGA_RAWDEV_NUM 32
+#define IFPGA_MAX_VDEV 4
 #define IFPGA_MAX_IRQ 12
 
 struct ifpga_rawdev {
@@ -64,6 +65,13 @@ struct ifpga_rawdev {
 	void *intr_handle[IFPGA_MAX_IRQ];
 	/* enable monitor thread poll device's sensors or not */
 	int poll_enabled;
+	/* name of virtual devices created on raw device */
+	char *vdev_name[IFPGA_MAX_VDEV];
+};
+
+struct ifpga_vdev_args {
+	char bdf[PCI_PRI_STR_SIZE];
+	int port;
 };
 
 struct ifpga_rawdev *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
  2022-05-27  8:33         ` [PATCH v4 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
  2022-05-27  8:33         ` [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-05-27  8:33         ` Wei Huang
  2022-06-07  6:03           ` Xu, Rosen
  2022-05-27  8:33         ` [PATCH v4 4/5] raw/ifpga: support ofs card probe Wei Huang
                           ` (2 subsequent siblings)
  5 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

There is an API rte_pmd_ifpga_cleanup provided by ifpga driver to
free the software resource used by ifpga card. The function call
of rte_pmd_ifpga_cleanup is list below.
rte_pmd_ifpga_cleanup()
  ifpga_rawdev_cleanup()
     rte_rawdev_pmd_release()
       rte_rawdev_close()
         ifpga_rawdev_close()

The interrupts are unregistered in ifpga_rawdev_destroy instead of
ifpga_rawdev_close function, so rte_pmd_ifpga_cleanup cannot free
interrupt resource as expected.

To fix such issue, interrupt unregistration is moved from
ifpga_rawdev_destroy to ifpga_rawdev_close function. The change of
function call of ifpga_rawdev_destroy is as below.
ifpga_rawdev_destroy()
  ifpga_unregister_msix_irq()  // removed
  rte_rawdev_pmd_release()
    rte_rawdev_close()
      ifpga_rawdev_close()

Fixes: e0a1aafe2af9 ("raw/ifpga: introduce IRQ functions")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
v2: update commit log with Tianfei's comment
---
v3: update commit log with more explanations about the function call
---
 drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index fe3fc43..94df56c 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(
 static int ifpga_pci_find_next_ext_capability(unsigned int fd,
 					      int start, uint32_t cap);
 static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
+static void fme_interrupt_handler(void *param);
 
 struct ifpga_rawdev *
 ifpga_rawdev_get(const struct rte_rawdev *rawdev)
@@ -740,8 +741,9 @@ static int set_surprise_link_check_aer(
 {
 	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	struct opae_manager *mgr;
 	char *vdev_name = NULL;
-	int i = 0;
+	int i, ret = 0;
 
 	if (dev) {
 		ifpga_rdev = ifpga_rawdev_get(dev);
@@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
 		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
+			mgr = opae_adapter_get_mgr(adapter);
+			if (ifpga_rdev && mgr) {
+				if (ifpga_unregister_msix_irq(ifpga_rdev,
+					IFPGA_FME_IRQ, 0,
+					fme_interrupt_handler, mgr) < 0)
+					ret = -EINVAL;
+			}
 			opae_adapter_destroy(adapter);
 			opae_adapter_data_free(adapter->data);
 		}
 	}
 
-	return dev ? 0:1;
+	return ret;
 }
 
 static int
@@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	int ret;
 	struct rte_rawdev *rawdev;
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
-	struct opae_adapter *adapter;
-	struct opae_manager *mgr;
-	struct ifpga_rawdev *dev;
 
 	if (!pci_dev) {
 		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
@@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
 		return -EINVAL;
 	}
-	dev = ifpga_rawdev_get(rawdev);
-
-	adapter = ifpga_rawdev_get_priv(rawdev);
-	if (!adapter)
-		return -ENODEV;
-
-	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
-		return -ENODEV;
-
-	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
-				fme_interrupt_handler, mgr) < 0)
-		return -EINVAL;
 
 	/* rte_rawdev_close is called by pmd_release */
 	ret = rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 4/5] raw/ifpga: support ofs card probe
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
                           ` (2 preceding siblings ...)
  2022-05-27  8:33         ` [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-05-27  8:33         ` Wei Huang
  2022-06-07  6:04           ` Xu, Rosen
  2022-05-27  8:33         ` [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
  5 siblings, 1 reply; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

PAC N6000 is the first OFS platform, its device id is added to ifpga
device support list.

Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
Feature List) starts from BAR0 by default, port DFL location is indicated
in PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port
DFL location can be defined individually in PCIe VSEC (Vendor Specific
Extended Capabilities). In this patch, DFL definition is searched in VSEC,
the legacy DFL is used only when DFL VSEC is not present.

In original DFL enumeration process, AFU is expected to locate in port DFL,
but this is not the case in OFS implementation. In this patch, enumeration
can search AFU in any PF/VF which has no FME and port.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
---
v2: fix build error in UB2004-32
---
v3: update commit log with Tianfei's comment, treat 7 as special BAR index
---
v4: fix typo and coding style issue
---
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 680 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
 9 files changed, 591 insertions(+), 192 deletions(-)

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index 4610ef1..f19cc26 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -13,15 +13,22 @@
 static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
 			      struct uuid *uuid)
 {
-	struct opae_bridge *br = acc->br;
-	struct ifpga_port_hw *port;
+	struct ifpga_afu_info *afu_info = acc->data;
+	struct opae_reg_region *region;
+	u64 val = 0;
 
-	if (!br || !br->data)
-		return -EINVAL;
+	if (!afu_info)
+		return -ENODEV;
 
-	port = br->data;
+	region = &afu_info->region[0];
+	if (uuid) {
+		val = readq(region->addr + sizeof(struct feature_header));
+		opae_memcpy(uuid->b, &val, sizeof(u64));
+		val = readq(region->addr + sizeof(struct feature_header) + 8);
+		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
+	}
 
-	return fpga_get_afu_uuid(port, uuid);
+	return 0;
 }
 
 static int ifpga_acc_set_irq(struct opae_accelerator *acc,
@@ -32,6 +39,9 @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
 	struct ifpga_port_hw *port;
 	struct fpga_uafu_irq_set irq_set;
 
+	if (!afu_info)
+		return -ENODEV;
+
 	if (!br || !br->data)
 		return -EINVAL;
 
@@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
 	struct ifpga_afu_info *afu_info = acc->data;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (info->index >= afu_info->num_regions)
 		return -EINVAL;
@@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
@@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h
index 8f62033..9a280eb 100644
--- a/drivers/raw/ifpga/base/ifpga_defines.h
+++ b/drivers/raw/ifpga/base/ifpga_defines.h
@@ -73,6 +73,7 @@
 enum fpga_id_type {
 	FME_ID,
 	PORT_ID,
+	AFU_ID,
 	FPGA_ID_MAX,
 };
 
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c b/drivers/raw/ifpga/base/ifpga_enumerate.c
index 48b8af4..7a5d264 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.c
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
@@ -2,6 +2,10 @@
  * Copyright(c) 2010-2018 Intel Corporation
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
 #include "opae_hw_api.h"
 #include "ifpga_api.h"
 
@@ -9,6 +13,19 @@
 #include "ifpga_enumerate.h"
 #include "ifpga_feature_dev.h"
 
+struct dfl_fpga_enum_dfl {
+	u64 start;
+	u64 len;
+	void *addr;
+	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
+};
+
+TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl);
+struct dfl_fpga_enum_info {
+	struct ifpga_hw *hw;
+	struct dfl_fpga_enum_dfls dfls;
+};
+
 struct build_feature_devs_info {
 	struct opae_adapter_data_pci *pci_data;
 
@@ -21,7 +38,6 @@ struct build_feature_devs_info {
 	void *ioaddr;
 	void *ioend;
 	uint64_t phys_addr;
-	int current_bar;
 
 	void *pfme_hdr;
 
@@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
 			unsigned int size, unsigned int vec_start,
 			unsigned int vec_cnt)
 {
-	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
-			vec_cnt);
+	if (binfo->current_type != AFU_ID)
+		return build_info_add_sub_feature(binfo, start, fid, size,
+			vec_start, vec_cnt);
+	return 0;
 }
 
 /*
@@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
  */
 static bool feature_is_UAFU(struct build_feature_devs_info *binfo)
 {
-	if (binfo->current_type != PORT_ID)
-		return false;
+	if ((binfo->current_type == PORT_ID) ||
+		(binfo->current_type == AFU_ID))
+		return true;
 
-	return true;
+	return false;
 }
 
-static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
+static int parse_feature_uafu(struct build_feature_devs_info *binfo,
 				   struct feature_header *hdr)
 {
 	u64 id = PORT_FEATURE_ID_UAFU;
@@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	int ret;
 	int size;
 
+	if (binfo->acc_info) {
+		dev_info(binfo, "Sub AFU found @ %p.\n", start);
+		return 0;
+	}
+
 	capability.csr = readq(&port_hdr->capability);
 
-	size = capability.mmio_size << 10;
+	if (binfo->current_type == AFU_ID) {
+		size = AFU_REGION_SIZE;
+	} else {
+		capability.csr = readq(&port_hdr->capability);
+		size = capability.mmio_size << 10;
+	}
 
 	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
 	if (ret)
@@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	info->region[0].phys_addr = binfo->phys_addr +
 			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
 	info->region[0].len = size;
-	info->num_regions = 1;
+	info->num_regions = AFU_MAX_REGION;
 
 	binfo->acc_info = info;
 
 	return ret;
 }
 
-static int parse_feature_afus(struct build_feature_devs_info *binfo,
-			      struct feature_header *hdr)
-{
-	int ret;
-	struct feature_afu_header *afu_hdr, header;
-	u8 __iomem *start;
-	u8 __iomem *end = binfo->ioend;
-
-	start = (u8 __iomem *)hdr;
-	for (; start < end; start += header.next_afu) {
-		if ((unsigned int)(end - start) <
-			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
-			return -EINVAL;
-
-		hdr = (struct feature_header *)start;
-		afu_hdr = (struct feature_afu_header *)(hdr + 1);
-		header.csr = readq(&afu_hdr->csr);
-
-		if (feature_is_UAFU(binfo)) {
-			ret = parse_feature_port_uafu(binfo, hdr);
-			if (ret)
-				return ret;
-		}
-
-		if (!header.next_afu)
-			break;
-	}
-
-	return 0;
-}
-
 /* create and register proper private data */
 static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
@@ -235,13 +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	struct ifpga_fme_hw *fme;
 	struct ifpga_feature *feature;
 
-	if (!binfo->fiu)
-		return 0;
-
 	if (binfo->current_type == PORT_ID) {
-		/* return error if no valid acc info data structure */
-		if (!info)
-			return -EFAULT;
+		if (!binfo->fiu)
+			return 0;
 
 		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
 				       binfo->fiu);
@@ -254,7 +248,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 		port = &hw->port[binfo->current_port_id];
 		feature = get_feature_by_id(&port->feature_list,
 				PORT_FEATURE_ID_UINT);
-		if (feature)
+		if (feature && info)
 			info->num_irqs = feature->vec_cnt;
 
 		acc = opae_accelerator_alloc(hw->adapter->name,
@@ -264,17 +258,21 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 			return -ENOMEM;
 		}
 
+		acc->adapter = hw->adapter;
 		acc->br = br;
 		if (hw->adapter->mgr)
 			acc->mgr = hw->adapter->mgr;
 		acc->index = br->id;
 
 		fme = &hw->fme;
-		fme->nums_acc_region = info->num_regions;
+		fme->nums_acc_region = info ? info->num_regions : 0;
 
 		opae_adapter_add_acc(hw->adapter, acc);
 
 	} else if (binfo->current_type == FME_ID) {
+		if (!binfo->fiu)
+			return 0;
+
 		mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,
 				&ifpga_mgr_network_ops, binfo->fiu);
 		if (!mgr)
@@ -282,6 +280,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 
 		mgr->adapter = hw->adapter;
 		hw->adapter->mgr = mgr;
+	} else if (binfo->current_type == AFU_ID) {
+		if (!info)
+			return -EFAULT;
+
+		info->num_irqs = 0;
+		acc = opae_accelerator_alloc(hw->adapter->name,
+					&ifpga_acc_ops, info);
+		if (!acc)
+			return -ENOMEM;
+
+		acc->adapter = hw->adapter;
+		acc->br = NULL;
+		acc->mgr = NULL;
+		acc->index = hw->num_afus++;
+
+		opae_adapter_add_acc(hw->adapter, acc);
 	}
 
 	binfo->fiu = NULL;
@@ -295,11 +309,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
 	int ret;
 
+	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
+		return 0;
+
 	ret = build_info_commit_dev(binfo);
 	if (ret)
 		return ret;
 
 	binfo->current_type = type;
+	binfo->acc_info = NULL;
 
 	if (type == FME_ID) {
 		binfo->fiu = &binfo->hw->fme;
@@ -311,6 +329,41 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	return 0;
 }
 
+static int parse_feature_afus(struct build_feature_devs_info *binfo,
+			      struct feature_header *hdr)
+{
+	int ret;
+	struct feature_afu_header *afu_hdr, header;
+	u8 __iomem *start;
+	u8 __iomem *end = binfo->ioend;
+
+	ret = build_info_create_dev(binfo, AFU_ID, 0);
+	if (ret)
+		return ret;
+
+	start = (u8 __iomem *)hdr;
+	for (; start < end; start += header.next_afu) {
+		if ((unsigned int)(end - start) <
+			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
+			return -EINVAL;
+
+		hdr = (struct feature_header *)start;
+		afu_hdr = (struct feature_afu_header *)(hdr + 1);
+		header.csr = readq(&afu_hdr->csr);
+
+		if (feature_is_UAFU(binfo)) {
+			ret = parse_feature_uafu(binfo, hdr);
+			if (ret)
+				return ret;
+		}
+
+		if (!header.next_afu)
+			break;
+	}
+
+	return 0;
+}
+
 static int parse_feature_fme(struct build_feature_devs_info *binfo,
 			     struct feature_header *start)
 {
@@ -405,7 +458,7 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 			if (ret)
 				return ret;
 		} else {
-			dev_info(binfo, "No AFUs detected on Port\n");
+			dev_info(binfo, "No AFU detected on Port\n");
 		}
 
 		break;
@@ -426,7 +479,7 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 
 	id = feature_id(start);
 
-	if (id == PORT_FEATURE_ID_UINT) {
+	if ((binfo->current_type == PORT_ID) && (id == PORT_FEATURE_ID_UINT)) {
 		struct feature_port_uint *port_uint = start;
 		struct feature_port_uint_cap uint_cap;
 
@@ -437,7 +490,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 		} else {
 			dev_debug(binfo, "UAFU doesn't support interrupt\n");
 		}
-	} else if (id == PORT_FEATURE_ID_ERROR) {
+	} else if ((binfo->current_type == PORT_ID) &&
+			(id == PORT_FEATURE_ID_ERROR)) {
 		struct feature_port_error *port_err = start;
 		struct feature_port_err_capability port_err_cap;
 
@@ -449,7 +503,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 			dev_debug(&binfo, "Port error doesn't support interrupt\n");
 		}
 
-	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
+	} else if ((binfo->current_type == FME_ID) &&
+			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
 		struct feature_fme_err *fme_err = start;
 		struct feature_fme_error_capability fme_err_cap;
 
@@ -497,9 +552,15 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
 		return parse_feature_fme_private(binfo, hdr);
 	case PORT_ID:
 		return parse_feature_port_private(binfo, hdr);
+	case AFU_ID:
+		dev_err(binfo, "private feature %x belonging to AFU "
+			"is not supported yet.\n", header.id);
+		break;
 	default:
-		dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n",
+		dev_err(binfo, "private feature %x belonging to TYPE %d "
+			"(unknown_type) is not supported yet.\n",
 			header.id, binfo->current_type);
+		break;
 	}
 	return 0;
 }
@@ -530,32 +591,57 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return ret;
 }
 
-static int
-parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
+static int build_info_prepare(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
 {
+	if (!binfo || !dfl)
+		return -EINVAL;
+
+	binfo->ioaddr = dfl->addr;
+	binfo->ioend = (u8 *)dfl->addr + dfl->len;
+	binfo->phys_addr = dfl->start;
+
+	return 0;
+}
+
+static int parse_feature_list(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
+{
+	u8 *start, *end;
 	struct feature_header *hdr, header;
-	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
 	int ret = 0;
 
+	ret = build_info_prepare(binfo, dfl);
+	if (ret)
+		return ret;
+
+	start = (u8 *)binfo->ioaddr;
+	end = (u8 *)binfo->ioend;
+
+	/* walk through the device feature list via DFH's next DFH pointer. */
 	for (; start < end; start += header.next_header_offset) {
 		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
-			dev_err(binfo, "The region is too small to contain a feature.\n");
-			ret =  -EINVAL;
+			dev_err(binfo, "The region is too small to "
+				"contain a feature.\n");
+			ret = -EINVAL;
 			break;
 		}
 
 		hdr = (struct feature_header *)start;
-		header.csr = readq(hdr);
+		header.csr = opae_readq(hdr);
 
-		dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n",
-			__func__, hdr, (unsigned long long)header.csr,
-			header.id, header.next_header_offset,
-			header.end_of_list, header.type);
+		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
+			"header.id=0x%x, header.next_offset=0x%x, "
+			"header.eol=0x%x, header.type=0x%x\n",
+			__func__, hdr, header.csr, header.id,
+			header.next_header_offset, header.end_of_list,
+			header.type);
 
 		ret = parse_feature(binfo, hdr);
 		if (ret)
 			return ret;
 
+		/* stop parsing if EOL(End of List) is set or offset is 0 */
 		if (header.end_of_list || !header.next_header_offset)
 			break;
 	}
@@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return build_info_commit_dev(binfo);
 }
 
-/* switch the memory mapping to BAR# @bar */
-static int parse_switch_to(struct build_feature_devs_info *binfo, int bar)
-{
-	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
-
-	if (!pci_data->region[bar].addr)
-		return -ENOMEM;
-
-	binfo->ioaddr = pci_data->region[bar].addr;
-	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len;
-	binfo->phys_addr = pci_data->region[bar].phys_addr;
-	binfo->current_bar = bar;
-
-	return 0;
-}
-
-static int parse_ports_from_fme(struct build_feature_devs_info *binfo)
-{
-	struct feature_fme_header *fme_hdr;
-	struct feature_fme_port port;
-	int i = 0, ret = 0;
-
-	if (!binfo->pfme_hdr) {
-		dev_info(binfo,  "VF is detected.\n");
-		return ret;
-	}
-
-	fme_hdr = binfo->pfme_hdr;
-
-	do {
-		port.csr = readq(&fme_hdr->port[i]);
-		if (!port.port_implemented)
-			break;
-
-		/* skip port which only could be accessed via VF */
-		if (port.afu_access_control == FME_AFU_ACCESS_VF)
-			continue;
-
-		ret = parse_switch_to(binfo, port.port_bar);
-		if (ret)
-			break;
-
-		ret = parse_feature_list(binfo,
-					 (u8 __iomem *)binfo->ioaddr +
-					  port.port_offset);
-		if (ret)
-			break;
-	} while (++i < MAX_FPGA_PORT_NUM);
-
-	return ret;
-}
-
-static struct build_feature_devs_info *
-build_info_alloc_and_init(struct ifpga_hw *hw)
-{
-	struct build_feature_devs_info *binfo;
-
-	binfo = zmalloc(sizeof(*binfo));
-	if (!binfo)
-		return binfo;
-
-	binfo->hw = hw;
-	binfo->pci_data = hw->pci_data;
-
-	/* fpga feature list starts from BAR 0 */
-	if (parse_switch_to(binfo, 0)) {
-		free(binfo);
-		return NULL;
-	}
-
-	return binfo;
-}
-
 static void build_info_free(struct build_feature_devs_info *binfo)
 {
-	free(binfo);
+	opae_free(binfo);
 }
 
 static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
@@ -648,6 +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	struct ifpga_feature *feature;
 	int i;
 
+	if (fme->state == IFPGA_FME_UNUSED) {
+		dev_info(hw, "FME is not present\n");
+		return;
+	}
+
 	dev_info(hw, "found fme_device, is in PF: %s\n",
 		 is_ifpga_hw_pf(hw) ? "yes" : "no");
 
@@ -685,40 +703,410 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	}
 }
 
-int ifpga_bus_enumerate(struct ifpga_hw *hw)
+static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct ifpga_hw *hw)
 {
-	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_info *info;
+
+	info = opae_zmalloc(sizeof(*info));
+	if (!info)
+		return NULL;
+
+	info->hw = hw;
+	TAILQ_INIT(&info->dfls);
+
+	return info;
+}
+
+static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
+{
+	struct dfl_fpga_enum_dfl *tmp, *dfl;
+
+	if (!info)
+		return;
+
+	/* remove all device feature lists in the list. */
+	for (dfl = TAILQ_FIRST(&info->dfls);
+		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
+		dfl = tmp) {
+		TAILQ_REMOVE(&info->dfls, dfl, node);
+		opae_free(dfl);
+	}
+
+	opae_free(info);
+}
+
+static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
+	u64 start, u64 len, void *addr)
+{
+	struct dfl_fpga_enum_dfl *dfl;
+
+	dfl = opae_zmalloc(sizeof(*dfl));
+	if (!dfl)
+		return -ENOMEM;
+
+	dfl->start = start;
+	dfl->len = len;
+	dfl->addr = addr;
+
+	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
+
+	return 0;
+}
+
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+static int
+pci_find_next_ecap(int fd, int start, u32 cap)
+{
+	u32 header;
+	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+	int pos = PCI_CFG_SPACE_SIZE;
 	int ret;
 
-	binfo = build_info_alloc_and_init(hw);
+	if (start > 0)
+		pos = start;
+
+	ret = pread(fd, &header, sizeof(header), pos);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+		ret = pread(fd, &header, sizeof(header), pos);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PCI_EXT_CAP_ID_VNDR	0x0B
+#define PCI_VNDR_HEADER		4
+#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VSEC_ID_INTEL_DFLS 0x43
+#define PCI_VNDR_DFLS_CNT 0x8
+#define PCI_VNDR_DFLS_RES 0xc
+#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
+#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
+
+static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	char path[64];
+	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
+	int fd, ret, dfl_res_off, voff = 0;
+	u64 start, len;
+	void *addr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->adapter || !hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
+			hw->adapter->name);
+	if ((unsigned int)ret >= sizeof(path))
+		return -EINVAL;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -EIO;
+
+	while ((voff = pci_find_next_ecap(fd, voff,
+		PCI_EXT_CAP_ID_VNDR))) {
+		vndr_hdr = 0;
+		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
+			voff + PCI_VNDR_HEADER);
+		if (ret < 0)
+			return -EIO;
+		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
+			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
+			break;
+	}
+
+	if (!voff) {
+		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
+		return -ENODEV;
+	}
+
+	dfl_cnt = 0;
+	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
+	if (ret < 0)
+		return -EIO;
+
+	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
+	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
+		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
+		dfl_res = GENMASK(31, 0);
+		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
+		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
+		if (bir >= PCI_MAX_RESOURCE) {
+			dev_err(hw, "%s bad bir number %d\n",
+				__func__, bir);
+			return -EINVAL;
+		}
+
+		len = pci_data->region[bir].len;
+		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
+		if (offset >= len) {
+			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
+				__func__, offset, len);
+			return -EINVAL;
+		}
+
+		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
+		len -= offset;
+		start = pci_data->region[bir].phys_addr + offset;
+		addr = pci_data->region[bir].addr + offset;
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	}
+
+	return 0;
+}
+
+/* default method of finding dfls starting at offset 0 of bar 0 */
+static int
+find_dfls_by_default(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	int port_num, bar, i, ret = 0;
+	u64 start, len;
+	void *addr;
+	u32 offset;
+	struct feature_header hdr;
+	struct feature_fme_capability cap;
+	struct feature_fme_port port;
+	struct feature_fme_header *fme_hdr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	/* start to find Device Feature List from Bar 0 */
+	addr = pci_data->region[0].addr;
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * PF device has FME and Ports/AFUs, and VF device only has one
+	 * Port/AFU. Check them and add related "Device Feature List" info
+	 * for the next step enumeration.
+	 */
+	hdr.csr = opae_readq(addr);
+	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id == FEATURE_FIU_ID_FME)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+
+		/*
+		 * find more Device Feature Lists (e.g. Ports) per information
+		 * indicated by FME module.
+		 */
+		fme_hdr = (struct feature_fme_header *)addr;
+		cap.csr = opae_readq(&fme_hdr->capability);
+		port_num = (int)cap.num_ports;
+
+		dev_info(hw, "port_num = %d\n", port_num);
+		if (port_num > MAX_FPGA_PORT_NUM)
+			port_num = MAX_FPGA_PORT_NUM;
+
+		for (i = 0; i < port_num; i++) {
+			port.csr = opae_readq(&fme_hdr->port[i]);
+
+			/* skip ports which are not implemented. */
+			if (!port.port_implemented)
+				continue;
+
+			/* skip port which only could be accessed via VF */
+			if (port.afu_access_control == FME_AFU_ACCESS_VF)
+				continue;
+
+			/*
+			 * add Port's Device Feature List information for next
+			 * step enumeration.
+			 */
+			bar = (int)port.port_bar;
+			offset = port.port_offset;
+			if (bar == FME_PORT_OFST_BAR_SKIP) {
+				continue;
+			} else if (bar >= PCI_MAX_RESOURCE) {
+				dev_err(hw, "bad BAR %d for port %d\n", bar, i);
+				ret = -EINVAL;
+				break;
+			}
+			dev_info(hw, "BAR %d offset %u\n", bar, offset);
+
+			len = pci_data->region[bar].len;
+			if (offset >= len) {
+				dev_warn(hw, "bad port offset %u >= %pa\n",
+					 offset, &len);
+				continue;
+			}
+
+			len -= offset;
+			start = pci_data->region[bar].phys_addr + offset;
+			addr = pci_data->region[bar].addr + offset;
+			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+		}
+	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
+		(hdr.id == FEATURE_FIU_ID_PORT)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else if (hdr.type == FEATURE_TYPE_AFU) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else {
+		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
+			 hdr.type, hdr.id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
+{
+	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_dfl *dfl;
+	int ret = 0;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+
+	/* create and init build info for enumeration */
+	binfo = opae_zmalloc(sizeof(*binfo));
 	if (!binfo)
 		return -ENOMEM;
 
-	ret = parse_feature_list(binfo, binfo->ioaddr);
+	binfo->hw = info->hw;
+	binfo->pci_data = info->hw->pci_data;
+
+	/*
+	 * start enumeration for all feature devices based on Device Feature
+	 * Lists.
+	 */
+	TAILQ_FOREACH(dfl, &info->dfls, node) {
+		ret = parse_feature_list(binfo, dfl);
+		if (ret)
+			break;
+	}
+
+	build_info_free(binfo);
+
+	return ret;
+}
+
+int ifpga_bus_enumerate(struct ifpga_hw *hw)
+{
+	struct dfl_fpga_enum_info *info;
+	int ret;
+
+	/* allocate enumeration info */
+	info = dfl_fpga_enum_info_alloc(hw);
+	if (!info)
+		return -ENOMEM;
+
+	ret = find_dfls_by_vsec(info);
+	if (ret < 0)
+		ret = find_dfls_by_default(info);
+
 	if (ret)
 		goto exit;
 
-	ret = parse_ports_from_fme(binfo);
-	if (ret)
+	/* start enumeration with prepared enumeration information */
+	ret = dfl_fpga_feature_devs_enumerate(info);
+	if (ret < 0) {
+		dev_err(hw, "Enumeration failure\n");
 		goto exit;
+	}
 
 	ifpga_print_device_feature_list(hw);
 
 exit:
-	build_info_free(binfo);
+	dfl_fpga_enum_info_free(info);
+
 	return ret;
 }
 
-int ifpga_bus_init(struct ifpga_hw *hw)
+static void ifpga_print_acc_list(struct opae_adapter *adapter)
 {
+	struct opae_accelerator *acc;
+	struct ifpga_afu_info *info;
+	struct uuid guid;
+	char buf[48];
 	int i;
+
+	opae_adapter_for_each_acc(adapter, acc) {
+		info = acc->data;
+		if (!info)
+			continue;
+		acc->ops->get_uuid(acc, &guid);
+		i = sprintf(buf, "%02x%02x%02x%02x-",
+			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
+		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
+			guid.b[5], guid.b[4], guid.b[3],
+			guid.b[2], guid.b[1], guid.b[0]);
+		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
+			acc->name, acc->index, info->region[0].addr,
+			info->region[0].len, buf);
+	}
+}
+
+int ifpga_bus_init(struct ifpga_hw *hw)
+{
+	int i, ret = 0;
 	struct ifpga_port_hw *port;
 
-	fme_hw_init(&hw->fme);
+	ret = fme_hw_init(&hw->fme);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
 		port = &hw->port[i];
 		port_hw_init(port);
 	}
+	ifpga_print_acc_list(hw->adapter);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h b/drivers/raw/ifpga/base/ifpga_enumerate.h
index 95ed594..e6b04f0 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.h
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
@@ -5,6 +5,8 @@
 #ifndef _IFPGA_ENUMERATE_H_
 #define _IFPGA_ENUMERATE_H_
 
+#define FME_PORT_OFST_BAR_SKIP  7
+
 int ifpga_bus_init(struct ifpga_hw *hw);
 int ifpga_bus_uinit(struct ifpga_hw *hw);
 int ifpga_bus_enumerate(struct ifpga_hw *hw);
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c
index 0813513..dbecc7b 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
@@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
 	if (fpga_wait_register_field(port_sftrst_ack, control,
 				     &port_hdr->control, RST_POLL_TIMEOUT,
 				     RST_POLL_INVL)) {
-		dev_err(port, "timeout, fail to reset device\n");
+		dev_err(port, "timeout, fail to reset FIM port\n");
 		return -ETIMEDOUT;
 	}
 
@@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list *list)
 	struct ifpga_feature *feature;
 
 	TAILQ_FOREACH(feature, list, next) {
-		if (feature->state != IFPGA_FEATURE_ATTACHED)
+		if (feature->state != IFPGA_FEATURE_INITED)
 			continue;
 		if (feature->ops && feature->ops->uinit)
 			feature->ops->uinit(feature);
+		feature->state = IFPGA_FEATURE_ATTACHED;
 	}
 }
 
@@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
 					ret = feature->ops->init(feature);
 					if (ret)
 						goto error;
+					else
+						feature->state =
+							IFPGA_FEATURE_INITED;
 				}
 			}
 		}
@@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
 
 int fme_hw_init(struct ifpga_fme_hw *fme)
 {
-	int ret;
-
-	if (fme->state != IFPGA_FME_IMPLEMENTED)
-		return -ENODEV;
-
-	ret = feature_init(fme_feature_drvs, &fme->feature_list);
-	if (ret)
-		return ret;
+	if (fme->state == IFPGA_FME_IMPLEMENTED)
+		return feature_init(fme_feature_drvs, &fme->feature_list);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h
index ed5edc6..4d56deb 100644
--- a/drivers/raw/ifpga/base/ifpga_hw.h
+++ b/drivers/raw/ifpga/base/ifpga_hw.h
@@ -15,6 +15,7 @@
 enum ifpga_feature_state {
 	IFPGA_FEATURE_UNUSED = 0,
 	IFPGA_FEATURE_ATTACHED,
+	IFPGA_FEATURE_INITED
 };
 
 enum feature_type {
@@ -134,6 +135,7 @@ struct ifpga_hw {
 
 	struct ifpga_fme_hw fme;
 	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
+	int num_afus;
 };
 
 static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 11c9887..87256fc 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator *acc,
 int opae_acc_set_irq(struct opae_accelerator *acc,
 		     u32 start, u32 count, s32 evtfds[])
 {
-	if (!acc || !acc->data)
+	if (!acc)
 		return -EINVAL;
 
 	if (start + count <= start)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 7e04b56..fd40e09 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -143,6 +143,7 @@ struct opae_accelerator {
 	TAILQ_ENTRY(opae_accelerator) node;
 	const char *name;
 	int index;
+	struct opae_adapter *adapter;
 	struct opae_bridge *br;
 	struct opae_manager *mgr;
 	struct opae_accelerator_ops *ops;
@@ -240,6 +241,7 @@ struct opae_adapter_data {
 
 struct opae_reg_region {
 	u64 phys_addr;
+#define AFU_REGION_SIZE  0x8000
 	u64 len;
 	u8 *addr;
 };
diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 94df56c..ceb18ae 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -47,11 +47,13 @@
 #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
 #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
 #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
+#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
 /* VF Device */
 #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
 #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
 #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
 #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
+#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
 #define RTE_MAX_RAW_DEVICE           10
 
 static const struct rte_pci_id pci_ifpga_map[] = {
@@ -63,6 +65,8 @@
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),},
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N6000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N6000),},
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -110,6 +114,7 @@ struct ifpga_rawdev *
 
 	return IFPGA_RAWDEV_NUM;
 }
+
 static struct ifpga_rawdev *
 ifpga_rawdev_allocate(struct rte_rawdev *rawdev)
 {
@@ -365,7 +370,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 		return -ENODEV;
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
+	if (!mgr || !mgr->sensor_list)
 		return -ENODEV;
 
 	opae_mgr_for_each_sensor(mgr, sensor) {
@@ -377,7 +382,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 			goto fail;
 
 		if (value == 0xdeadbeef) {
-			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value %x\n",
+			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s value %x\n",
 					raw_dev->dev_id, sensor->name, value);
 			continue;
 		}
@@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(
 {
 	struct opae_adapter *adapter;
 	struct opae_manager *mgr;
-	struct opae_board_info *info;
+	struct opae_board_info *info = NULL;
 	struct rte_afu_pr_conf *afu_pr_conf;
 	int ret;
 	struct uuid uuid;
@@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
 	}
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr) {
-		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL");
-		return -1;
-	}
-
-	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
-		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
-		return -1;
+	if (mgr) {
+		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
+			IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
+			return -1;
+		}
 	}
 
-	if (info->lightweight) {
+	if (info && info->lightweight) {
 		/* set uuid to all 0, when fpga is lightweight image */
 		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
 		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
@@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
 			__func__,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
-		}
+	}
 	return 0;
 }
 
@@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
 	if (ret) {
 		ret = -ENOMEM;
-		goto free_adapter_data;
+		goto cleanup;
 	}
 
 	rawdev->dev_ops = &ifpga_rawdev_ops;
@@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	/* must enumerate the adapter before use it */
 	ret = opae_adapter_enumerate(adapter);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	/* get opae_manager to rawdev */
 	mgr = opae_adapter_get_mgr(adapter);
 	if (mgr) {
-		/* PF function */
-		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
+		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
+				fme_interrupt_handler, "fme_irq", mgr);
+		if (ret)
+			goto cleanup;
 	}
 
-	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
-			fme_interrupt_handler, "fme_irq", mgr);
-	if (ret)
-		goto free_adapter_data;
-
 	ret = ifpga_monitor_start_func(dev);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	return ret;
 
-free_adapter_data:
-	if (data)
-		opae_adapter_data_free(data);
 cleanup:
 	if (rawdev)
 		rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
                           ` (3 preceding siblings ...)
  2022-05-27  8:33         ` [PATCH v4 4/5] raw/ifpga: support ofs card probe Wei Huang
@ 2022-05-27  8:33         ` Wei Huang
  2022-05-31  0:24           ` Zhang, Tianfei
  2022-06-06  6:45           ` Zhang, Tianfei
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
  5 siblings, 2 replies; 47+ messages in thread
From: Wei Huang @ 2022-05-27  8:33 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

OFS (Open FPGA Stack) specification is introduced briefly.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
v2: update description per Tianfei's comment
---
 doc/guides/rawdevs/ifpga.rst | 105 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 104 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst
index dbd0d6e..3dce57a 100644
--- a/doc/guides/rawdevs/ifpga.rst
+++ b/doc/guides/rawdevs/ifpga.rst
@@ -1,5 +1,5 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
-    Copyright(c) 2018 Intel Corporation.
+    Copyright(c) 2018-2022 Intel Corporation.
 
 IFPGA Rawdev Driver
 ======================
@@ -100,3 +100,106 @@ The following device parameters are supported:
 
   If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
   identifies AFU Bit Stream file.
+
+
+Open FPGA Stack
+=====================
+
+Open FPGA Stack (OFS) is a collection of RTL and open source software providing
+interfaces to access the instantiated RTL easily in an FPGA. OFS leverages the
+DFL for the implementation of the FPGA RTL design.
+
+OFS designs allow for the arrangement of software interfaces across multiple
+PCIe endpoints. Some of these interfaces may be PFs defined in the static region
+that connect to interfaces in an IP that is loaded via Partial Reconfiguration (PR).
+And some of these interfaces may be VFs defined in the PR region that can be
+reconfigured by the end-user. Furthermore, these PFs/VFs may use DFLs such that
+features may be discovered and accessed in user space with the aid of a generic
+kernel driver like vfio-pci. The diagram below depicts an example design with one
+PF and two VFs. In this example, it will export the management functions via PF0
+and acceleration functions via VF0 and VF1, leverage VFIO to export the MMIO space
+to an application.::
+
+     +-----------------+  +-------------+  +------------+
+     | FPGA Management |  |  DPDK App   |  |  User App  |
+     |      App        |  |             |  |            |
+     +--------+--------+  +------+------+  +-----+------+
+              |                  |               |
+     +--------+--------+  +------+------+        |
+     |IFPGA PMD driver |  |AFU MF driver|        |
+     +--------+--------+  +------+------+        |
+              |                  |               |
+     +--------+------------------+---------------+------+
+     |                VFIO-PCI                          |
+     +--------+------------------+---------------+------+
+              |                  |               |
+     +--------+--------+  +------+------+   +----+------+
+     |       PF0       |  |   PF0_VF0   |   |  PF0_VF1  |
+     +-----------------+  +-------------+   +-----------+
+
+As accelerators are specialized hardware, they are typically limited in the
+number installed in a given system. Many use cases require them to be shared
+across multiple software contexts or threads of software execution, either
+through partitioning of individual dedicated resources, or virtualization of
+shared resources. OFS provides several models to share the AFU resources via
+PR mechanism and hardware-based virtualization schemes.
+
+1. Legacy model.
+   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
+   a notion that the boundary between the AFU and the shell is also the unit of
+   PR for those FPGA platforms. This model is only able to handle a
+   single context, because it only has one PR engine, and one PR region which
+   has an associated Port device.
+2. Multiple VFs per PR slot.
+   In this model, available AFU resources may allow instantiation of many VFs
+   which have a dedicated PCIe function with their own dedicated MMIO space, or
+   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
+   card has implemented this model.
+   In this model, the AFU/PR slot was not connected to port device. For DFL's view,
+   the Next_AFU pointer in FIU feature header of port device points to NULL in this
+   model. On the other hand, each VF can start with an AFU feature header without
+   being connected to a FIU Port feature header.
+
+The VFs are created through the Linux kernel driver before we use them in DPDK.
+
+OFS provides the diversity for accessing the AFU resource to RTL developer.
+An IP designer may choose to add more than one PF for interfacing with IP
+on the FPGA and choose different model to access the AFU resource.
+
+There is one reference architecture design using the "Multiple VFs per PR slot"
+model for OFS as illustrated below. In this reference design, it exports the
+FPGA management functions via PF0. PF1 will bind with DPDK virtio driver
+presenting itself as a network interface to the application. PF2 will bind to the
+vfio-pci driver allowing the user space software to discover and interface
+with the specific workload like diagnostic test. It leverages AFU PMD driver to
+access the AFU resources in DPDK.::
+
+                              +----------------------+
+                              |   PF/VF mux/demux    |
+                              +--+--+-----+------+-+-+
+                                 |  |     |      | |
+        +------------------------+  |     |      | |
+  PF0   |                 +---------+   +-+      | |
+    +---+---+             |         +---+----+   | |
+    |  DFH  |             |         |   DFH  |   | |
+    +-------+       +-----+----+    +--------+   | |
+    |  FME  |       |  VirtIO  |    |  Test  |   | |
+    +---+---+       +----------+    +--------+   | |
+        |                PF1            PF2      | |
+        |                                        | |
+        |                             +----------+ |
+        |                             |           ++
+        |                             |           |
+        |                             | PF0_VF0   | PF0_VF1
+        |           +-----------------+-----------+------------+
+        |           |           +-----+-----------+--------+   |
+        |           |           |     |           |        |   |
+        |           | +------+  |  +--+ -+     +--+---+    |   |
+        |           | | Port |  |  | DFH |     |  DFH |    |   |
+        +-----------+ +------+  |  +-----+     +------+    |   |
+                    |           |  | DEV |     |  DEV |    |   |
+                    |           |  +-----+     +------+    |   |
+                    |           |            PR Slot       |   |
+                    |           +--------------------------+   |
+                    | Port Gasket                              |
+                    +------------------------------------------+
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-27  8:33         ` [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
@ 2022-05-31  0:24           ` Zhang, Tianfei
  2022-06-06  6:45           ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-05-31  0:24 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 4:34 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc
> 
> OFS (Open FPGA Stack) specification is introduced briefly.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Reviewed-by: Rosen Xu <rosen.xu@intel.com>
> ---
> v2: update description per Tianfei's comment
> ---
>  doc/guides/rawdevs/ifpga.rst | 105
> ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 104 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst index
> dbd0d6e..3dce57a 100644
> --- a/doc/guides/rawdevs/ifpga.rst
> +++ b/doc/guides/rawdevs/ifpga.rst
> @@ -1,5 +1,5 @@
>  ..  SPDX-License-Identifier: BSD-3-Clause
> -    Copyright(c) 2018 Intel Corporation.
> +    Copyright(c) 2018-2022 Intel Corporation.
> 
>  IFPGA Rawdev Driver
>  ======================
> @@ -100,3 +100,106 @@ The following device parameters are supported:
> 
>    If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
>    identifies AFU Bit Stream file.
> +
> +
> +Open FPGA Stack
> +=====================
> +
> +Open FPGA Stack (OFS) is a collection of RTL and open source software
> +providing interfaces to access the instantiated RTL easily in an FPGA.
> +OFS leverages the DFL for the implementation of the FPGA RTL design.
> +
> +OFS designs allow for the arrangement of software interfaces across
> +multiple PCIe endpoints. Some of these interfaces may be PFs defined in
> +the static region that connect to interfaces in an IP that is loaded via Partial
> Reconfiguration (PR).
> +And some of these interfaces may be VFs defined in the PR region that
> +can be reconfigured by the end-user. Furthermore, these PFs/VFs may use
> +DFLs such that features may be discovered and accessed in user space
> +with the aid of a generic kernel driver like vfio-pci. The diagram
> +below depicts an example design with one PF and two VFs. In this
> +example, it will export the management functions via PF0 and
> +acceleration functions via VF0 and VF1, leverage VFIO to export the MMIO
> space to an application.::
> +
> +     +-----------------+  +-------------+  +------------+
> +     | FPGA Management |  |  DPDK App   |  |  User App  |
> +     |      App        |  |             |  |            |
> +     +--------+--------+  +------+------+  +-----+------+
> +              |                  |               |
> +     +--------+--------+  +------+------+        |
> +     |IFPGA PMD driver |  |AFU MF driver|        |
> +     +--------+--------+  +------+------+        |
> +              |                  |               |
> +     +--------+------------------+---------------+------+
> +     |                VFIO-PCI                          |
> +     +--------+------------------+---------------+------+
> +              |                  |               |
> +     +--------+--------+  +------+------+   +----+------+
> +     |       PF0       |  |   PF0_VF0   |   |  PF0_VF1  |
> +     +-----------------+  +-------------+   +-----------+
> +
> +As accelerators are specialized hardware, they are typically limited in
> +the number installed in a given system. Many use cases require them to
> +be shared across multiple software contexts or threads of software
> +execution, either through partitioning of individual dedicated
> +resources, or virtualization of shared resources. OFS provides several
> +models to share the AFU resources via PR mechanism and hardware-based
> virtualization schemes.
> +
> +1. Legacy model.
> +   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
> +   a notion that the boundary between the AFU and the shell is also the unit of
> +   PR for those FPGA platforms. This model is only able to handle a
> +   single context, because it only has one PR engine, and one PR region which
> +   has an associated Port device.
> +2. Multiple VFs per PR slot.
> +   In this model, available AFU resources may allow instantiation of many VFs
> +   which have a dedicated PCIe function with their own dedicated MMIO space,
> or
> +   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
> +   card has implemented this model.
> +   In this model, the AFU/PR slot was not connected to port device. For DFL's
> view,
> +   the Next_AFU pointer in FIU feature header of port device points to NULL in
> this
> +   model. On the other hand, each VF can start with an AFU feature header
> without
> +   being connected to a FIU Port feature header.
> +
> +The VFs are created through the Linux kernel driver before we use them in
> DPDK.
> +
> +OFS provides the diversity for accessing the AFU resource to RTL developer.
> +An IP designer may choose to add more than one PF for interfacing with
> +IP on the FPGA and choose different model to access the AFU resource.
> +
> +There is one reference architecture design using the "Multiple VFs per PR slot"
> +model for OFS as illustrated below. In this reference design, it
> +exports the FPGA management functions via PF0. PF1 will bind with DPDK
> +virtio driver presenting itself as a network interface to the
> +application. PF2 will bind to the vfio-pci driver allowing the user
> +space software to discover and interface with the specific workload
> +like diagnostic test. It leverages AFU PMD driver to access the AFU resources in
> DPDK.::
> +
> +                              +----------------------+
> +                              |   PF/VF mux/demux    |
> +                              +--+--+-----+------+-+-+
> +                                 |  |     |      | |
> +        +------------------------+  |     |      | |
> +  PF0   |                 +---------+   +-+      | |
> +    +---+---+             |         +---+----+   | |
> +    |  DFH  |             |         |   DFH  |   | |
> +    +-------+       +-----+----+    +--------+   | |
> +    |  FME  |       |  VirtIO  |    |  Test  |   | |
> +    +---+---+       +----------+    +--------+   | |
> +        |                PF1            PF2      | |
> +        |                                        | |
> +        |                             +----------+ |
> +        |                             |           ++
> +        |                             |           |
> +        |                             | PF0_VF0   | PF0_VF1
> +        |           +-----------------+-----------+------------+
> +        |           |           +-----+-----------+--------+   |
> +        |           |           |     |           |        |   |
> +        |           | +------+  |  +--+ -+     +--+---+    |   |
> +        |           | | Port |  |  | DFH |     |  DFH |    |   |
> +        +-----------+ +------+  |  +-----+     +------+    |   |
> +                    |           |  | DEV |     |  DEV |    |   |
> +                    |           |  +-----+     +------+    |   |
> +                    |           |            PR Slot       |   |
> +                    |           +--------------------------+   |
> +                    | Port Gasket                              |
> +                    +------------------------------------------+
> --
> 1.8.3.1

Hi Wei,

It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>



^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-05-27  8:33         ` [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
  2022-05-31  0:24           ` Zhang, Tianfei
@ 2022-06-06  6:45           ` Zhang, Tianfei
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-06-06  6:45 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 4:34 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc
> 
> OFS (Open FPGA Stack) specification is introduced briefly.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Reviewed-by: Rosen Xu <rosen.xu@intel.com>
> ---
> v2: update description per Tianfei's comment
> ---
>  doc/guides/rawdevs/ifpga.rst | 105
> ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 104 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst index
> dbd0d6e..3dce57a 100644
> --- a/doc/guides/rawdevs/ifpga.rst
> +++ b/doc/guides/rawdevs/ifpga.rst
> @@ -1,5 +1,5 @@
>  ..  SPDX-License-Identifier: BSD-3-Clause
> -    Copyright(c) 2018 Intel Corporation.
> +    Copyright(c) 2018-2022 Intel Corporation.
> 
>  IFPGA Rawdev Driver
>  ======================
> @@ -100,3 +100,106 @@ The following device parameters are supported:
> 
>    If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
>    identifies AFU Bit Stream file.
> +
> +
> +Open FPGA Stack
> +=====================
> +
> +Open FPGA Stack (OFS) is a collection of RTL and open source software
> +providing interfaces to access the instantiated RTL easily in an FPGA.
> +OFS leverages the DFL for the implementation of the FPGA RTL design.
> +
> +OFS designs allow for the arrangement of software interfaces across
> +multiple PCIe endpoints. Some of these interfaces may be PFs defined in
> +the static region that connect to interfaces in an IP that is loaded via Partial
> Reconfiguration (PR).
> +And some of these interfaces may be VFs defined in the PR region that
> +can be reconfigured by the end-user. Furthermore, these PFs/VFs may use
> +DFLs such that features may be discovered and accessed in user space
> +with the aid of a generic kernel driver like vfio-pci. The diagram
> +below depicts an example design with one PF and two VFs. In this
> +example, it will export the management functions via PF0 and
> +acceleration functions via VF0 and VF1, leverage VFIO to export the MMIO
> space to an application.::
> +
> +     +-----------------+  +-------------+  +------------+
> +     | FPGA Management |  |  DPDK App   |  |  User App  |
> +     |      App        |  |             |  |            |
> +     +--------+--------+  +------+------+  +-----+------+
> +              |                  |               |
> +     +--------+--------+  +------+------+        |
> +     |IFPGA PMD driver |  |AFU MF driver|        |
> +     +--------+--------+  +------+------+        |
> +              |                  |               |
> +     +--------+------------------+---------------+------+
> +     |                VFIO-PCI                          |
> +     +--------+------------------+---------------+------+
> +              |                  |               |
> +     +--------+--------+  +------+------+   +----+------+
> +     |       PF0       |  |   PF0_VF0   |   |  PF0_VF1  |
> +     +-----------------+  +-------------+   +-----------+
> +
> +As accelerators are specialized hardware, they are typically limited in
> +the number installed in a given system. Many use cases require them to
> +be shared across multiple software contexts or threads of software
> +execution, either through partitioning of individual dedicated
> +resources, or virtualization of shared resources. OFS provides several
> +models to share the AFU resources via PR mechanism and hardware-based
> virtualization schemes.
> +
> +1. Legacy model.
> +   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
> +   a notion that the boundary between the AFU and the shell is also the unit of
> +   PR for those FPGA platforms. This model is only able to handle a
> +   single context, because it only has one PR engine, and one PR region which
> +   has an associated Port device.
> +2. Multiple VFs per PR slot.
> +   In this model, available AFU resources may allow instantiation of many VFs
> +   which have a dedicated PCIe function with their own dedicated MMIO space,
> or
> +   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
> +   card has implemented this model.
> +   In this model, the AFU/PR slot was not connected to port device. For DFL's
> view,
> +   the Next_AFU pointer in FIU feature header of port device points to NULL in
> this
> +   model. On the other hand, each VF can start with an AFU feature header
> without
> +   being connected to a FIU Port feature header.
> +
> +The VFs are created through the Linux kernel driver before we use them in
> DPDK.
> +
> +OFS provides the diversity for accessing the AFU resource to RTL developer.
> +An IP designer may choose to add more than one PF for interfacing with
> +IP on the FPGA and choose different model to access the AFU resource.
> +
> +There is one reference architecture design using the "Multiple VFs per PR slot"
> +model for OFS as illustrated below. In this reference design, it
> +exports the FPGA management functions via PF0. PF1 will bind with DPDK
> +virtio driver presenting itself as a network interface to the
> +application. PF2 will bind to the vfio-pci driver allowing the user
> +space software to discover and interface with the specific workload
> +like diagnostic test. It leverages AFU PMD driver to access the AFU resources in
> DPDK.::
> +
> +                              +----------------------+
> +                              |   PF/VF mux/demux    |
> +                              +--+--+-----+------+-+-+
> +                                 |  |     |      | |
> +        +------------------------+  |     |      | |
> +  PF0   |                 +---------+   +-+      | |
> +    +---+---+             |         +---+----+   | |
> +    |  DFH  |             |         |   DFH  |   | |
> +    +-------+       +-----+----+    +--------+   | |
> +    |  FME  |       |  VirtIO  |    |  Test  |   | |
> +    +---+---+       +----------+    +--------+   | |
> +        |                PF1            PF2      | |
> +        |                                        | |
> +        |                             +----------+ |
> +        |                             |           ++
> +        |                             |           |
> +        |                             | PF0_VF0   | PF0_VF1
> +        |           +-----------------+-----------+------------+
> +        |           |           +-----+-----------+--------+   |
> +        |           |           |     |           |        |   |
> +        |           | +------+  |  +--+ -+     +--+---+    |   |
> +        |           | | Port |  |  | DFH |     |  DFH |    |   |
> +        +-----------+ +------+  |  +-----+     +------+    |   |
> +                    |           |  | DEV |     |  DEV |    |   |
> +                    |           |  +-----+     +------+    |   |
> +                    |           |            PR Slot       |   |
> +                    |           +--------------------------+   |
> +                    | Port Gasket                              |
> +                    +------------------------------------------+
> --
It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-05-27  8:33         ` [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-06-06  6:46           ` Zhang, Tianfei
  2022-06-07  6:02           ` Xu, Rosen
  1 sibling, 0 replies; 47+ messages in thread
From: Zhang, Tianfei @ 2022-06-06  6:46 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Xu, Rosen, Zhang, Qi Z



> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 4:34 PM
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed
> 
> Virtual devices created on ifpga raw device will not be removed when ifpga
> device has closed. To avoid resource leak problem, this patch introduces an
> ifpga virtual device remove function, virtual devices will be destroyed after the
> ifpga raw device closed.
> 
> Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: update commit log with Tianfei's comment
> ---
> v3: replace constant with PCI_PRI_STR_SIZE per Rosen's comment
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---
> ------
>  drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
>  2 files changed, 138 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 6d4117c..fe3fc43 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -134,6 +134,8 @@ struct ifpga_rawdev *
>  	for (i = 0; i < IFPGA_MAX_IRQ; i++)
>  		dev->intr_handle[i] = NULL;
>  	dev->poll_enabled = 0;
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++)
> +		dev->vdev_name[i] = NULL;
> 
>  	return dev;
>  }
> @@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(  static int
> ifpga_rawdev_close(struct rte_rawdev *dev)  {
> +	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	char *vdev_name = NULL;
> +	int i = 0;
> 
>  	if (dev) {
> -		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
> +		ifpga_rdev = ifpga_rawdev_get(dev);
> +		if (ifpga_rdev) {
> +			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +				vdev_name = ifpga_rdev->vdev_name[i];
> +				if (vdev_name)
> +					rte_vdev_uninit(vdev_name);
> +			}
> +			ifpga_monitor_stop_func(ifpga_rdev);
> +			ifpga_rdev->rawdev = NULL;
> +		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
>  			opae_adapter_destroy(adapter);
> @@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager
> *mgr)
>  		return -EINVAL;
>  	}
>  	dev = ifpga_rawdev_get(rawdev);
> -	if (dev)
> -		dev->rawdev = NULL;
> 
>  	adapter = ifpga_rawdev_get_priv(rawdev);
>  	if (!adapter)
> @@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char
> *key __rte_unused,
> 
>  	return 0;
>  }
> +
>  static int
> -ifpga_cfg_probe(struct rte_vdev_device *dev)
> +ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
> +	struct ifpga_vdev_args *args)
>  {
> -	struct rte_devargs *devargs;
> -	struct rte_kvargs *kvlist = NULL;
> -	struct rte_rawdev *rawdev = NULL;
> -	struct ifpga_rawdev *ifpga_dev;
> -	int port;
> +	struct rte_kvargs *kvlist;
>  	char *name = NULL;
> -	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> -	int ret = -1;
> +	int port = 0;
> +	int ret = -EINVAL;
> 
> -	devargs = dev->device.devargs;
> +	if (!devargs || !args)
> +		return ret;
> 
>  	kvlist = rte_kvargs_parse(devargs->args, valid_args);
>  	if (!kvlist) {
> -		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
> -		goto end;
> +		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
> +		return ret;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
>  		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
> -				       &ifpga_rawdev_get_string_arg,
> -				       &name) < 0) {
> +			&ifpga_rawdev_get_string_arg, &name) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
> -				     IFPGA_ARG_NAME);
> +				IFPGA_ARG_NAME);
>  			goto end;
> +		} else {
> +			strlcpy(args->bdf, name, sizeof(args->bdf));
> +			rte_free(name);
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
> -			  IFPGA_ARG_NAME);
> +			IFPGA_ARG_NAME);
>  		goto end;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
> -		if (rte_kvargs_process(kvlist,
> -			IFPGA_ARG_PORT,
> -			&rte_ifpga_get_integer32_arg,
> -			&port) < 0) {
> +		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
> +			&rte_ifpga_get_integer32_arg, &port) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
>  				IFPGA_ARG_PORT);
>  			goto end;
> +		} else {
> +			args->port = port;
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
> -			  IFPGA_ARG_PORT);
> +			IFPGA_ARG_PORT);
>  		goto end;
>  	}
> 
> +	ret = 0;
> +
> +end:
> +	if (kvlist)
> +		rte_kvargs_free(kvlist);
> +
> +	return ret;
> +}
> +
> +static int
> +ifpga_cfg_probe(struct rte_vdev_device *vdev) {
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	int i, n, ret = 0;
> +
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
>  	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> name);
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
>  	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
>  	if (!rawdev)
> -		goto end;
> +		return -ENODEV;
>  	ifpga_dev = ifpga_rawdev_get(rawdev);
>  	if (!ifpga_dev)
> -		goto end;
> +		return -ENODEV;
> 
> -	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> -	port, name);
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		if (ifpga_dev->vdev_name[i] == NULL) {
> +			n = strlen(vdev_name) + 1;
> +			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
> +			if (ifpga_dev->vdev_name[i] == NULL)
> +				return -ENOMEM;
> +			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
> +			break;
> +		}
> +	}
> 
> +	if (i >= IFPGA_MAX_VDEV) {
> +		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
> +		return -ENOENT;
> +	}
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
>  	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
> -			dev_name, devargs->args);
> -end:
> -	rte_kvargs_free(kvlist);
> -	free(name);
> +			dev_name, vdev->device.devargs->args);
> +	if (ret) {
> +		rte_free(ifpga_dev->vdev_name[i]);
> +		ifpga_dev->vdev_name[i] = NULL;
> +	}
> 
>  	return ret;
>  }
> @@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char
> *key __rte_unused,  static int  ifpga_cfg_remove(struct rte_vdev_device *vdev)
> {
> -	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
> -		vdev);
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	char *tmp_vdev = NULL;
> +	int i, ret = 0;
> 
> -	return 0;
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
> +	memset(dev_name, 0, sizeof(dev_name));
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
> +	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
> +	if (!rawdev)
> +		return -ENODEV;
> +	ifpga_dev = ifpga_rawdev_get(rawdev);
> +	if (!ifpga_dev)
> +		return -ENODEV;
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
> +	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME),
> dev_name);
> +
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		tmp_vdev = ifpga_dev->vdev_name[i];
> +		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
> +			free(tmp_vdev);
> +			ifpga_dev->vdev_name[i] = NULL;
> +			break;
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static struct rte_vdev_driver ifpga_cfg_driver = { diff --git
> a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
> index 857b734..4c19119 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.h
> +++ b/drivers/raw/ifpga/ifpga_rawdev.h
> @@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
> 
>  #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
>  #define IFPGA_RAWDEV_NUM 32
> +#define IFPGA_MAX_VDEV 4
>  #define IFPGA_MAX_IRQ 12
> 
>  struct ifpga_rawdev {
> @@ -64,6 +65,13 @@ struct ifpga_rawdev {
>  	void *intr_handle[IFPGA_MAX_IRQ];
>  	/* enable monitor thread poll device's sensors or not */
>  	int poll_enabled;
> +	/* name of virtual devices created on raw device */
> +	char *vdev_name[IFPGA_MAX_VDEV];
> +};
> +
> +struct ifpga_vdev_args {
> +	char bdf[PCI_PRI_STR_SIZE];
> +	int port;
>  };
> 
>  struct ifpga_rawdev *
> --

It looks good for me, you can add:
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-05-27  8:33         ` [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
  2022-06-06  6:46           ` Zhang, Tianfei
@ 2022-06-07  6:02           ` Xu, Rosen
  1 sibling, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-06-07  6:02 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 16:34
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed
> 
> Virtual devices created on ifpga raw device will not be removed when ifpga
> device has closed. To avoid resource leak problem, this patch introduces an
> ifpga virtual device remove function, virtual devices will be destroyed after
> the ifpga raw device closed.
> 
> Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> ---
> v2: update commit log with Tianfei's comment
> ---
> v3: replace constant with PCI_PRI_STR_SIZE per Rosen's comment
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 166
> ++++++++++++++++++++++++++++++---------
>  drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
>  2 files changed, 138 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 6d4117c..fe3fc43 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -134,6 +134,8 @@ struct ifpga_rawdev *
>  	for (i = 0; i < IFPGA_MAX_IRQ; i++)
>  		dev->intr_handle[i] = NULL;
>  	dev->poll_enabled = 0;
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++)
> +		dev->vdev_name[i] = NULL;
> 
>  	return dev;
>  }
> @@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(  static int
> ifpga_rawdev_close(struct rte_rawdev *dev)  {
> +	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	char *vdev_name = NULL;
> +	int i = 0;
> 
>  	if (dev) {
> -		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
> +		ifpga_rdev = ifpga_rawdev_get(dev);
> +		if (ifpga_rdev) {
> +			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +				vdev_name = ifpga_rdev->vdev_name[i];
> +				if (vdev_name)
> +					rte_vdev_uninit(vdev_name);
> +			}
> +			ifpga_monitor_stop_func(ifpga_rdev);
> +			ifpga_rdev->rawdev = NULL;
> +		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
>  			opae_adapter_destroy(adapter);
> @@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		return -EINVAL;
>  	}
>  	dev = ifpga_rawdev_get(rawdev);
> -	if (dev)
> -		dev->rawdev = NULL;
> 
>  	adapter = ifpga_rawdev_get_priv(rawdev);
>  	if (!adapter)
> @@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const
> char *key __rte_unused,
> 
>  	return 0;
>  }
> +
>  static int
> -ifpga_cfg_probe(struct rte_vdev_device *dev)
> +ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
> +	struct ifpga_vdev_args *args)
>  {
> -	struct rte_devargs *devargs;
> -	struct rte_kvargs *kvlist = NULL;
> -	struct rte_rawdev *rawdev = NULL;
> -	struct ifpga_rawdev *ifpga_dev;
> -	int port;
> +	struct rte_kvargs *kvlist;
>  	char *name = NULL;
> -	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> -	int ret = -1;
> +	int port = 0;
> +	int ret = -EINVAL;
> 
> -	devargs = dev->device.devargs;
> +	if (!devargs || !args)
> +		return ret;
> 
>  	kvlist = rte_kvargs_parse(devargs->args, valid_args);
>  	if (!kvlist) {
> -		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing
> param");
> -		goto end;
> +		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
> +		return ret;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
>  		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
> -				       &ifpga_rawdev_get_string_arg,
> -				       &name) < 0) {
> +			&ifpga_rawdev_get_string_arg, &name) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
> -				     IFPGA_ARG_NAME);
> +				IFPGA_ARG_NAME);
>  			goto end;
> +		} else {
> +			strlcpy(args->bdf, name, sizeof(args->bdf));
> +			rte_free(name);
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga
> bus",
> -			  IFPGA_ARG_NAME);
> +			IFPGA_ARG_NAME);
>  		goto end;
>  	}
> 
>  	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
> -		if (rte_kvargs_process(kvlist,
> -			IFPGA_ARG_PORT,
> -			&rte_ifpga_get_integer32_arg,
> -			&port) < 0) {
> +		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
> +			&rte_ifpga_get_integer32_arg, &port) < 0) {
>  			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
>  				IFPGA_ARG_PORT);
>  			goto end;
> +		} else {
> +			args->port = port;
>  		}
>  	} else {
>  		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga
> bus",
> -			  IFPGA_ARG_PORT);
> +			IFPGA_ARG_PORT);
>  		goto end;
>  	}
> 
> +	ret = 0;
> +
> +end:
> +	if (kvlist)
> +		rte_kvargs_free(kvlist);
> +
> +	return ret;
> +}
> +
> +static int
> +ifpga_cfg_probe(struct rte_vdev_device *vdev) {
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	int i, n, ret = 0;
> +
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
>  	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> name);
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
>  	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
>  	if (!rawdev)
> -		goto end;
> +		return -ENODEV;
>  	ifpga_dev = ifpga_rawdev_get(rawdev);
>  	if (!ifpga_dev)
> -		goto end;
> +		return -ENODEV;
> 
> -	memset(dev_name, 0, sizeof(dev_name));
> -	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> -	port, name);
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		if (ifpga_dev->vdev_name[i] == NULL) {
> +			n = strlen(vdev_name) + 1;
> +			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
> +			if (ifpga_dev->vdev_name[i] == NULL)
> +				return -ENOMEM;
> +			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
> +			break;
> +		}
> +	}
> 
> +	if (i >= IFPGA_MAX_VDEV) {
> +		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual
> device!");
> +		return -ENOENT;
> +	}
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
>  	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
> -			dev_name, devargs->args);
> -end:
> -	rte_kvargs_free(kvlist);
> -	free(name);
> +			dev_name, vdev->device.devargs->args);
> +	if (ret) {
> +		rte_free(ifpga_dev->vdev_name[i]);
> +		ifpga_dev->vdev_name[i] = NULL;
> +	}
> 
>  	return ret;
>  }
> @@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const
> char *key __rte_unused,  static int  ifpga_cfg_remove(struct
> rte_vdev_device *vdev)  {
> -	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
> -		vdev);
> +	struct rte_rawdev *rawdev = NULL;
> +	struct ifpga_rawdev *ifpga_dev;
> +	struct ifpga_vdev_args args;
> +	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
> +	const char *vdev_name = NULL;
> +	char *tmp_vdev = NULL;
> +	int i, ret = 0;
> 
> -	return 0;
> +	vdev_name = rte_vdev_device_name(vdev);
> +	if (!vdev_name)
> +		return -EINVAL;
> +
> +	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s",
> vdev_name);
> +
> +	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
> +	if (ret)
> +		return ret;
> +
> +	memset(dev_name, 0, sizeof(dev_name));
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s",
> args.bdf);
> +	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
> +	if (!rawdev)
> +		return -ENODEV;
> +	ifpga_dev = ifpga_rawdev_get(rawdev);
> +	if (!ifpga_dev)
> +		return -ENODEV;
> +
> +	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
> +		args.port, args.bdf);
> +	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME),
> dev_name);
> +
> +	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
> +		tmp_vdev = ifpga_dev->vdev_name[i];
> +		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
> +			free(tmp_vdev);
> +			ifpga_dev->vdev_name[i] = NULL;
> +			break;
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static struct rte_vdev_driver ifpga_cfg_driver = { diff --git
> a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
> index 857b734..4c19119 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.h
> +++ b/drivers/raw/ifpga/ifpga_rawdev.h
> @@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
> 
>  #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
>  #define IFPGA_RAWDEV_NUM 32
> +#define IFPGA_MAX_VDEV 4
>  #define IFPGA_MAX_IRQ 12
> 
>  struct ifpga_rawdev {
> @@ -64,6 +65,13 @@ struct ifpga_rawdev {
>  	void *intr_handle[IFPGA_MAX_IRQ];
>  	/* enable monitor thread poll device's sensors or not */
>  	int poll_enabled;
> +	/* name of virtual devices created on raw device */
> +	char *vdev_name[IFPGA_MAX_VDEV];
> +};
> +
> +struct ifpga_vdev_args {
> +	char bdf[PCI_PRI_STR_SIZE];
> +	int port;
>  };
> 
>  struct ifpga_rawdev *
> --
> 1.8.3.1

Reviewed-by: Rosen Xu <rosen.xu@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-05-27  8:33         ` [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-06-07  6:03           ` Xu, Rosen
  0 siblings, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-06-07  6:03 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 16:34
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function
> 
> There is an API rte_pmd_ifpga_cleanup provided by ifpga driver to free the
> software resource used by ifpga card. The function call of
> rte_pmd_ifpga_cleanup is list below.
> rte_pmd_ifpga_cleanup()
>   ifpga_rawdev_cleanup()
>      rte_rawdev_pmd_release()
>        rte_rawdev_close()
>          ifpga_rawdev_close()
> 
> The interrupts are unregistered in ifpga_rawdev_destroy instead of
> ifpga_rawdev_close function, so rte_pmd_ifpga_cleanup cannot free
> interrupt resource as expected.
> 
> To fix such issue, interrupt unregistration is moved from
> ifpga_rawdev_destroy to ifpga_rawdev_close function. The change of
> function call of ifpga_rawdev_destroy is as below.
> ifpga_rawdev_destroy()
>   ifpga_unregister_msix_irq()  // removed
>   rte_rawdev_pmd_release()
>     rte_rawdev_close()
>       ifpga_rawdev_close()
> 
> Fixes: e0a1aafe2af9 ("raw/ifpga: introduce IRQ functions")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
> ---
> v2: update commit log with Tianfei's comment
> ---
> v3: update commit log with more explanations about the function call
> ---
>  drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index fe3fc43..94df56c 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(  static int
> ifpga_pci_find_next_ext_capability(unsigned int fd,
>  					      int start, uint32_t cap);
>  static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
> +static void fme_interrupt_handler(void *param);
> 
>  struct ifpga_rawdev *
>  ifpga_rawdev_get(const struct rte_rawdev *rawdev) @@ -740,8 +741,9 @@
> static int set_surprise_link_check_aer(  {
>  	struct ifpga_rawdev *ifpga_rdev = NULL;
>  	struct opae_adapter *adapter;
> +	struct opae_manager *mgr;
>  	char *vdev_name = NULL;
> -	int i = 0;
> +	int i, ret = 0;
> 
>  	if (dev) {
>  		ifpga_rdev = ifpga_rawdev_get(dev);
> @@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
>  		}
>  		adapter = ifpga_rawdev_get_priv(dev);
>  		if (adapter) {
> +			mgr = opae_adapter_get_mgr(adapter);
> +			if (ifpga_rdev && mgr) {
> +				if (ifpga_unregister_msix_irq(ifpga_rdev,
> +					IFPGA_FME_IRQ, 0,
> +					fme_interrupt_handler, mgr) < 0)
> +					ret = -EINVAL;
> +			}
>  			opae_adapter_destroy(adapter);
>  			opae_adapter_data_free(adapter->data);
>  		}
>  	}
> 
> -	return dev ? 0:1;
> +	return ret;
>  }
> 
>  static int
> @@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	int ret;
>  	struct rte_rawdev *rawdev;
>  	char name[RTE_RAWDEV_NAME_MAX_LEN];
> -	struct opae_adapter *adapter;
> -	struct opae_manager *mgr;
> -	struct ifpga_rawdev *dev;
> 
>  	if (!pci_dev) {
>  		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
> @@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)",
> name);
>  		return -EINVAL;
>  	}
> -	dev = ifpga_rawdev_get(rawdev);
> -
> -	adapter = ifpga_rawdev_get_priv(rawdev);
> -	if (!adapter)
> -		return -ENODEV;
> -
> -	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> -		return -ENODEV;
> -
> -	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
> -				fme_interrupt_handler, mgr) < 0)
> -		return -EINVAL;
> 
>  	/* rte_rawdev_close is called by pmd_release */
>  	ret = rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1

Reviewed-by: Rosen Xu <rosen.xu@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [PATCH v4 4/5] raw/ifpga: support ofs card probe
  2022-05-27  8:33         ` [PATCH v4 4/5] raw/ifpga: support ofs card probe Wei Huang
@ 2022-06-07  6:04           ` Xu, Rosen
  0 siblings, 0 replies; 47+ messages in thread
From: Xu, Rosen @ 2022-06-07  6:04 UTC (permalink / raw)
  To: Huang, Wei, dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, Zhang, Tianfei, Zhang, Qi Z

Hi,

> -----Original Message-----
> From: Huang, Wei <wei.huang@intel.com>
> Sent: Friday, May 27, 2022 16:34
> To: dev@dpdk.org; thomas@monjalon.net; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: stable@dpdk.org; Xu, Rosen <rosen.xu@intel.com>; Zhang, Tianfei
> <tianfei.zhang@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Huang, Wei
> <wei.huang@intel.com>
> Subject: [PATCH v4 4/5] raw/ifpga: support ofs card probe
> 
> PAC N6000 is the first OFS platform, its device id is added to ifpga device
> support list.
> 
> Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
> Feature List) starts from BAR0 by default, port DFL location is indicated in
> PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port
> DFL location can be defined individually in PCIe VSEC (Vendor Specific
> Extended Capabilities). In this patch, DFL definition is searched in VSEC, the
> legacy DFL is used only when DFL VSEC is not present.
> 
> In original DFL enumeration process, AFU is expected to locate in port DFL,
> but this is not the case in OFS implementation. In this patch, enumeration can
> search AFU in any PF/VF which has no FME and port.
> 
> Signed-off-by: Wei Huang <wei.huang@intel.com>
> Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
> ---
> v2: fix build error in UB2004-32
> ---
> v3: update commit log with Tianfei's comment, treat 7 as special BAR index
> ---
> v4: fix typo and coding style issue
> ---
>  drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
>  drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
>  drivers/raw/ifpga/base/ifpga_enumerate.c   | 680
> ++++++++++++++++++++++-------
>  drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
>  drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
>  drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
>  drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
>  drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
>  drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
>  9 files changed, 591 insertions(+), 192 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_api.c
> b/drivers/raw/ifpga/base/ifpga_api.c
> index 4610ef1..f19cc26 100644
> --- a/drivers/raw/ifpga/base/ifpga_api.c
> +++ b/drivers/raw/ifpga/base/ifpga_api.c
> @@ -13,15 +13,22 @@
>  static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
>  			      struct uuid *uuid)
>  {
> -	struct opae_bridge *br = acc->br;
> -	struct ifpga_port_hw *port;
> +	struct ifpga_afu_info *afu_info = acc->data;
> +	struct opae_reg_region *region;
> +	u64 val = 0;
> 
> -	if (!br || !br->data)
> -		return -EINVAL;
> +	if (!afu_info)
> +		return -ENODEV;
> 
> -	port = br->data;
> +	region = &afu_info->region[0];
> +	if (uuid) {
> +		val = readq(region->addr + sizeof(struct feature_header));
> +		opae_memcpy(uuid->b, &val, sizeof(u64));
> +		val = readq(region->addr + sizeof(struct feature_header) + 8);
> +		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
> +	}
> 
> -	return fpga_get_afu_uuid(port, uuid);
> +	return 0;
>  }
> 
>  static int ifpga_acc_set_irq(struct opae_accelerator *acc, @@ -32,6 +39,9
> @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
>  	struct ifpga_port_hw *port;
>  	struct fpga_uafu_irq_set irq_set;
> 
> +	if (!afu_info)
> +		return -ENODEV;
> +
>  	if (!br || !br->data)
>  		return -EINVAL;
> 
> @@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct
> opae_accelerator *acc,
>  	struct ifpga_afu_info *afu_info = acc->data;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (info->index >= afu_info->num_regions)
>  		return -EINVAL;
> @@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc,
> unsigned int region_idx,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> @@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator
> *acc,
>  	struct opae_reg_region *region;
> 
>  	if (!afu_info)
> -		return -EINVAL;
> +		return -ENODEV;
> 
>  	if (offset + byte <= offset)
>  		return -EINVAL;
> diff --git a/drivers/raw/ifpga/base/ifpga_defines.h
> b/drivers/raw/ifpga/base/ifpga_defines.h
> index 8f62033..9a280eb 100644
> --- a/drivers/raw/ifpga/base/ifpga_defines.h
> +++ b/drivers/raw/ifpga/base/ifpga_defines.h
> @@ -73,6 +73,7 @@
>  enum fpga_id_type {
>  	FME_ID,
>  	PORT_ID,
> +	AFU_ID,
>  	FPGA_ID_MAX,
>  };
> 
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c
> b/drivers/raw/ifpga/base/ifpga_enumerate.c
> index 48b8af4..7a5d264 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.c
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
> @@ -2,6 +2,10 @@
>   * Copyright(c) 2010-2018 Intel Corporation
>   */
> 
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <unistd.h>
> +
>  #include "opae_hw_api.h"
>  #include "ifpga_api.h"
> 
> @@ -9,6 +13,19 @@
>  #include "ifpga_enumerate.h"
>  #include "ifpga_feature_dev.h"
> 
> +struct dfl_fpga_enum_dfl {
> +	u64 start;
> +	u64 len;
> +	void *addr;
> +	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
> +};
> +
> +TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl); struct
> +dfl_fpga_enum_info {
> +	struct ifpga_hw *hw;
> +	struct dfl_fpga_enum_dfls dfls;
> +};
> +
>  struct build_feature_devs_info {
>  	struct opae_adapter_data_pci *pci_data;
> 
> @@ -21,7 +38,6 @@ struct build_feature_devs_info {
>  	void *ioaddr;
>  	void *ioend;
>  	uint64_t phys_addr;
> -	int current_bar;
> 
>  	void *pfme_hdr;
> 
> @@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
>  			unsigned int size, unsigned int vec_start,
>  			unsigned int vec_cnt)
>  {
> -	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
> -			vec_cnt);
> +	if (binfo->current_type != AFU_ID)
> +		return build_info_add_sub_feature(binfo, start, fid, size,
> +			vec_start, vec_cnt);
> +	return 0;
>  }
> 
>  /*
> @@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
>   */
>  static bool feature_is_UAFU(struct build_feature_devs_info *binfo)  {
> -	if (binfo->current_type != PORT_ID)
> -		return false;
> +	if ((binfo->current_type == PORT_ID) ||
> +		(binfo->current_type == AFU_ID))
> +		return true;
> 
> -	return true;
> +	return false;
>  }
> 
> -static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
> +static int parse_feature_uafu(struct build_feature_devs_info *binfo,
>  				   struct feature_header *hdr)
>  {
>  	u64 id = PORT_FEATURE_ID_UAFU;
> @@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	int ret;
>  	int size;
> 
> +	if (binfo->acc_info) {
> +		dev_info(binfo, "Sub AFU found @ %p.\n", start);
> +		return 0;
> +	}
> +
>  	capability.csr = readq(&port_hdr->capability);
> 
> -	size = capability.mmio_size << 10;
> +	if (binfo->current_type == AFU_ID) {
> +		size = AFU_REGION_SIZE;
> +	} else {
> +		capability.csr = readq(&port_hdr->capability);
> +		size = capability.mmio_size << 10;
> +	}
> 
>  	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
>  	if (ret)
> @@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct
> build_feature_devs_info *binfo,
>  	info->region[0].phys_addr = binfo->phys_addr +
>  			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
>  	info->region[0].len = size;
> -	info->num_regions = 1;
> +	info->num_regions = AFU_MAX_REGION;
> 
>  	binfo->acc_info = info;
> 
>  	return ret;
>  }
> 
> -static int parse_feature_afus(struct build_feature_devs_info *binfo,
> -			      struct feature_header *hdr)
> -{
> -	int ret;
> -	struct feature_afu_header *afu_hdr, header;
> -	u8 __iomem *start;
> -	u8 __iomem *end = binfo->ioend;
> -
> -	start = (u8 __iomem *)hdr;
> -	for (; start < end; start += header.next_afu) {
> -		if ((unsigned int)(end - start) <
> -			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> -			return -EINVAL;
> -
> -		hdr = (struct feature_header *)start;
> -		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> -		header.csr = readq(&afu_hdr->csr);
> -
> -		if (feature_is_UAFU(binfo)) {
> -			ret = parse_feature_port_uafu(binfo, hdr);
> -			if (ret)
> -				return ret;
> -		}
> -
> -		if (!header.next_afu)
> -			break;
> -	}
> -
> -	return 0;
> -}
> -
>  /* create and register proper private data */  static int
> build_info_commit_dev(struct build_feature_devs_info *binfo)  { @@ -
> 235,13 +233,9 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	struct ifpga_fme_hw *fme;
>  	struct ifpga_feature *feature;
> 
> -	if (!binfo->fiu)
> -		return 0;
> -
>  	if (binfo->current_type == PORT_ID) {
> -		/* return error if no valid acc info data structure */
> -		if (!info)
> -			return -EFAULT;
> +		if (!binfo->fiu)
> +			return 0;
> 
>  		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
>  				       binfo->fiu);
> @@ -254,7 +248,7 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  		port = &hw->port[binfo->current_port_id];
>  		feature = get_feature_by_id(&port->feature_list,
>  				PORT_FEATURE_ID_UINT);
> -		if (feature)
> +		if (feature && info)
>  			info->num_irqs = feature->vec_cnt;
> 
>  		acc = opae_accelerator_alloc(hw->adapter->name,
> @@ -264,17 +258,21 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  			return -ENOMEM;
>  		}
> 
> +		acc->adapter = hw->adapter;
>  		acc->br = br;
>  		if (hw->adapter->mgr)
>  			acc->mgr = hw->adapter->mgr;
>  		acc->index = br->id;
> 
>  		fme = &hw->fme;
> -		fme->nums_acc_region = info->num_regions;
> +		fme->nums_acc_region = info ? info->num_regions : 0;
> 
>  		opae_adapter_add_acc(hw->adapter, acc);
> 
>  	} else if (binfo->current_type == FME_ID) {
> +		if (!binfo->fiu)
> +			return 0;
> +
>  		mgr = opae_manager_alloc(hw->adapter->name,
> &ifpga_mgr_ops,
>  				&ifpga_mgr_network_ops, binfo->fiu);
>  		if (!mgr)
> @@ -282,6 +280,22 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
> 
>  		mgr->adapter = hw->adapter;
>  		hw->adapter->mgr = mgr;
> +	} else if (binfo->current_type == AFU_ID) {
> +		if (!info)
> +			return -EFAULT;
> +
> +		info->num_irqs = 0;
> +		acc = opae_accelerator_alloc(hw->adapter->name,
> +					&ifpga_acc_ops, info);
> +		if (!acc)
> +			return -ENOMEM;
> +
> +		acc->adapter = hw->adapter;
> +		acc->br = NULL;
> +		acc->mgr = NULL;
> +		acc->index = hw->num_afus++;
> +
> +		opae_adapter_add_acc(hw->adapter, acc);
>  	}
> 
>  	binfo->fiu = NULL;
> @@ -295,11 +309,15 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)  {
>  	int ret;
> 
> +	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
> +		return 0;
> +
>  	ret = build_info_commit_dev(binfo);
>  	if (ret)
>  		return ret;
> 
>  	binfo->current_type = type;
> +	binfo->acc_info = NULL;
> 
>  	if (type == FME_ID) {
>  		binfo->fiu = &binfo->hw->fme;
> @@ -311,6 +329,41 @@ static int build_info_commit_dev(struct
> build_feature_devs_info *binfo)
>  	return 0;
>  }
> 
> +static int parse_feature_afus(struct build_feature_devs_info *binfo,
> +			      struct feature_header *hdr)
> +{
> +	int ret;
> +	struct feature_afu_header *afu_hdr, header;
> +	u8 __iomem *start;
> +	u8 __iomem *end = binfo->ioend;
> +
> +	ret = build_info_create_dev(binfo, AFU_ID, 0);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 __iomem *)hdr;
> +	for (; start < end; start += header.next_afu) {
> +		if ((unsigned int)(end - start) <
> +			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
> +			return -EINVAL;
> +
> +		hdr = (struct feature_header *)start;
> +		afu_hdr = (struct feature_afu_header *)(hdr + 1);
> +		header.csr = readq(&afu_hdr->csr);
> +
> +		if (feature_is_UAFU(binfo)) {
> +			ret = parse_feature_uafu(binfo, hdr);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (!header.next_afu)
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
>  static int parse_feature_fme(struct build_feature_devs_info *binfo,
>  			     struct feature_header *start)
>  {
> @@ -405,7 +458,7 @@ static int parse_feature_fiu(struct
> build_feature_devs_info *binfo,
>  			if (ret)
>  				return ret;
>  		} else {
> -			dev_info(binfo, "No AFUs detected on Port\n");
> +			dev_info(binfo, "No AFU detected on Port\n");
>  		}
> 
>  		break;
> @@ -426,7 +479,7 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
> 
>  	id = feature_id(start);
> 
> -	if (id == PORT_FEATURE_ID_UINT) {
> +	if ((binfo->current_type == PORT_ID) && (id ==
> PORT_FEATURE_ID_UINT))
> +{
>  		struct feature_port_uint *port_uint = start;
>  		struct feature_port_uint_cap uint_cap;
> 
> @@ -437,7 +490,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  		} else {
>  			dev_debug(binfo, "UAFU doesn't support
> interrupt\n");
>  		}
> -	} else if (id == PORT_FEATURE_ID_ERROR) {
> +	} else if ((binfo->current_type == PORT_ID) &&
> +			(id == PORT_FEATURE_ID_ERROR)) {
>  		struct feature_port_error *port_err = start;
>  		struct feature_port_err_capability port_err_cap;
> 
> @@ -449,7 +503,8 @@ static void parse_feature_irqs(struct
> build_feature_devs_info *binfo,
>  			dev_debug(&binfo, "Port error doesn't support
> interrupt\n");
>  		}
> 
> -	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
> +	} else if ((binfo->current_type == FME_ID) &&
> +			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
>  		struct feature_fme_err *fme_err = start;
>  		struct feature_fme_error_capability fme_err_cap;
> 
> @@ -497,9 +552,15 @@ static int parse_feature_private(struct
> build_feature_devs_info *binfo,
>  		return parse_feature_fme_private(binfo, hdr);
>  	case PORT_ID:
>  		return parse_feature_port_private(binfo, hdr);
> +	case AFU_ID:
> +		dev_err(binfo, "private feature %x belonging to AFU "
> +			"is not supported yet.\n", header.id);
> +		break;
>  	default:
> -		dev_err(binfo, "private feature %x belonging to AFU %d
> (unknown_type) is not supported yet.\n",
> +		dev_err(binfo, "private feature %x belonging to TYPE %d "
> +			"(unknown_type) is not supported yet.\n",
>  			header.id, binfo->current_type);
> +		break;
>  	}
>  	return 0;
>  }
> @@ -530,32 +591,57 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return ret;
>  }
> 
> -static int
> -parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem
> *start)
> +static int build_info_prepare(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
>  {
> +	if (!binfo || !dfl)
> +		return -EINVAL;
> +
> +	binfo->ioaddr = dfl->addr;
> +	binfo->ioend = (u8 *)dfl->addr + dfl->len;
> +	binfo->phys_addr = dfl->start;
> +
> +	return 0;
> +}
> +
> +static int parse_feature_list(struct build_feature_devs_info *binfo,
> +	struct dfl_fpga_enum_dfl *dfl)
> +{
> +	u8 *start, *end;
>  	struct feature_header *hdr, header;
> -	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
>  	int ret = 0;
> 
> +	ret = build_info_prepare(binfo, dfl);
> +	if (ret)
> +		return ret;
> +
> +	start = (u8 *)binfo->ioaddr;
> +	end = (u8 *)binfo->ioend;
> +
> +	/* walk through the device feature list via DFH's next DFH pointer. */
>  	for (; start < end; start += header.next_header_offset) {
>  		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
> -			dev_err(binfo, "The region is too small to contain a
> feature.\n");
> -			ret =  -EINVAL;
> +			dev_err(binfo, "The region is too small to "
> +				"contain a feature.\n");
> +			ret = -EINVAL;
>  			break;
>  		}
> 
>  		hdr = (struct feature_header *)start;
> -		header.csr = readq(hdr);
> +		header.csr = opae_readq(hdr);
> 
> -		dev_debug(binfo, "%s: address=0x%p, val=0x%llx,
> header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x,
> header.type=0x%x\n",
> -			__func__, hdr, (unsigned long long)header.csr,
> -			header.id, header.next_header_offset,
> -			header.end_of_list, header.type);
> +		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
> +			"header.id=0x%x, header.next_offset=0x%x, "
> +			"header.eol=0x%x, header.type=0x%x\n",
> +			__func__, hdr, header.csr, header.id,
> +			header.next_header_offset, header.end_of_list,
> +			header.type);
> 
>  		ret = parse_feature(binfo, hdr);
>  		if (ret)
>  			return ret;
> 
> +		/* stop parsing if EOL(End of List) is set or offset is 0 */
>  		if (header.end_of_list || !header.next_header_offset)
>  			break;
>  	}
> @@ -563,82 +649,9 @@ static int parse_feature(struct
> build_feature_devs_info *binfo,
>  	return build_info_commit_dev(binfo);
>  }
> 
> -/* switch the memory mapping to BAR# @bar */ -static int
> parse_switch_to(struct build_feature_devs_info *binfo, int bar) -{
> -	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
> -
> -	if (!pci_data->region[bar].addr)
> -		return -ENOMEM;
> -
> -	binfo->ioaddr = pci_data->region[bar].addr;
> -	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data-
> >region[bar].len;
> -	binfo->phys_addr = pci_data->region[bar].phys_addr;
> -	binfo->current_bar = bar;
> -
> -	return 0;
> -}
> -
> -static int parse_ports_from_fme(struct build_feature_devs_info *binfo) -{
> -	struct feature_fme_header *fme_hdr;
> -	struct feature_fme_port port;
> -	int i = 0, ret = 0;
> -
> -	if (!binfo->pfme_hdr) {
> -		dev_info(binfo,  "VF is detected.\n");
> -		return ret;
> -	}
> -
> -	fme_hdr = binfo->pfme_hdr;
> -
> -	do {
> -		port.csr = readq(&fme_hdr->port[i]);
> -		if (!port.port_implemented)
> -			break;
> -
> -		/* skip port which only could be accessed via VF */
> -		if (port.afu_access_control == FME_AFU_ACCESS_VF)
> -			continue;
> -
> -		ret = parse_switch_to(binfo, port.port_bar);
> -		if (ret)
> -			break;
> -
> -		ret = parse_feature_list(binfo,
> -					 (u8 __iomem *)binfo->ioaddr +
> -					  port.port_offset);
> -		if (ret)
> -			break;
> -	} while (++i < MAX_FPGA_PORT_NUM);
> -
> -	return ret;
> -}
> -
> -static struct build_feature_devs_info * -build_info_alloc_and_init(struct
> ifpga_hw *hw) -{
> -	struct build_feature_devs_info *binfo;
> -
> -	binfo = zmalloc(sizeof(*binfo));
> -	if (!binfo)
> -		return binfo;
> -
> -	binfo->hw = hw;
> -	binfo->pci_data = hw->pci_data;
> -
> -	/* fpga feature list starts from BAR 0 */
> -	if (parse_switch_to(binfo, 0)) {
> -		free(binfo);
> -		return NULL;
> -	}
> -
> -	return binfo;
> -}
> -
>  static void build_info_free(struct build_feature_devs_info *binfo)  {
> -	free(binfo);
> +	opae_free(binfo);
>  }
> 
>  static void ifpga_print_device_feature_list(struct ifpga_hw *hw) @@ -648,6
> +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
>  	struct ifpga_feature *feature;
>  	int i;
> 
> +	if (fme->state == IFPGA_FME_UNUSED) {
> +		dev_info(hw, "FME is not present\n");
> +		return;
> +	}
> +
>  	dev_info(hw, "found fme_device, is in PF: %s\n",
>  		 is_ifpga_hw_pf(hw) ? "yes" : "no");
> 
> @@ -685,40 +703,410 @@ static void ifpga_print_device_feature_list(struct
> ifpga_hw *hw)
>  	}
>  }
> 
> -int ifpga_bus_enumerate(struct ifpga_hw *hw)
> +static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct
> +ifpga_hw *hw)
>  {
> -	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_info *info;
> +
> +	info = opae_zmalloc(sizeof(*info));
> +	if (!info)
> +		return NULL;
> +
> +	info->hw = hw;
> +	TAILQ_INIT(&info->dfls);
> +
> +	return info;
> +}
> +
> +static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info) {
> +	struct dfl_fpga_enum_dfl *tmp, *dfl;
> +
> +	if (!info)
> +		return;
> +
> +	/* remove all device feature lists in the list. */
> +	for (dfl = TAILQ_FIRST(&info->dfls);
> +		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
> +		dfl = tmp) {
> +		TAILQ_REMOVE(&info->dfls, dfl, node);
> +		opae_free(dfl);
> +	}
> +
> +	opae_free(info);
> +}
> +
> +static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
> +	u64 start, u64 len, void *addr)
> +{
> +	struct dfl_fpga_enum_dfl *dfl;
> +
> +	dfl = opae_zmalloc(sizeof(*dfl));
> +	if (!dfl)
> +		return -ENOMEM;
> +
> +	dfl->start = start;
> +	dfl->len = len;
> +	dfl->addr = addr;
> +
> +	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
> +
> +	return 0;
> +}
> +
> +#define PCI_CFG_SPACE_SIZE	256
> +#define PCI_CFG_SPACE_EXP_SIZE	4096
> +#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
> +#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
> +
> +static int
> +pci_find_next_ecap(int fd, int start, u32 cap) {
> +	u32 header;
> +	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
> +	int pos = PCI_CFG_SPACE_SIZE;
>  	int ret;
> 
> -	binfo = build_info_alloc_and_init(hw);
> +	if (start > 0)
> +		pos = start;
> +
> +	ret = pread(fd, &header, sizeof(header), pos);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * If we have no capabilities, this is indicated by cap ID,
> +	 * cap version and next pointer all being 0.
> +	 */
> +	if (header == 0)
> +		return 0;
> +
> +	while (ttl-- > 0) {
> +		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
> +			return pos;
> +
> +		pos = PCI_EXT_CAP_NEXT(header);
> +		if (pos < PCI_CFG_SPACE_SIZE)
> +			break;
> +		ret = pread(fd, &header, sizeof(header), pos);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +#define PCI_EXT_CAP_ID_VNDR	0x0B
> +#define PCI_VNDR_HEADER		4
> +#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
> +#define PCI_VENDOR_ID_INTEL 0x8086
> +#define PCI_VSEC_ID_INTEL_DFLS 0x43
> +#define PCI_VNDR_DFLS_CNT 0x8
> +#define PCI_VNDR_DFLS_RES 0xc
> +#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0) #define
> +PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
> +
> +static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	char path[64];
> +	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
> +	int fd, ret, dfl_res_off, voff = 0;
> +	u64 start, len;
> +	void *addr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->adapter || !hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
> +			hw->adapter->name);
> +	if ((unsigned int)ret >= sizeof(path))
> +		return -EINVAL;
> +
> +	fd = open(path, O_RDWR);
> +	if (fd < 0)
> +		return -EIO;
> +
> +	while ((voff = pci_find_next_ecap(fd, voff,
> +		PCI_EXT_CAP_ID_VNDR))) {
> +		vndr_hdr = 0;
> +		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
> +			voff + PCI_VNDR_HEADER);
> +		if (ret < 0)
> +			return -EIO;
> +		if (PCI_VNDR_HEADER_ID(vndr_hdr) ==
> PCI_VSEC_ID_INTEL_DFLS &&
> +			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
> +			break;
> +	}
> +
> +	if (!voff) {
> +		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	dfl_cnt = 0;
> +	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff +
> PCI_VNDR_DFLS_CNT);
> +	if (ret < 0)
> +		return -EIO;
> +
> +	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
> +	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE)
> {
> +		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
> +		dfl_res = GENMASK(31, 0);
> +		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
> +		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
> +		if (bir >= PCI_MAX_RESOURCE) {
> +			dev_err(hw, "%s bad bir number %d\n",
> +				__func__, bir);
> +			return -EINVAL;
> +		}
> +
> +		len = pci_data->region[bir].len;
> +		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
> +		if (offset >= len) {
> +			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
> +				__func__, offset, len);
> +			return -EINVAL;
> +		}
> +
> +		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir,
> offset);
> +		len -= offset;
> +		start = pci_data->region[bir].phys_addr + offset;
> +		addr = pci_data->region[bir].addr + offset;
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	}
> +
> +	return 0;
> +}
> +
> +/* default method of finding dfls starting at offset 0 of bar 0 */
> +static int find_dfls_by_default(struct dfl_fpga_enum_info *info) {
> +	struct ifpga_hw *hw;
> +	struct opae_adapter_data_pci *pci_data;
> +	int port_num, bar, i, ret = 0;
> +	u64 start, len;
> +	void *addr;
> +	u32 offset;
> +	struct feature_header hdr;
> +	struct feature_fme_capability cap;
> +	struct feature_fme_port port;
> +	struct feature_fme_header *fme_hdr;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +	hw = info->hw;
> +
> +	if (!hw->pci_data)
> +		return -EINVAL;
> +	pci_data = hw->pci_data;
> +
> +	/* start to find Device Feature List from Bar 0 */
> +	addr = pci_data->region[0].addr;
> +	if (!addr)
> +		return -ENOMEM;
> +
> +	/*
> +	 * PF device has FME and Ports/AFUs, and VF device only has one
> +	 * Port/AFU. Check them and add related "Device Feature List" info
> +	 * for the next step enumeration.
> +	 */
> +	hdr.csr = opae_readq(addr);
> +	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id ==
> FEATURE_FIU_ID_FME)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +
> +		/*
> +		 * find more Device Feature Lists (e.g. Ports) per information
> +		 * indicated by FME module.
> +		 */
> +		fme_hdr = (struct feature_fme_header *)addr;
> +		cap.csr = opae_readq(&fme_hdr->capability);
> +		port_num = (int)cap.num_ports;
> +
> +		dev_info(hw, "port_num = %d\n", port_num);
> +		if (port_num > MAX_FPGA_PORT_NUM)
> +			port_num = MAX_FPGA_PORT_NUM;
> +
> +		for (i = 0; i < port_num; i++) {
> +			port.csr = opae_readq(&fme_hdr->port[i]);
> +
> +			/* skip ports which are not implemented. */
> +			if (!port.port_implemented)
> +				continue;
> +
> +			/* skip port which only could be accessed via VF */
> +			if (port.afu_access_control == FME_AFU_ACCESS_VF)
> +				continue;
> +
> +			/*
> +			 * add Port's Device Feature List information for next
> +			 * step enumeration.
> +			 */
> +			bar = (int)port.port_bar;
> +			offset = port.port_offset;
> +			if (bar == FME_PORT_OFST_BAR_SKIP) {
> +				continue;
> +			} else if (bar >= PCI_MAX_RESOURCE) {
> +				dev_err(hw, "bad BAR %d for port %d\n", bar,
> i);
> +				ret = -EINVAL;
> +				break;
> +			}
> +			dev_info(hw, "BAR %d offset %u\n", bar, offset);
> +
> +			len = pci_data->region[bar].len;
> +			if (offset >= len) {
> +				dev_warn(hw, "bad port
> offset %u >= %pa\n",
> +					 offset, &len);
> +				continue;
> +			}
> +
> +			len -= offset;
> +			start = pci_data->region[bar].phys_addr + offset;
> +			addr = pci_data->region[bar].addr + offset;
> +			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +		}
> +	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
> +		(hdr.id == FEATURE_FIU_ID_PORT)) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else if (hdr.type == FEATURE_TYPE_AFU) {
> +		start = pci_data->region[0].phys_addr;
> +		len = pci_data->region[0].len;
> +		addr = pci_data->region[0].addr;
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
> +	} else {
> +		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
> +			 hdr.type, hdr.id);
> +		ret = -ENODEV;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info
> +*info) {
> +	struct build_feature_devs_info *binfo;
> +	struct dfl_fpga_enum_dfl *dfl;
> +	int ret = 0;
> +
> +	if (!info || !info->hw)
> +		return -EINVAL;
> +
> +	/* create and init build info for enumeration */
> +	binfo = opae_zmalloc(sizeof(*binfo));
>  	if (!binfo)
>  		return -ENOMEM;
> 
> -	ret = parse_feature_list(binfo, binfo->ioaddr);
> +	binfo->hw = info->hw;
> +	binfo->pci_data = info->hw->pci_data;
> +
> +	/*
> +	 * start enumeration for all feature devices based on Device Feature
> +	 * Lists.
> +	 */
> +	TAILQ_FOREACH(dfl, &info->dfls, node) {
> +		ret = parse_feature_list(binfo, dfl);
> +		if (ret)
> +			break;
> +	}
> +
> +	build_info_free(binfo);
> +
> +	return ret;
> +}
> +
> +int ifpga_bus_enumerate(struct ifpga_hw *hw) {
> +	struct dfl_fpga_enum_info *info;
> +	int ret;
> +
> +	/* allocate enumeration info */
> +	info = dfl_fpga_enum_info_alloc(hw);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	ret = find_dfls_by_vsec(info);
> +	if (ret < 0)
> +		ret = find_dfls_by_default(info);
> +
>  	if (ret)
>  		goto exit;
> 
> -	ret = parse_ports_from_fme(binfo);
> -	if (ret)
> +	/* start enumeration with prepared enumeration information */
> +	ret = dfl_fpga_feature_devs_enumerate(info);
> +	if (ret < 0) {
> +		dev_err(hw, "Enumeration failure\n");
>  		goto exit;
> +	}
> 
>  	ifpga_print_device_feature_list(hw);
> 
>  exit:
> -	build_info_free(binfo);
> +	dfl_fpga_enum_info_free(info);
> +
>  	return ret;
>  }
> 
> -int ifpga_bus_init(struct ifpga_hw *hw)
> +static void ifpga_print_acc_list(struct opae_adapter *adapter)
>  {
> +	struct opae_accelerator *acc;
> +	struct ifpga_afu_info *info;
> +	struct uuid guid;
> +	char buf[48];
>  	int i;
> +
> +	opae_adapter_for_each_acc(adapter, acc) {
> +		info = acc->data;
> +		if (!info)
> +			continue;
> +		acc->ops->get_uuid(acc, &guid);
> +		i = sprintf(buf, "%02x%02x%02x%02x-",
> +			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
> +		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
> +		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
> +			guid.b[5], guid.b[4], guid.b[3],
> +			guid.b[2], guid.b[1], guid.b[0]);
> +		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64",
> guid:%s\n",
> +			acc->name, acc->index, info->region[0].addr,
> +			info->region[0].len, buf);
> +	}
> +}
> +
> +int ifpga_bus_init(struct ifpga_hw *hw) {
> +	int i, ret = 0;
>  	struct ifpga_port_hw *port;
> 
> -	fme_hw_init(&hw->fme);
> +	ret = fme_hw_init(&hw->fme);
> +	if (ret)
> +		return ret;
> +
>  	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
>  		port = &hw->port[i];
>  		port_hw_init(port);
>  	}
> +	ifpga_print_acc_list(hw->adapter);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h
> b/drivers/raw/ifpga/base/ifpga_enumerate.h
> index 95ed594..e6b04f0 100644
> --- a/drivers/raw/ifpga/base/ifpga_enumerate.h
> +++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
> @@ -5,6 +5,8 @@
>  #ifndef _IFPGA_ENUMERATE_H_
>  #define _IFPGA_ENUMERATE_H_
> 
> +#define FME_PORT_OFST_BAR_SKIP  7
> +
>  int ifpga_bus_init(struct ifpga_hw *hw);  int ifpga_bus_uinit(struct ifpga_hw
> *hw);  int ifpga_bus_enumerate(struct ifpga_hw *hw); diff --git
> a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> index 0813513..dbecc7b 100644
> --- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
> +++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
> @@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
>  	if (fpga_wait_register_field(port_sftrst_ack, control,
>  				     &port_hdr->control, RST_POLL_TIMEOUT,
>  				     RST_POLL_INVL)) {
> -		dev_err(port, "timeout, fail to reset device\n");
> +		dev_err(port, "timeout, fail to reset FIM port\n");
>  		return -ETIMEDOUT;
>  	}
> 
> @@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list
> *list)
>  	struct ifpga_feature *feature;
> 
>  	TAILQ_FOREACH(feature, list, next) {
> -		if (feature->state != IFPGA_FEATURE_ATTACHED)
> +		if (feature->state != IFPGA_FEATURE_INITED)
>  			continue;
>  		if (feature->ops && feature->ops->uinit)
>  			feature->ops->uinit(feature);
> +		feature->state = IFPGA_FEATURE_ATTACHED;
>  	}
>  }
> 
> @@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
>  					ret = feature->ops->init(feature);
>  					if (ret)
>  						goto error;
> +					else
> +						feature->state =
> +
> 	IFPGA_FEATURE_INITED;
>  				}
>  			}
>  		}
> @@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
> 
>  int fme_hw_init(struct ifpga_fme_hw *fme)  {
> -	int ret;
> -
> -	if (fme->state != IFPGA_FME_IMPLEMENTED)
> -		return -ENODEV;
> -
> -	ret = feature_init(fme_feature_drvs, &fme->feature_list);
> -	if (ret)
> -		return ret;
> +	if (fme->state == IFPGA_FME_IMPLEMENTED)
> +		return feature_init(fme_feature_drvs, &fme->feature_list);
> 
>  	return 0;
>  }
> diff --git a/drivers/raw/ifpga/base/ifpga_hw.h
> b/drivers/raw/ifpga/base/ifpga_hw.h
> index ed5edc6..4d56deb 100644
> --- a/drivers/raw/ifpga/base/ifpga_hw.h
> +++ b/drivers/raw/ifpga/base/ifpga_hw.h
> @@ -15,6 +15,7 @@
>  enum ifpga_feature_state {
>  	IFPGA_FEATURE_UNUSED = 0,
>  	IFPGA_FEATURE_ATTACHED,
> +	IFPGA_FEATURE_INITED
>  };
> 
>  enum feature_type {
> @@ -134,6 +135,7 @@ struct ifpga_hw {
> 
>  	struct ifpga_fme_hw fme;
>  	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
> +	int num_afus;
>  };
> 
>  static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) diff --git
> a/drivers/raw/ifpga/base/opae_hw_api.c
> b/drivers/raw/ifpga/base/opae_hw_api.c
> index 11c9887..87256fc 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.c
> +++ b/drivers/raw/ifpga/base/opae_hw_api.c
> @@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct
> opae_accelerator *acc,  int opae_acc_set_irq(struct opae_accelerator *acc,
>  		     u32 start, u32 count, s32 evtfds[])  {
> -	if (!acc || !acc->data)
> +	if (!acc)
>  		return -EINVAL;
> 
>  	if (start + count <= start)
> diff --git a/drivers/raw/ifpga/base/opae_hw_api.h
> b/drivers/raw/ifpga/base/opae_hw_api.h
> index 7e04b56..fd40e09 100644
> --- a/drivers/raw/ifpga/base/opae_hw_api.h
> +++ b/drivers/raw/ifpga/base/opae_hw_api.h
> @@ -143,6 +143,7 @@ struct opae_accelerator {
>  	TAILQ_ENTRY(opae_accelerator) node;
>  	const char *name;
>  	int index;
> +	struct opae_adapter *adapter;
>  	struct opae_bridge *br;
>  	struct opae_manager *mgr;
>  	struct opae_accelerator_ops *ops;
> @@ -240,6 +241,7 @@ struct opae_adapter_data {
> 
>  struct opae_reg_region {
>  	u64 phys_addr;
> +#define AFU_REGION_SIZE  0x8000
>  	u64 len;
>  	u8 *addr;
>  };
> diff --git a/drivers/raw/ifpga/ifpga_rawdev.c
> b/drivers/raw/ifpga/ifpga_rawdev.c
> index 94df56c..ceb18ae 100644
> --- a/drivers/raw/ifpga/ifpga_rawdev.c
> +++ b/drivers/raw/ifpga/ifpga_rawdev.c
> @@ -47,11 +47,13 @@
>  #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
>  #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
>  #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
> +#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
>  /* VF Device */
>  #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
>  #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
>  #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
>  #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
> +#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
>  #define RTE_MAX_RAW_DEVICE           10
> 
>  static const struct rte_pci_id pci_ifpga_map[] = { @@ -63,6 +65,8 @@
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_DSC_1_X) },
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N3000),},
>  	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N3000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_PAC_N6000),},
> +	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL,
> PCIE_DEVICE_ID_VF_PAC_N6000),},
>  	{ .vendor_id = 0, /* sentinel */ },
>  };
> 
> @@ -110,6 +114,7 @@ struct ifpga_rawdev *
> 
>  	return IFPGA_RAWDEV_NUM;
>  }
> +
>  static struct ifpga_rawdev *
>  ifpga_rawdev_allocate(struct rte_rawdev *rawdev)  { @@ -365,7 +370,7
> @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  		return -ENODEV;
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr)
> +	if (!mgr || !mgr->sensor_list)
>  		return -ENODEV;
> 
>  	opae_mgr_for_each_sensor(mgr, sensor) { @@ -377,7 +382,7 @@
> static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
>  			goto fail;
> 
>  		if (value == 0xdeadbeef) {
> -			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s
> value %x\n",
> +			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d
> sensor %s value %x\n",
>  					raw_dev->dev_id, sensor->name,
> value);
>  			continue;
>  		}
> @@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(  {
>  	struct opae_adapter *adapter;
>  	struct opae_manager *mgr;
> -	struct opae_board_info *info;
> +	struct opae_board_info *info = NULL;
>  	struct rte_afu_pr_conf *afu_pr_conf;
>  	int ret;
>  	struct uuid uuid;
> @@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
>  	}
> 
>  	mgr = opae_adapter_get_mgr(adapter);
> -	if (!mgr) {
> -		IFPGA_RAWDEV_PMD_ERR("opae_manager of
> opae_adapter is NULL");
> -		return -1;
> -	}
> -
> -	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> -		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info
> fail!");
> -		return -1;
> +	if (mgr) {
> +		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
> +			IFPGA_RAWDEV_PMD_ERR("ifpga manager
> get_board_info fail!");
> +			return -1;
> +		}
>  	}
> 
> -	if (info->lightweight) {
> +	if (info && info->lightweight) {
>  		/* set uuid to all 0, when fpga is lightweight image */
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0,
> sizeof(u64));
>  		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0,
> sizeof(u64)); @@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
>  			__func__,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
>  			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
> -		}
> +	}
>  	return 0;
>  }
> 
> @@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
>  	if (ret) {
>  		ret = -ENOMEM;
> -		goto free_adapter_data;
> +		goto cleanup;
>  	}
> 
>  	rawdev->dev_ops = &ifpga_rawdev_ops;
> @@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct
> opae_manager *mgr)
>  	/* must enumerate the adapter before use it */
>  	ret = opae_adapter_enumerate(adapter);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	/* get opae_manager to rawdev */
>  	mgr = opae_adapter_get_mgr(adapter);
>  	if (mgr) {
> -		/* PF function */
> -		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
> +		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> +				fme_interrupt_handler, "fme_irq", mgr);
> +		if (ret)
> +			goto cleanup;
>  	}
> 
> -	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
> -			fme_interrupt_handler, "fme_irq", mgr);
> -	if (ret)
> -		goto free_adapter_data;
> -
>  	ret = ifpga_monitor_start_func(dev);
>  	if (ret)
> -		goto free_adapter_data;
> +		goto cleanup;
> 
>  	return ret;
> 
> -free_adapter_data:
> -	if (data)
> -		opae_adapter_data_free(data);
>  cleanup:
>  	if (rawdev)
>  		rte_rawdev_pmd_release(rawdev);
> --
> 1.8.3.1

Reviewed-by: Rosen Xu <rosen.xu@intel.com>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 0/5] Support OFS card
  2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
                           ` (4 preceding siblings ...)
  2022-05-27  8:33         ` [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
@ 2022-06-07  9:07         ` Wei Huang
  2022-06-07  9:07           ` [PATCH v5 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
                             ` (5 more replies)
  5 siblings, 6 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Changes from v4:
1. update afu driver name in diagram in ifpga doc.

Wei Huang (5):
  raw/ifpga: remove experimental tag from ifpga APIs
  raw/ifpga: remove vdev when ifpga is closed
  raw/ifpga: unregister interrupt in ifpga close function
  raw/ifpga: support ofs card probe
  guides/rawdevs: add description of ofs in ifpga doc

 doc/guides/rawdevs/ifpga.rst               | 105 ++++-
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 680 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           | 241 ++++++----
 drivers/raw/ifpga/ifpga_rawdev.h           |   8 +
 drivers/raw/ifpga/rte_pmd_ifpga.h          |  48 --
 drivers/raw/ifpga/version.map              |   7 +-
 13 files changed, 845 insertions(+), 299 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 1/5] raw/ifpga: remove experimental tag from ifpga APIs
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
@ 2022-06-07  9:07           ` Wei Huang
  2022-06-07  9:07           ` [PATCH v5 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
                             ` (4 subsequent siblings)
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

These APIs are introduced in DPDK 21.05 and have been tested in several
release, experimental tag can be formally removed.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
 drivers/raw/ifpga/rte_pmd_ifpga.h | 48 ---------------------------------------
 drivers/raw/ifpga/version.map     |  7 ++----
 2 files changed, 2 insertions(+), 53 deletions(-)

diff --git a/drivers/raw/ifpga/rte_pmd_ifpga.h b/drivers/raw/ifpga/rte_pmd_ifpga.h
index 47d66ba..3fa5d34 100644
--- a/drivers/raw/ifpga/rte_pmd_ifpga.h
+++ b/drivers/raw/ifpga/rte_pmd_ifpga.h
@@ -68,9 +68,6 @@
 } rte_pmd_ifpga_phy_info;
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get raw device ID from PCI address string like 'Domain:Bus:Dev.Func'
  *
  * @param pci_addr
@@ -82,14 +79,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-ENODEV) if FPGA is not probed by ifpga driver.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_dev_id(const char *pci_addr, uint16_t *dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -103,14 +96,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_rsu_status(uint16_t dev_id, uint32_t *stat, uint32_t *prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Set current RSU status of the specified Intel FPGA device
  *
  * @param dev_id
@@ -124,14 +113,10 @@
  *   - (-ENODEV) if dev_id is invalid.
  *   - (-ENOMEM) if share data is not initialized.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_set_rsu_status(uint16_t dev_id, uint32_t stat, uint32_t prog);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get FPGA property of specified Intel FPGA device
  *
  * @param dev_id
@@ -144,14 +129,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_property(uint16_t dev_id, rte_pmd_ifpga_prop *prop);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PHY information of specified Intel FPGA device
  *
  * @param dev_id
@@ -164,14 +145,10 @@
  *   - (-EBUSY) if FPGA is rebooting.
  *   - (-EIO) if failed to access hardware.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_get_phy_info(uint16_t dev_id, rte_pmd_ifpga_phy_info *info);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Update image flash of specified Intel FPGA device
  *
  * @param dev_id
@@ -187,15 +164,11 @@
  *   - (-EBUSY) if FPGA is updating or rebooting.
  *   - (-EIO) if failed to open image file.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_update_flash(uint16_t dev_id, const char *image,
 	uint64_t *status);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Stop flash update of specified Intel FPGA device
  *
  * @param dev_id
@@ -208,14 +181,10 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EAGAIN) if failed with force.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_stop_update(uint16_t dev_id, int force);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Check current Intel FPGA status and change it to reboot status if it is idle
  *
  * @param dev_id
@@ -226,14 +195,10 @@
  *   - (-ENOMEM) if share data is not initialized.
  *   - (-EBUSY) if FPGA is updating or rebooting.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reboot_try(uint16_t dev_id);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Trigger full reconfiguration of specified Intel FPGA device
  *
  * @param dev_id
@@ -252,28 +217,20 @@
  *   - (-EINVAL) if bad parameter.
  *   - (-EBUSY) if failed to access BMC register.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_reload(uint16_t dev_id, int type, int page);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Get PCI bus the Intel FPGA driver register to
  *
  * @return
  *   - (valid pointer) if successful.
  *   - (NULL) if the Intel FPGA driver is not registered to any PCI bus.
  */
-__rte_experimental
 const struct rte_pci_bus *
 rte_pmd_ifpga_get_pci_bus(void);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Perform PR (partial reconfiguration) on specified Intel FPGA device
  *
  * @param dev_id
@@ -287,17 +244,12 @@
  *   - (-EINVAL) if bad parameter or operation failed.
  *   - (-ENOMEM) if failed to allocate memory.
  */
-__rte_experimental
 int
 rte_pmd_ifpga_partial_reconfigure(uint16_t dev_id, int port, const char *file);
 
 /**
- * @warning
- * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
- *
  * Free software resources allocated by Intel FPGA PMD
  */
-__rte_experimental
 void
 rte_pmd_ifpga_cleanup(void);
 
diff --git a/drivers/raw/ifpga/version.map b/drivers/raw/ifpga/version.map
index a1a6be2..ff71a45 100644
--- a/drivers/raw/ifpga/version.map
+++ b/drivers/raw/ifpga/version.map
@@ -1,11 +1,6 @@
 DPDK_22 {
-	local: *;
-};
-
-EXPERIMENTAL {
 	global:
 
-	# added in 21.05
 	rte_pmd_ifpga_get_dev_id;
 	rte_pmd_ifpga_get_rsu_status;
 	rte_pmd_ifpga_set_rsu_status;
@@ -18,4 +13,6 @@ EXPERIMENTAL {
 	rte_pmd_ifpga_get_pci_bus;
 	rte_pmd_ifpga_partial_reconfigure;
 	rte_pmd_ifpga_cleanup;
+
+	local: *;
 };
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 2/5] raw/ifpga: remove vdev when ifpga is closed
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
  2022-06-07  9:07           ` [PATCH v5 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
@ 2022-06-07  9:07           ` Wei Huang
  2022-06-07  9:07           ` [PATCH v5 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
                             ` (3 subsequent siblings)
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

Virtual devices created on ifpga raw device will not be removed
when ifpga device has closed. To avoid resource leak problem,
this patch introduces an ifpga virtual device remove function,
virtual devices will be destroyed after the ifpga raw device closed.

Fixes: ef1e8ede3da5 ("raw/ifpga: add Intel FPGA bus rawdev driver")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
v2: update commit log with Tianfei's comment
---
v3: replace constant with PCI_PRI_STR_SIZE per Rosen's comment
---
 drivers/raw/ifpga/ifpga_rawdev.c | 166 ++++++++++++++++++++++++++++++---------
 drivers/raw/ifpga/ifpga_rawdev.h |   8 ++
 2 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 6d4117c..fe3fc43 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -134,6 +134,8 @@ struct ifpga_rawdev *
 	for (i = 0; i < IFPGA_MAX_IRQ; i++)
 		dev->intr_handle[i] = NULL;
 	dev->poll_enabled = 0;
+	for (i = 0; i < IFPGA_MAX_VDEV; i++)
+		dev->vdev_name[i] = NULL;
 
 	return dev;
 }
@@ -736,10 +738,22 @@ static int set_surprise_link_check_aer(
 static int
 ifpga_rawdev_close(struct rte_rawdev *dev)
 {
+	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	char *vdev_name = NULL;
+	int i = 0;
 
 	if (dev) {
-		ifpga_monitor_stop_func(ifpga_rawdev_get(dev));
+		ifpga_rdev = ifpga_rawdev_get(dev);
+		if (ifpga_rdev) {
+			for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+				vdev_name = ifpga_rdev->vdev_name[i];
+				if (vdev_name)
+					rte_vdev_uninit(vdev_name);
+			}
+			ifpga_monitor_stop_func(ifpga_rdev);
+			ifpga_rdev->rawdev = NULL;
+		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
 			opae_adapter_destroy(adapter);
@@ -1638,8 +1652,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		return -EINVAL;
 	}
 	dev = ifpga_rawdev_get(rawdev);
-	if (dev)
-		dev->rawdev = NULL;
 
 	adapter = ifpga_rawdev_get_priv(rawdev);
 	if (!adapter)
@@ -1714,73 +1726,118 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 
 	return 0;
 }
+
 static int
-ifpga_cfg_probe(struct rte_vdev_device *dev)
+ifpga_vdev_parse_devargs(struct rte_devargs *devargs,
+	struct ifpga_vdev_args *args)
 {
-	struct rte_devargs *devargs;
-	struct rte_kvargs *kvlist = NULL;
-	struct rte_rawdev *rawdev = NULL;
-	struct ifpga_rawdev *ifpga_dev;
-	int port;
+	struct rte_kvargs *kvlist;
 	char *name = NULL;
-	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
-	int ret = -1;
+	int port = 0;
+	int ret = -EINVAL;
 
-	devargs = dev->device.devargs;
+	if (!devargs || !args)
+		return ret;
 
 	kvlist = rte_kvargs_parse(devargs->args, valid_args);
 	if (!kvlist) {
-		IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param");
-		goto end;
+		IFPGA_RAWDEV_PMD_ERR("error when parsing devargs");
+		return ret;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) {
 		if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME,
-				       &ifpga_rawdev_get_string_arg,
-				       &name) < 0) {
+			&ifpga_rawdev_get_string_arg, &name) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
-				     IFPGA_ARG_NAME);
+				IFPGA_ARG_NAME);
 			goto end;
+		} else {
+			strlcpy(args->bdf, name, sizeof(args->bdf));
+			rte_free(name);
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_NAME);
+			IFPGA_ARG_NAME);
 		goto end;
 	}
 
 	if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) {
-		if (rte_kvargs_process(kvlist,
-			IFPGA_ARG_PORT,
-			&rte_ifpga_get_integer32_arg,
-			&port) < 0) {
+		if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT,
+			&rte_ifpga_get_integer32_arg, &port) < 0) {
 			IFPGA_RAWDEV_PMD_ERR("error to parse %s",
 				IFPGA_ARG_PORT);
 			goto end;
+		} else {
+			args->port = port;
 		}
 	} else {
 		IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus",
-			  IFPGA_ARG_PORT);
+			IFPGA_ARG_PORT);
 		goto end;
 	}
 
+	ret = 0;
+
+end:
+	if (kvlist)
+		rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+ifpga_cfg_probe(struct rte_vdev_device *vdev)
+{
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	int i, n, ret = 0;
+
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("probe ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
 	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name);
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
 	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
 	if (!rawdev)
-		goto end;
+		return -ENODEV;
 	ifpga_dev = ifpga_rawdev_get(rawdev);
 	if (!ifpga_dev)
-		goto end;
+		return -ENODEV;
 
-	memset(dev_name, 0, sizeof(dev_name));
-	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
-	port, name);
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		if (ifpga_dev->vdev_name[i] == NULL) {
+			n = strlen(vdev_name) + 1;
+			ifpga_dev->vdev_name[i] = rte_malloc(NULL, n, 0);
+			if (ifpga_dev->vdev_name[i] == NULL)
+				return -ENOMEM;
+			strlcpy(ifpga_dev->vdev_name[i], vdev_name, n);
+			break;
+		}
+	}
 
+	if (i >= IFPGA_MAX_VDEV) {
+		IFPGA_RAWDEV_PMD_ERR("Can't create more virtual device!");
+		return -ENOENT;
+	}
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
 	ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME),
-			dev_name, devargs->args);
-end:
-	rte_kvargs_free(kvlist);
-	free(name);
+			dev_name, vdev->device.devargs->args);
+	if (ret) {
+		rte_free(ifpga_dev->vdev_name[i]);
+		ifpga_dev->vdev_name[i] = NULL;
+	}
 
 	return ret;
 }
@@ -1788,10 +1845,47 @@ static int ifpga_rawdev_get_string_arg(const char *key __rte_unused,
 static int
 ifpga_cfg_remove(struct rte_vdev_device *vdev)
 {
-	IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p",
-		vdev);
+	struct rte_rawdev *rawdev = NULL;
+	struct ifpga_rawdev *ifpga_dev;
+	struct ifpga_vdev_args args;
+	char dev_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const char *vdev_name = NULL;
+	char *tmp_vdev = NULL;
+	int i, ret = 0;
 
-	return 0;
+	vdev_name = rte_vdev_device_name(vdev);
+	if (!vdev_name)
+		return -EINVAL;
+
+	IFPGA_RAWDEV_PMD_INFO("remove ifpga virtual device %s", vdev_name);
+
+	ret = ifpga_vdev_parse_devargs(vdev->device.devargs, &args);
+	if (ret)
+		return ret;
+
+	memset(dev_name, 0, sizeof(dev_name));
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", args.bdf);
+	rawdev = rte_rawdev_pmd_get_named_dev(dev_name);
+	if (!rawdev)
+		return -ENODEV;
+	ifpga_dev = ifpga_rawdev_get(rawdev);
+	if (!ifpga_dev)
+		return -ENODEV;
+
+	snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s",
+		args.port, args.bdf);
+	ret = rte_eal_hotplug_remove(RTE_STR(IFPGA_BUS_NAME), dev_name);
+
+	for (i = 0; i < IFPGA_MAX_VDEV; i++) {
+		tmp_vdev = ifpga_dev->vdev_name[i];
+		if (tmp_vdev && !strcmp(tmp_vdev, vdev_name)) {
+			free(tmp_vdev);
+			ifpga_dev->vdev_name[i] = NULL;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static struct rte_vdev_driver ifpga_cfg_driver = {
diff --git a/drivers/raw/ifpga/ifpga_rawdev.h b/drivers/raw/ifpga/ifpga_rawdev.h
index 857b734..4c19119 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.h
+++ b/drivers/raw/ifpga/ifpga_rawdev.h
@@ -50,6 +50,7 @@ enum ifpga_rawdev_device_state {
 
 #define IFPGA_RAWDEV_MSIX_IRQ_NUM 7
 #define IFPGA_RAWDEV_NUM 32
+#define IFPGA_MAX_VDEV 4
 #define IFPGA_MAX_IRQ 12
 
 struct ifpga_rawdev {
@@ -64,6 +65,13 @@ struct ifpga_rawdev {
 	void *intr_handle[IFPGA_MAX_IRQ];
 	/* enable monitor thread poll device's sensors or not */
 	int poll_enabled;
+	/* name of virtual devices created on raw device */
+	char *vdev_name[IFPGA_MAX_VDEV];
+};
+
+struct ifpga_vdev_args {
+	char bdf[PCI_PRI_STR_SIZE];
+	int port;
 };
 
 struct ifpga_rawdev *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 3/5] raw/ifpga: unregister interrupt in ifpga close function
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
  2022-06-07  9:07           ` [PATCH v5 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
  2022-06-07  9:07           ` [PATCH v5 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
@ 2022-06-07  9:07           ` Wei Huang
  2022-06-07  9:07           ` [PATCH v5 4/5] raw/ifpga: support ofs card probe Wei Huang
                             ` (2 subsequent siblings)
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

There is an API rte_pmd_ifpga_cleanup provided by ifpga driver to
free the software resource used by ifpga card. The function call
of rte_pmd_ifpga_cleanup is list below.
rte_pmd_ifpga_cleanup()
  ifpga_rawdev_cleanup()
     rte_rawdev_pmd_release()
       rte_rawdev_close()
         ifpga_rawdev_close()

The interrupts are unregistered in ifpga_rawdev_destroy instead of
ifpga_rawdev_close function, so rte_pmd_ifpga_cleanup cannot free
interrupt resource as expected.

To fix such issue, interrupt unregistration is moved from
ifpga_rawdev_destroy to ifpga_rawdev_close function. The change of
function call of ifpga_rawdev_destroy is as below.
ifpga_rawdev_destroy()
  ifpga_unregister_msix_irq()  // removed
  rte_rawdev_pmd_release()
    rte_rawdev_close()
      ifpga_rawdev_close()

Fixes: e0a1aafe2af9 ("raw/ifpga: introduce IRQ functions")
Cc: stable@dpdk.org

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
v2: update commit log with Tianfei's comment
---
v3: update commit log with more explanations about the function call
---
 drivers/raw/ifpga/ifpga_rawdev.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index fe3fc43..94df56c 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -78,6 +78,7 @@ static int set_surprise_link_check_aer(
 static int ifpga_pci_find_next_ext_capability(unsigned int fd,
 					      int start, uint32_t cap);
 static int ifpga_pci_find_ext_capability(unsigned int fd, uint32_t cap);
+static void fme_interrupt_handler(void *param);
 
 struct ifpga_rawdev *
 ifpga_rawdev_get(const struct rte_rawdev *rawdev)
@@ -740,8 +741,9 @@ static int set_surprise_link_check_aer(
 {
 	struct ifpga_rawdev *ifpga_rdev = NULL;
 	struct opae_adapter *adapter;
+	struct opae_manager *mgr;
 	char *vdev_name = NULL;
-	int i = 0;
+	int i, ret = 0;
 
 	if (dev) {
 		ifpga_rdev = ifpga_rawdev_get(dev);
@@ -756,12 +758,19 @@ static int set_surprise_link_check_aer(
 		}
 		adapter = ifpga_rawdev_get_priv(dev);
 		if (adapter) {
+			mgr = opae_adapter_get_mgr(adapter);
+			if (ifpga_rdev && mgr) {
+				if (ifpga_unregister_msix_irq(ifpga_rdev,
+					IFPGA_FME_IRQ, 0,
+					fme_interrupt_handler, mgr) < 0)
+					ret = -EINVAL;
+			}
 			opae_adapter_destroy(adapter);
 			opae_adapter_data_free(adapter->data);
 		}
 	}
 
-	return dev ? 0:1;
+	return ret;
 }
 
 static int
@@ -1629,9 +1638,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	int ret;
 	struct rte_rawdev *rawdev;
 	char name[RTE_RAWDEV_NAME_MAX_LEN];
-	struct opae_adapter *adapter;
-	struct opae_manager *mgr;
-	struct ifpga_rawdev *dev;
 
 	if (!pci_dev) {
 		IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!");
@@ -1651,19 +1657,6 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 		IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name);
 		return -EINVAL;
 	}
-	dev = ifpga_rawdev_get(rawdev);
-
-	adapter = ifpga_rawdev_get_priv(rawdev);
-	if (!adapter)
-		return -ENODEV;
-
-	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
-		return -ENODEV;
-
-	if (ifpga_unregister_msix_irq(dev, IFPGA_FME_IRQ, 0,
-				fme_interrupt_handler, mgr) < 0)
-		return -EINVAL;
 
 	/* rte_rawdev_close is called by pmd_release */
 	ret = rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 4/5] raw/ifpga: support ofs card probe
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
                             ` (2 preceding siblings ...)
  2022-06-07  9:07           ` [PATCH v5 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
@ 2022-06-07  9:07           ` Wei Huang
  2022-06-07  9:07           ` [PATCH v5 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
  2022-06-07 13:53           ` [PATCH v5 0/5] Support OFS card Thomas Monjalon
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

PAC N6000 is the first OFS platform, its device id is added to ifpga
device support list.

Previous FPGA platform like Intel PAC N3000 and N5000, FME DFL (Device
Feature List) starts from BAR0 by default, port DFL location is indicated
in PORTn_OFFSET register in FME. In OFS implementation, FME DFL and port
DFL location can be defined individually in PCIe VSEC (Vendor Specific
Extended Capabilities). In this patch, DFL definition is searched in VSEC,
the legacy DFL is used only when DFL VSEC is not present.

In original DFL enumeration process, AFU is expected to locate in port DFL,
but this is not the case in OFS implementation. In this patch, enumeration
can search AFU in any PF/VF which has no FME and port.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
v2: fix build error in UB2004-32
---
v3: update commit log with Tianfei's comment, treat 7 as special BAR index
---
v4: fix typo and coding style issue
---
 drivers/raw/ifpga/base/ifpga_api.c         |  28 +-
 drivers/raw/ifpga/base/ifpga_defines.h     |   1 +
 drivers/raw/ifpga/base/ifpga_enumerate.c   | 680 ++++++++++++++++++++++-------
 drivers/raw/ifpga/base/ifpga_enumerate.h   |   2 +
 drivers/raw/ifpga/base/ifpga_feature_dev.c |  18 +-
 drivers/raw/ifpga/base/ifpga_hw.h          |   2 +
 drivers/raw/ifpga/base/opae_hw_api.c       |   2 +-
 drivers/raw/ifpga/base/opae_hw_api.h       |   2 +
 drivers/raw/ifpga/ifpga_rawdev.c           |  48 +-
 9 files changed, 591 insertions(+), 192 deletions(-)

diff --git a/drivers/raw/ifpga/base/ifpga_api.c b/drivers/raw/ifpga/base/ifpga_api.c
index 4610ef1..f19cc26 100644
--- a/drivers/raw/ifpga/base/ifpga_api.c
+++ b/drivers/raw/ifpga/base/ifpga_api.c
@@ -13,15 +13,22 @@
 static int ifpga_acc_get_uuid(struct opae_accelerator *acc,
 			      struct uuid *uuid)
 {
-	struct opae_bridge *br = acc->br;
-	struct ifpga_port_hw *port;
+	struct ifpga_afu_info *afu_info = acc->data;
+	struct opae_reg_region *region;
+	u64 val = 0;
 
-	if (!br || !br->data)
-		return -EINVAL;
+	if (!afu_info)
+		return -ENODEV;
 
-	port = br->data;
+	region = &afu_info->region[0];
+	if (uuid) {
+		val = readq(region->addr + sizeof(struct feature_header));
+		opae_memcpy(uuid->b, &val, sizeof(u64));
+		val = readq(region->addr + sizeof(struct feature_header) + 8);
+		opae_memcpy(uuid->b + 8, &val, sizeof(u64));
+	}
 
-	return fpga_get_afu_uuid(port, uuid);
+	return 0;
 }
 
 static int ifpga_acc_set_irq(struct opae_accelerator *acc,
@@ -32,6 +39,9 @@ static int ifpga_acc_set_irq(struct opae_accelerator *acc,
 	struct ifpga_port_hw *port;
 	struct fpga_uafu_irq_set irq_set;
 
+	if (!afu_info)
+		return -ENODEV;
+
 	if (!br || !br->data)
 		return -EINVAL;
 
@@ -68,7 +78,7 @@ static int ifpga_acc_get_region_info(struct opae_accelerator *acc,
 	struct ifpga_afu_info *afu_info = acc->data;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (info->index >= afu_info->num_regions)
 		return -EINVAL;
@@ -89,7 +99,7 @@ static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
@@ -129,7 +139,7 @@ static int ifpga_acc_write(struct opae_accelerator *acc,
 	struct opae_reg_region *region;
 
 	if (!afu_info)
-		return -EINVAL;
+		return -ENODEV;
 
 	if (offset + byte <= offset)
 		return -EINVAL;
diff --git a/drivers/raw/ifpga/base/ifpga_defines.h b/drivers/raw/ifpga/base/ifpga_defines.h
index 8f62033..9a280eb 100644
--- a/drivers/raw/ifpga/base/ifpga_defines.h
+++ b/drivers/raw/ifpga/base/ifpga_defines.h
@@ -73,6 +73,7 @@
 enum fpga_id_type {
 	FME_ID,
 	PORT_ID,
+	AFU_ID,
 	FPGA_ID_MAX,
 };
 
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.c b/drivers/raw/ifpga/base/ifpga_enumerate.c
index 48b8af4..7a5d264 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.c
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.c
@@ -2,6 +2,10 @@
  * Copyright(c) 2010-2018 Intel Corporation
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
 #include "opae_hw_api.h"
 #include "ifpga_api.h"
 
@@ -9,6 +13,19 @@
 #include "ifpga_enumerate.h"
 #include "ifpga_feature_dev.h"
 
+struct dfl_fpga_enum_dfl {
+	u64 start;
+	u64 len;
+	void *addr;
+	TAILQ_ENTRY(dfl_fpga_enum_dfl) node;
+};
+
+TAILQ_HEAD(dfl_fpga_enum_dfls, dfl_fpga_enum_dfl);
+struct dfl_fpga_enum_info {
+	struct ifpga_hw *hw;
+	struct dfl_fpga_enum_dfls dfls;
+};
+
 struct build_feature_devs_info {
 	struct opae_adapter_data_pci *pci_data;
 
@@ -21,7 +38,6 @@ struct build_feature_devs_info {
 	void *ioaddr;
 	void *ioend;
 	uint64_t phys_addr;
-	int current_bar;
 
 	void *pfme_hdr;
 
@@ -141,8 +157,10 @@ static u64 feature_id(void __iomem *start)
 			unsigned int size, unsigned int vec_start,
 			unsigned int vec_cnt)
 {
-	return build_info_add_sub_feature(binfo, start, fid, size, vec_start,
-			vec_cnt);
+	if (binfo->current_type != AFU_ID)
+		return build_info_add_sub_feature(binfo, start, fid, size,
+			vec_start, vec_cnt);
+	return 0;
 }
 
 /*
@@ -152,13 +170,14 @@ static u64 feature_id(void __iomem *start)
  */
 static bool feature_is_UAFU(struct build_feature_devs_info *binfo)
 {
-	if (binfo->current_type != PORT_ID)
-		return false;
+	if ((binfo->current_type == PORT_ID) ||
+		(binfo->current_type == AFU_ID))
+		return true;
 
-	return true;
+	return false;
 }
 
-static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
+static int parse_feature_uafu(struct build_feature_devs_info *binfo,
 				   struct feature_header *hdr)
 {
 	u64 id = PORT_FEATURE_ID_UAFU;
@@ -169,9 +188,19 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	int ret;
 	int size;
 
+	if (binfo->acc_info) {
+		dev_info(binfo, "Sub AFU found @ %p.\n", start);
+		return 0;
+	}
+
 	capability.csr = readq(&port_hdr->capability);
 
-	size = capability.mmio_size << 10;
+	if (binfo->current_type == AFU_ID) {
+		size = AFU_REGION_SIZE;
+	} else {
+		capability.csr = readq(&port_hdr->capability);
+		size = capability.mmio_size << 10;
+	}
 
 	ret = create_feature_instance(binfo, hdr, id, size, 0, 0);
 	if (ret)
@@ -185,44 +214,13 @@ static int parse_feature_port_uafu(struct build_feature_devs_info *binfo,
 	info->region[0].phys_addr = binfo->phys_addr +
 			(uint8_t *)start - (uint8_t *)binfo->ioaddr;
 	info->region[0].len = size;
-	info->num_regions = 1;
+	info->num_regions = AFU_MAX_REGION;
 
 	binfo->acc_info = info;
 
 	return ret;
 }
 
-static int parse_feature_afus(struct build_feature_devs_info *binfo,
-			      struct feature_header *hdr)
-{
-	int ret;
-	struct feature_afu_header *afu_hdr, header;
-	u8 __iomem *start;
-	u8 __iomem *end = binfo->ioend;
-
-	start = (u8 __iomem *)hdr;
-	for (; start < end; start += header.next_afu) {
-		if ((unsigned int)(end - start) <
-			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
-			return -EINVAL;
-
-		hdr = (struct feature_header *)start;
-		afu_hdr = (struct feature_afu_header *)(hdr + 1);
-		header.csr = readq(&afu_hdr->csr);
-
-		if (feature_is_UAFU(binfo)) {
-			ret = parse_feature_port_uafu(binfo, hdr);
-			if (ret)
-				return ret;
-		}
-
-		if (!header.next_afu)
-			break;
-	}
-
-	return 0;
-}
-
 /* create and register proper private data */
 static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
@@ -235,13 +233,9 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	struct ifpga_fme_hw *fme;
 	struct ifpga_feature *feature;
 
-	if (!binfo->fiu)
-		return 0;
-
 	if (binfo->current_type == PORT_ID) {
-		/* return error if no valid acc info data structure */
-		if (!info)
-			return -EFAULT;
+		if (!binfo->fiu)
+			return 0;
 
 		br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops,
 				       binfo->fiu);
@@ -254,7 +248,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 		port = &hw->port[binfo->current_port_id];
 		feature = get_feature_by_id(&port->feature_list,
 				PORT_FEATURE_ID_UINT);
-		if (feature)
+		if (feature && info)
 			info->num_irqs = feature->vec_cnt;
 
 		acc = opae_accelerator_alloc(hw->adapter->name,
@@ -264,17 +258,21 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 			return -ENOMEM;
 		}
 
+		acc->adapter = hw->adapter;
 		acc->br = br;
 		if (hw->adapter->mgr)
 			acc->mgr = hw->adapter->mgr;
 		acc->index = br->id;
 
 		fme = &hw->fme;
-		fme->nums_acc_region = info->num_regions;
+		fme->nums_acc_region = info ? info->num_regions : 0;
 
 		opae_adapter_add_acc(hw->adapter, acc);
 
 	} else if (binfo->current_type == FME_ID) {
+		if (!binfo->fiu)
+			return 0;
+
 		mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops,
 				&ifpga_mgr_network_ops, binfo->fiu);
 		if (!mgr)
@@ -282,6 +280,22 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 
 		mgr->adapter = hw->adapter;
 		hw->adapter->mgr = mgr;
+	} else if (binfo->current_type == AFU_ID) {
+		if (!info)
+			return -EFAULT;
+
+		info->num_irqs = 0;
+		acc = opae_accelerator_alloc(hw->adapter->name,
+					&ifpga_acc_ops, info);
+		if (!acc)
+			return -ENOMEM;
+
+		acc->adapter = hw->adapter;
+		acc->br = NULL;
+		acc->mgr = NULL;
+		acc->index = hw->num_afus++;
+
+		opae_adapter_add_acc(hw->adapter, acc);
 	}
 
 	binfo->fiu = NULL;
@@ -295,11 +309,15 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 {
 	int ret;
 
+	if ((type == AFU_ID) && (binfo->current_type == PORT_ID))
+		return 0;
+
 	ret = build_info_commit_dev(binfo);
 	if (ret)
 		return ret;
 
 	binfo->current_type = type;
+	binfo->acc_info = NULL;
 
 	if (type == FME_ID) {
 		binfo->fiu = &binfo->hw->fme;
@@ -311,6 +329,41 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 	return 0;
 }
 
+static int parse_feature_afus(struct build_feature_devs_info *binfo,
+			      struct feature_header *hdr)
+{
+	int ret;
+	struct feature_afu_header *afu_hdr, header;
+	u8 __iomem *start;
+	u8 __iomem *end = binfo->ioend;
+
+	ret = build_info_create_dev(binfo, AFU_ID, 0);
+	if (ret)
+		return ret;
+
+	start = (u8 __iomem *)hdr;
+	for (; start < end; start += header.next_afu) {
+		if ((unsigned int)(end - start) <
+			(unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr)))
+			return -EINVAL;
+
+		hdr = (struct feature_header *)start;
+		afu_hdr = (struct feature_afu_header *)(hdr + 1);
+		header.csr = readq(&afu_hdr->csr);
+
+		if (feature_is_UAFU(binfo)) {
+			ret = parse_feature_uafu(binfo, hdr);
+			if (ret)
+				return ret;
+		}
+
+		if (!header.next_afu)
+			break;
+	}
+
+	return 0;
+}
+
 static int parse_feature_fme(struct build_feature_devs_info *binfo,
 			     struct feature_header *start)
 {
@@ -405,7 +458,7 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 			if (ret)
 				return ret;
 		} else {
-			dev_info(binfo, "No AFUs detected on Port\n");
+			dev_info(binfo, "No AFU detected on Port\n");
 		}
 
 		break;
@@ -426,7 +479,7 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 
 	id = feature_id(start);
 
-	if (id == PORT_FEATURE_ID_UINT) {
+	if ((binfo->current_type == PORT_ID) && (id == PORT_FEATURE_ID_UINT)) {
 		struct feature_port_uint *port_uint = start;
 		struct feature_port_uint_cap uint_cap;
 
@@ -437,7 +490,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 		} else {
 			dev_debug(binfo, "UAFU doesn't support interrupt\n");
 		}
-	} else if (id == PORT_FEATURE_ID_ERROR) {
+	} else if ((binfo->current_type == PORT_ID) &&
+			(id == PORT_FEATURE_ID_ERROR)) {
 		struct feature_port_error *port_err = start;
 		struct feature_port_err_capability port_err_cap;
 
@@ -449,7 +503,8 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo,
 			dev_debug(&binfo, "Port error doesn't support interrupt\n");
 		}
 
-	} else if (id == FME_FEATURE_ID_GLOBAL_ERR) {
+	} else if ((binfo->current_type == FME_ID) &&
+			(id == FME_FEATURE_ID_GLOBAL_ERR)) {
 		struct feature_fme_err *fme_err = start;
 		struct feature_fme_error_capability fme_err_cap;
 
@@ -497,9 +552,15 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
 		return parse_feature_fme_private(binfo, hdr);
 	case PORT_ID:
 		return parse_feature_port_private(binfo, hdr);
+	case AFU_ID:
+		dev_err(binfo, "private feature %x belonging to AFU "
+			"is not supported yet.\n", header.id);
+		break;
 	default:
-		dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n",
+		dev_err(binfo, "private feature %x belonging to TYPE %d "
+			"(unknown_type) is not supported yet.\n",
 			header.id, binfo->current_type);
+		break;
 	}
 	return 0;
 }
@@ -530,32 +591,57 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return ret;
 }
 
-static int
-parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start)
+static int build_info_prepare(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
 {
+	if (!binfo || !dfl)
+		return -EINVAL;
+
+	binfo->ioaddr = dfl->addr;
+	binfo->ioend = (u8 *)dfl->addr + dfl->len;
+	binfo->phys_addr = dfl->start;
+
+	return 0;
+}
+
+static int parse_feature_list(struct build_feature_devs_info *binfo,
+	struct dfl_fpga_enum_dfl *dfl)
+{
+	u8 *start, *end;
 	struct feature_header *hdr, header;
-	u8 __iomem *end = (u8 __iomem *)binfo->ioend;
 	int ret = 0;
 
+	ret = build_info_prepare(binfo, dfl);
+	if (ret)
+		return ret;
+
+	start = (u8 *)binfo->ioaddr;
+	end = (u8 *)binfo->ioend;
+
+	/* walk through the device feature list via DFH's next DFH pointer. */
 	for (; start < end; start += header.next_header_offset) {
 		if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) {
-			dev_err(binfo, "The region is too small to contain a feature.\n");
-			ret =  -EINVAL;
+			dev_err(binfo, "The region is too small to "
+				"contain a feature.\n");
+			ret = -EINVAL;
 			break;
 		}
 
 		hdr = (struct feature_header *)start;
-		header.csr = readq(hdr);
+		header.csr = opae_readq(hdr);
 
-		dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n",
-			__func__, hdr, (unsigned long long)header.csr,
-			header.id, header.next_header_offset,
-			header.end_of_list, header.type);
+		dev_debug(binfo, "%s: address=0x%p, val=0x%"PRIx64", "
+			"header.id=0x%x, header.next_offset=0x%x, "
+			"header.eol=0x%x, header.type=0x%x\n",
+			__func__, hdr, header.csr, header.id,
+			header.next_header_offset, header.end_of_list,
+			header.type);
 
 		ret = parse_feature(binfo, hdr);
 		if (ret)
 			return ret;
 
+		/* stop parsing if EOL(End of List) is set or offset is 0 */
 		if (header.end_of_list || !header.next_header_offset)
 			break;
 	}
@@ -563,82 +649,9 @@ static int parse_feature(struct build_feature_devs_info *binfo,
 	return build_info_commit_dev(binfo);
 }
 
-/* switch the memory mapping to BAR# @bar */
-static int parse_switch_to(struct build_feature_devs_info *binfo, int bar)
-{
-	struct opae_adapter_data_pci *pci_data = binfo->pci_data;
-
-	if (!pci_data->region[bar].addr)
-		return -ENOMEM;
-
-	binfo->ioaddr = pci_data->region[bar].addr;
-	binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len;
-	binfo->phys_addr = pci_data->region[bar].phys_addr;
-	binfo->current_bar = bar;
-
-	return 0;
-}
-
-static int parse_ports_from_fme(struct build_feature_devs_info *binfo)
-{
-	struct feature_fme_header *fme_hdr;
-	struct feature_fme_port port;
-	int i = 0, ret = 0;
-
-	if (!binfo->pfme_hdr) {
-		dev_info(binfo,  "VF is detected.\n");
-		return ret;
-	}
-
-	fme_hdr = binfo->pfme_hdr;
-
-	do {
-		port.csr = readq(&fme_hdr->port[i]);
-		if (!port.port_implemented)
-			break;
-
-		/* skip port which only could be accessed via VF */
-		if (port.afu_access_control == FME_AFU_ACCESS_VF)
-			continue;
-
-		ret = parse_switch_to(binfo, port.port_bar);
-		if (ret)
-			break;
-
-		ret = parse_feature_list(binfo,
-					 (u8 __iomem *)binfo->ioaddr +
-					  port.port_offset);
-		if (ret)
-			break;
-	} while (++i < MAX_FPGA_PORT_NUM);
-
-	return ret;
-}
-
-static struct build_feature_devs_info *
-build_info_alloc_and_init(struct ifpga_hw *hw)
-{
-	struct build_feature_devs_info *binfo;
-
-	binfo = zmalloc(sizeof(*binfo));
-	if (!binfo)
-		return binfo;
-
-	binfo->hw = hw;
-	binfo->pci_data = hw->pci_data;
-
-	/* fpga feature list starts from BAR 0 */
-	if (parse_switch_to(binfo, 0)) {
-		free(binfo);
-		return NULL;
-	}
-
-	return binfo;
-}
-
 static void build_info_free(struct build_feature_devs_info *binfo)
 {
-	free(binfo);
+	opae_free(binfo);
 }
 
 static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
@@ -648,6 +661,11 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	struct ifpga_feature *feature;
 	int i;
 
+	if (fme->state == IFPGA_FME_UNUSED) {
+		dev_info(hw, "FME is not present\n");
+		return;
+	}
+
 	dev_info(hw, "found fme_device, is in PF: %s\n",
 		 is_ifpga_hw_pf(hw) ? "yes" : "no");
 
@@ -685,40 +703,410 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw)
 	}
 }
 
-int ifpga_bus_enumerate(struct ifpga_hw *hw)
+static struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct ifpga_hw *hw)
 {
-	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_info *info;
+
+	info = opae_zmalloc(sizeof(*info));
+	if (!info)
+		return NULL;
+
+	info->hw = hw;
+	TAILQ_INIT(&info->dfls);
+
+	return info;
+}
+
+static void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
+{
+	struct dfl_fpga_enum_dfl *tmp, *dfl;
+
+	if (!info)
+		return;
+
+	/* remove all device feature lists in the list. */
+	for (dfl = TAILQ_FIRST(&info->dfls);
+		dfl && (tmp = TAILQ_NEXT(dfl, node), 1);
+		dfl = tmp) {
+		TAILQ_REMOVE(&info->dfls, dfl, node);
+		opae_free(dfl);
+	}
+
+	opae_free(info);
+}
+
+static int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
+	u64 start, u64 len, void *addr)
+{
+	struct dfl_fpga_enum_dfl *dfl;
+
+	dfl = opae_zmalloc(sizeof(*dfl));
+	if (!dfl)
+		return -ENOMEM;
+
+	dfl->start = start;
+	dfl->len = len;
+	dfl->addr = addr;
+
+	TAILQ_INSERT_TAIL(&info->dfls, dfl, node);
+
+	return 0;
+}
+
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+#define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
+#define PCI_EXT_CAP_NEXT(header)	((header >> 20) & 0xffc)
+
+static int
+pci_find_next_ecap(int fd, int start, u32 cap)
+{
+	u32 header;
+	int ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+	int pos = PCI_CFG_SPACE_SIZE;
 	int ret;
 
-	binfo = build_info_alloc_and_init(hw);
+	if (start > 0)
+		pos = start;
+
+	ret = pread(fd, &header, sizeof(header), pos);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if ((PCI_EXT_CAP_ID(header) == cap) && (pos != start))
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < PCI_CFG_SPACE_SIZE)
+			break;
+		ret = pread(fd, &header, sizeof(header), pos);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PCI_EXT_CAP_ID_VNDR	0x0B
+#define PCI_VNDR_HEADER		4
+#define PCI_VNDR_HEADER_ID(x)	((x) & 0xffff)
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VSEC_ID_INTEL_DFLS 0x43
+#define PCI_VNDR_DFLS_CNT 0x8
+#define PCI_VNDR_DFLS_RES 0xc
+#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
+#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
+
+static int find_dfls_by_vsec(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	char path[64];
+	u32 bir, offset, vndr_hdr, i, dfl_cnt, dfl_res;
+	int fd, ret, dfl_res_off, voff = 0;
+	u64 start, len;
+	void *addr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->adapter || !hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	ret = snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/config",
+			hw->adapter->name);
+	if ((unsigned int)ret >= sizeof(path))
+		return -EINVAL;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -EIO;
+
+	while ((voff = pci_find_next_ecap(fd, voff,
+		PCI_EXT_CAP_ID_VNDR))) {
+		vndr_hdr = 0;
+		ret = pread(fd, &vndr_hdr, sizeof(vndr_hdr),
+			voff + PCI_VNDR_HEADER);
+		if (ret < 0)
+			return -EIO;
+		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
+			pci_data->vendor_id == PCI_VENDOR_ID_INTEL)
+			break;
+	}
+
+	if (!voff) {
+		dev_debug(hw, "%s no DFL VSEC found\n", __func__);
+		return -ENODEV;
+	}
+
+	dfl_cnt = 0;
+	ret = pread(fd, &dfl_cnt, sizeof(dfl_cnt), voff + PCI_VNDR_DFLS_CNT);
+	if (ret < 0)
+		return -EIO;
+
+	dfl_res_off = voff + PCI_VNDR_DFLS_RES;
+	if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
+		dev_err(hw, "%s DFL VSEC too big for PCIe config space\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
+		dfl_res = GENMASK(31, 0);
+		ret = pread(fd, &dfl_res, sizeof(dfl_res), dfl_res_off);
+		bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
+		if (bir >= PCI_MAX_RESOURCE) {
+			dev_err(hw, "%s bad bir number %d\n",
+				__func__, bir);
+			return -EINVAL;
+		}
+
+		len = pci_data->region[bir].len;
+		offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
+		if (offset >= len) {
+			dev_err(hw, "%s bad offset %u >= %"PRIu64"\n",
+				__func__, offset, len);
+			return -EINVAL;
+		}
+
+		dev_debug(hw, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
+		len -= offset;
+		start = pci_data->region[bir].phys_addr + offset;
+		addr = pci_data->region[bir].addr + offset;
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	}
+
+	return 0;
+}
+
+/* default method of finding dfls starting at offset 0 of bar 0 */
+static int
+find_dfls_by_default(struct dfl_fpga_enum_info *info)
+{
+	struct ifpga_hw *hw;
+	struct opae_adapter_data_pci *pci_data;
+	int port_num, bar, i, ret = 0;
+	u64 start, len;
+	void *addr;
+	u32 offset;
+	struct feature_header hdr;
+	struct feature_fme_capability cap;
+	struct feature_fme_port port;
+	struct feature_fme_header *fme_hdr;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+	hw = info->hw;
+
+	if (!hw->pci_data)
+		return -EINVAL;
+	pci_data = hw->pci_data;
+
+	/* start to find Device Feature List from Bar 0 */
+	addr = pci_data->region[0].addr;
+	if (!addr)
+		return -ENOMEM;
+
+	/*
+	 * PF device has FME and Ports/AFUs, and VF device only has one
+	 * Port/AFU. Check them and add related "Device Feature List" info
+	 * for the next step enumeration.
+	 */
+	hdr.csr = opae_readq(addr);
+	if ((hdr.type == FEATURE_TYPE_FIU) && (hdr.id == FEATURE_FIU_ID_FME)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+
+		/*
+		 * find more Device Feature Lists (e.g. Ports) per information
+		 * indicated by FME module.
+		 */
+		fme_hdr = (struct feature_fme_header *)addr;
+		cap.csr = opae_readq(&fme_hdr->capability);
+		port_num = (int)cap.num_ports;
+
+		dev_info(hw, "port_num = %d\n", port_num);
+		if (port_num > MAX_FPGA_PORT_NUM)
+			port_num = MAX_FPGA_PORT_NUM;
+
+		for (i = 0; i < port_num; i++) {
+			port.csr = opae_readq(&fme_hdr->port[i]);
+
+			/* skip ports which are not implemented. */
+			if (!port.port_implemented)
+				continue;
+
+			/* skip port which only could be accessed via VF */
+			if (port.afu_access_control == FME_AFU_ACCESS_VF)
+				continue;
+
+			/*
+			 * add Port's Device Feature List information for next
+			 * step enumeration.
+			 */
+			bar = (int)port.port_bar;
+			offset = port.port_offset;
+			if (bar == FME_PORT_OFST_BAR_SKIP) {
+				continue;
+			} else if (bar >= PCI_MAX_RESOURCE) {
+				dev_err(hw, "bad BAR %d for port %d\n", bar, i);
+				ret = -EINVAL;
+				break;
+			}
+			dev_info(hw, "BAR %d offset %u\n", bar, offset);
+
+			len = pci_data->region[bar].len;
+			if (offset >= len) {
+				dev_warn(hw, "bad port offset %u >= %pa\n",
+					 offset, &len);
+				continue;
+			}
+
+			len -= offset;
+			start = pci_data->region[bar].phys_addr + offset;
+			addr = pci_data->region[bar].addr + offset;
+			dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+		}
+	} else if ((hdr.type == FEATURE_TYPE_FIU) &&
+		(hdr.id == FEATURE_FIU_ID_PORT)) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else if (hdr.type == FEATURE_TYPE_AFU) {
+		start = pci_data->region[0].phys_addr;
+		len = pci_data->region[0].len;
+		addr = pci_data->region[0].addr;
+
+		dfl_fpga_enum_info_add_dfl(info, start, len, addr);
+	} else {
+		dev_info(hw, "Unknown feature type 0x%x id 0x%x\n",
+			 hdr.type, hdr.id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
+{
+	struct build_feature_devs_info *binfo;
+	struct dfl_fpga_enum_dfl *dfl;
+	int ret = 0;
+
+	if (!info || !info->hw)
+		return -EINVAL;
+
+	/* create and init build info for enumeration */
+	binfo = opae_zmalloc(sizeof(*binfo));
 	if (!binfo)
 		return -ENOMEM;
 
-	ret = parse_feature_list(binfo, binfo->ioaddr);
+	binfo->hw = info->hw;
+	binfo->pci_data = info->hw->pci_data;
+
+	/*
+	 * start enumeration for all feature devices based on Device Feature
+	 * Lists.
+	 */
+	TAILQ_FOREACH(dfl, &info->dfls, node) {
+		ret = parse_feature_list(binfo, dfl);
+		if (ret)
+			break;
+	}
+
+	build_info_free(binfo);
+
+	return ret;
+}
+
+int ifpga_bus_enumerate(struct ifpga_hw *hw)
+{
+	struct dfl_fpga_enum_info *info;
+	int ret;
+
+	/* allocate enumeration info */
+	info = dfl_fpga_enum_info_alloc(hw);
+	if (!info)
+		return -ENOMEM;
+
+	ret = find_dfls_by_vsec(info);
+	if (ret < 0)
+		ret = find_dfls_by_default(info);
+
 	if (ret)
 		goto exit;
 
-	ret = parse_ports_from_fme(binfo);
-	if (ret)
+	/* start enumeration with prepared enumeration information */
+	ret = dfl_fpga_feature_devs_enumerate(info);
+	if (ret < 0) {
+		dev_err(hw, "Enumeration failure\n");
 		goto exit;
+	}
 
 	ifpga_print_device_feature_list(hw);
 
 exit:
-	build_info_free(binfo);
+	dfl_fpga_enum_info_free(info);
+
 	return ret;
 }
 
-int ifpga_bus_init(struct ifpga_hw *hw)
+static void ifpga_print_acc_list(struct opae_adapter *adapter)
 {
+	struct opae_accelerator *acc;
+	struct ifpga_afu_info *info;
+	struct uuid guid;
+	char buf[48];
 	int i;
+
+	opae_adapter_for_each_acc(adapter, acc) {
+		info = acc->data;
+		if (!info)
+			continue;
+		acc->ops->get_uuid(acc, &guid);
+		i = sprintf(buf, "%02x%02x%02x%02x-",
+			guid.b[15], guid.b[14], guid.b[13], guid.b[12]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[11], guid.b[10]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[9], guid.b[8]);
+		i += sprintf(buf+i, "%02x%02x-", guid.b[7], guid.b[6]);
+		sprintf(buf+i, "%02x%02x%02x%02x%02x%02x",
+			guid.b[5], guid.b[4], guid.b[3],
+			guid.b[2], guid.b[1], guid.b[0]);
+		dev_info(hw, "AFU(%s-%d)@%p: len:0x%"PRIx64", guid:%s\n",
+			acc->name, acc->index, info->region[0].addr,
+			info->region[0].len, buf);
+	}
+}
+
+int ifpga_bus_init(struct ifpga_hw *hw)
+{
+	int i, ret = 0;
 	struct ifpga_port_hw *port;
 
-	fme_hw_init(&hw->fme);
+	ret = fme_hw_init(&hw->fme);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < MAX_FPGA_PORT_NUM; i++) {
 		port = &hw->port[i];
 		port_hw_init(port);
 	}
+	ifpga_print_acc_list(hw->adapter);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_enumerate.h b/drivers/raw/ifpga/base/ifpga_enumerate.h
index 95ed594..e6b04f0 100644
--- a/drivers/raw/ifpga/base/ifpga_enumerate.h
+++ b/drivers/raw/ifpga/base/ifpga_enumerate.h
@@ -5,6 +5,8 @@
 #ifndef _IFPGA_ENUMERATE_H_
 #define _IFPGA_ENUMERATE_H_
 
+#define FME_PORT_OFST_BAR_SKIP  7
+
 int ifpga_bus_init(struct ifpga_hw *hw);
 int ifpga_bus_uinit(struct ifpga_hw *hw);
 int ifpga_bus_enumerate(struct ifpga_hw *hw);
diff --git a/drivers/raw/ifpga/base/ifpga_feature_dev.c b/drivers/raw/ifpga/base/ifpga_feature_dev.c
index 0813513..dbecc7b 100644
--- a/drivers/raw/ifpga/base/ifpga_feature_dev.c
+++ b/drivers/raw/ifpga/base/ifpga_feature_dev.c
@@ -59,7 +59,7 @@ int __fpga_port_disable(struct ifpga_port_hw *port)
 	if (fpga_wait_register_field(port_sftrst_ack, control,
 				     &port_hdr->control, RST_POLL_TIMEOUT,
 				     RST_POLL_INVL)) {
-		dev_err(port, "timeout, fail to reset device\n");
+		dev_err(port, "timeout, fail to reset FIM port\n");
 		return -ETIMEDOUT;
 	}
 
@@ -277,10 +277,11 @@ static void feature_uinit(struct ifpga_feature_list *list)
 	struct ifpga_feature *feature;
 
 	TAILQ_FOREACH(feature, list, next) {
-		if (feature->state != IFPGA_FEATURE_ATTACHED)
+		if (feature->state != IFPGA_FEATURE_INITED)
 			continue;
 		if (feature->ops && feature->ops->uinit)
 			feature->ops->uinit(feature);
+		feature->state = IFPGA_FEATURE_ATTACHED;
 	}
 }
 
@@ -301,6 +302,9 @@ static int feature_init(struct feature_driver *drv,
 					ret = feature->ops->init(feature);
 					if (ret)
 						goto error;
+					else
+						feature->state =
+							IFPGA_FEATURE_INITED;
 				}
 			}
 		}
@@ -315,14 +319,8 @@ static int feature_init(struct feature_driver *drv,
 
 int fme_hw_init(struct ifpga_fme_hw *fme)
 {
-	int ret;
-
-	if (fme->state != IFPGA_FME_IMPLEMENTED)
-		return -ENODEV;
-
-	ret = feature_init(fme_feature_drvs, &fme->feature_list);
-	if (ret)
-		return ret;
+	if (fme->state == IFPGA_FME_IMPLEMENTED)
+		return feature_init(fme_feature_drvs, &fme->feature_list);
 
 	return 0;
 }
diff --git a/drivers/raw/ifpga/base/ifpga_hw.h b/drivers/raw/ifpga/base/ifpga_hw.h
index ed5edc6..4d56deb 100644
--- a/drivers/raw/ifpga/base/ifpga_hw.h
+++ b/drivers/raw/ifpga/base/ifpga_hw.h
@@ -15,6 +15,7 @@
 enum ifpga_feature_state {
 	IFPGA_FEATURE_UNUSED = 0,
 	IFPGA_FEATURE_ATTACHED,
+	IFPGA_FEATURE_INITED
 };
 
 enum feature_type {
@@ -134,6 +135,7 @@ struct ifpga_hw {
 
 	struct ifpga_fme_hw fme;
 	struct ifpga_port_hw port[MAX_FPGA_PORT_NUM];
+	int num_afus;
 };
 
 static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.c b/drivers/raw/ifpga/base/opae_hw_api.c
index 11c9887..87256fc 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.c
+++ b/drivers/raw/ifpga/base/opae_hw_api.c
@@ -177,7 +177,7 @@ int opae_acc_get_region_info(struct opae_accelerator *acc,
 int opae_acc_set_irq(struct opae_accelerator *acc,
 		     u32 start, u32 count, s32 evtfds[])
 {
-	if (!acc || !acc->data)
+	if (!acc)
 		return -EINVAL;
 
 	if (start + count <= start)
diff --git a/drivers/raw/ifpga/base/opae_hw_api.h b/drivers/raw/ifpga/base/opae_hw_api.h
index 7e04b56..fd40e09 100644
--- a/drivers/raw/ifpga/base/opae_hw_api.h
+++ b/drivers/raw/ifpga/base/opae_hw_api.h
@@ -143,6 +143,7 @@ struct opae_accelerator {
 	TAILQ_ENTRY(opae_accelerator) node;
 	const char *name;
 	int index;
+	struct opae_adapter *adapter;
 	struct opae_bridge *br;
 	struct opae_manager *mgr;
 	struct opae_accelerator_ops *ops;
@@ -240,6 +241,7 @@ struct opae_adapter_data {
 
 struct opae_reg_region {
 	u64 phys_addr;
+#define AFU_REGION_SIZE  0x8000
 	u64 len;
 	u8 *addr;
 };
diff --git a/drivers/raw/ifpga/ifpga_rawdev.c b/drivers/raw/ifpga/ifpga_rawdev.c
index 94df56c..ceb18ae 100644
--- a/drivers/raw/ifpga/ifpga_rawdev.c
+++ b/drivers/raw/ifpga/ifpga_rawdev.c
@@ -47,11 +47,13 @@
 #define PCIE_DEVICE_ID_PF_INT_6_X    0xBCC0
 #define PCIE_DEVICE_ID_PF_DSC_1_X    0x09C4
 #define PCIE_DEVICE_ID_PAC_N3000     0x0B30
+#define PCIE_DEVICE_ID_PAC_N6000     0xBCCE
 /* VF Device */
 #define PCIE_DEVICE_ID_VF_INT_5_X    0xBCBF
 #define PCIE_DEVICE_ID_VF_INT_6_X    0xBCC1
 #define PCIE_DEVICE_ID_VF_DSC_1_X    0x09C5
 #define PCIE_DEVICE_ID_VF_PAC_N3000  0x0B31
+#define PCIE_DEVICE_ID_VF_PAC_N6000  0xBCCF
 #define RTE_MAX_RAW_DEVICE           10
 
 static const struct rte_pci_id pci_ifpga_map[] = {
@@ -63,6 +65,8 @@
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) },
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),},
 	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N6000),},
+	{ RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N6000),},
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
@@ -110,6 +114,7 @@ struct ifpga_rawdev *
 
 	return IFPGA_RAWDEV_NUM;
 }
+
 static struct ifpga_rawdev *
 ifpga_rawdev_allocate(struct rte_rawdev *rawdev)
 {
@@ -365,7 +370,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 		return -ENODEV;
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr)
+	if (!mgr || !mgr->sensor_list)
 		return -ENODEV;
 
 	opae_mgr_for_each_sensor(mgr, sensor) {
@@ -377,7 +382,7 @@ static int ifpga_rawdev_fill_info(struct ifpga_rawdev *ifpga_dev)
 			goto fail;
 
 		if (value == 0xdeadbeef) {
-			IFPGA_RAWDEV_PMD_ERR("dev_id %d sensor %s value %x\n",
+			IFPGA_RAWDEV_PMD_DEBUG("dev_id %d sensor %s value %x\n",
 					raw_dev->dev_id, sensor->name, value);
 			continue;
 		}
@@ -893,7 +898,7 @@ static int set_surprise_link_check_aer(
 {
 	struct opae_adapter *adapter;
 	struct opae_manager *mgr;
-	struct opae_board_info *info;
+	struct opae_board_info *info = NULL;
 	struct rte_afu_pr_conf *afu_pr_conf;
 	int ret;
 	struct uuid uuid;
@@ -921,17 +926,14 @@ static int set_surprise_link_check_aer(
 	}
 
 	mgr = opae_adapter_get_mgr(adapter);
-	if (!mgr) {
-		IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL");
-		return -1;
-	}
-
-	if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
-		IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
-		return -1;
+	if (mgr) {
+		if (ifpga_mgr_ops.get_board_info(mgr, &info)) {
+			IFPGA_RAWDEV_PMD_ERR("ifpga manager get_board_info fail!");
+			return -1;
+		}
 	}
 
-	if (info->lightweight) {
+	if (info && info->lightweight) {
 		/* set uuid to all 0, when fpga is lightweight image */
 		memset(&afu_pr_conf->afu_id.uuid.uuid_low, 0, sizeof(u64));
 		memset(&afu_pr_conf->afu_id.uuid.uuid_high, 0, sizeof(u64));
@@ -953,7 +955,7 @@ static int set_surprise_link_check_aer(
 			__func__,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_low,
 			(unsigned long)afu_pr_conf->afu_id.uuid.uuid_high);
-		}
+	}
 	return 0;
 }
 
@@ -1592,7 +1594,7 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	ret = opae_adapter_init(adapter, pci_dev->device.name, data);
 	if (ret) {
 		ret = -ENOMEM;
-		goto free_adapter_data;
+		goto cleanup;
 	}
 
 	rawdev->dev_ops = &ifpga_rawdev_ops;
@@ -1602,29 +1604,23 @@ static int fme_clean_fme_error(struct opae_manager *mgr)
 	/* must enumerate the adapter before use it */
 	ret = opae_adapter_enumerate(adapter);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	/* get opae_manager to rawdev */
 	mgr = opae_adapter_get_mgr(adapter);
 	if (mgr) {
-		/* PF function */
-		IFPGA_RAWDEV_PMD_INFO("this is a PF function");
+		ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
+				fme_interrupt_handler, "fme_irq", mgr);
+		if (ret)
+			goto cleanup;
 	}
 
-	ret = ifpga_register_msix_irq(dev, 0, IFPGA_FME_IRQ, 0, 0,
-			fme_interrupt_handler, "fme_irq", mgr);
-	if (ret)
-		goto free_adapter_data;
-
 	ret = ifpga_monitor_start_func(dev);
 	if (ret)
-		goto free_adapter_data;
+		goto cleanup;
 
 	return ret;
 
-free_adapter_data:
-	if (data)
-		opae_adapter_data_free(data);
 cleanup:
 	if (rawdev)
 		rte_rawdev_pmd_release(rawdev);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v5 5/5] guides/rawdevs: add description of ofs in ifpga doc
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
                             ` (3 preceding siblings ...)
  2022-06-07  9:07           ` [PATCH v5 4/5] raw/ifpga: support ofs card probe Wei Huang
@ 2022-06-07  9:07           ` Wei Huang
  2022-06-07 13:53           ` [PATCH v5 0/5] Support OFS card Thomas Monjalon
  5 siblings, 0 replies; 47+ messages in thread
From: Wei Huang @ 2022-06-07  9:07 UTC (permalink / raw)
  To: dev, thomas, nipun.gupta, hemant.agrawal
  Cc: stable, rosen.xu, tianfei.zhang, qi.z.zhang, Wei Huang

OFS (Open FPGA Stack) specification is introduced briefly.

Signed-off-by: Wei Huang <wei.huang@intel.com>
Acked-by: Tianfei Zhang <tianfei.zhang@intel.com>
Reviewed-by: Rosen Xu <rosen.xu@intel.com>
---
v2: update description per Tianfei's comment
---
v3: update afu driver name in diagram
---
 doc/guides/rawdevs/ifpga.rst | 105 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 104 insertions(+), 1 deletion(-)

diff --git a/doc/guides/rawdevs/ifpga.rst b/doc/guides/rawdevs/ifpga.rst
index dbd0d6e..bf557b2 100644
--- a/doc/guides/rawdevs/ifpga.rst
+++ b/doc/guides/rawdevs/ifpga.rst
@@ -1,5 +1,5 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
-    Copyright(c) 2018 Intel Corporation.
+    Copyright(c) 2018-2022 Intel Corporation.
 
 IFPGA Rawdev Driver
 ======================
@@ -100,3 +100,106 @@ The following device parameters are supported:
 
   If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and
   identifies AFU Bit Stream file.
+
+
+Open FPGA Stack
+=====================
+
+Open FPGA Stack (OFS) is a collection of RTL and open source software providing
+interfaces to access the instantiated RTL easily in an FPGA. OFS leverages the
+DFL for the implementation of the FPGA RTL design.
+
+OFS designs allow for the arrangement of software interfaces across multiple
+PCIe endpoints. Some of these interfaces may be PFs defined in the static region
+that connect to interfaces in an IP that is loaded via Partial Reconfiguration (PR).
+And some of these interfaces may be VFs defined in the PR region that can be
+reconfigured by the end-user. Furthermore, these PFs/VFs may use DFLs such that
+features may be discovered and accessed in user space with the aid of a generic
+kernel driver like vfio-pci. The diagram below depicts an example design with one
+PF and two VFs. In this example, it will export the management functions via PF0
+and acceleration functions via VF0 and VF1, leverage VFIO to export the MMIO space
+to an application.::
+
+     +-----------------+  +-------------+  +------------+
+     | FPGA Management |  |  DPDK App   |  |  User App  |
+     |      App        |  |             |  |            |
+     +--------+--------+  +------+------+  +-----+------+
+              |                  |               |
+     +--------+--------+  +------+------+        |
+     |    IFPGA PMD    |  |   AFU PMD   |        |
+     +--------+--------+  +------+------+        |
+              |                  |               |
+     +--------+------------------+---------------+------+
+     |                VFIO-PCI                          |
+     +--------+------------------+---------------+------+
+              |                  |               |
+     +--------+--------+  +------+------+  +-----+------+
+     |       PF0       |  |   PF0_VF0   |  |  PF0_VF1   |
+     +-----------------+  +-------------+  +------------+
+
+As accelerators are specialized hardware, they are typically limited in the
+number installed in a given system. Many use cases require them to be shared
+across multiple software contexts or threads of software execution, either
+through partitioning of individual dedicated resources, or virtualization of
+shared resources. OFS provides several models to share the AFU resources via
+PR mechanism and hardware-based virtualization schemes.
+
+1. Legacy model.
+   With legacy model FPGA cards like Intel PAC N3000 or N5000, there is
+   a notion that the boundary between the AFU and the shell is also the unit of
+   PR for those FPGA platforms. This model is only able to handle a
+   single context, because it only has one PR engine, and one PR region which
+   has an associated Port device.
+2. Multiple VFs per PR slot.
+   In this model, available AFU resources may allow instantiation of many VFs
+   which have a dedicated PCIe function with their own dedicated MMIO space, or
+   partition a region of MMIO space on a single PCIe function. Intel PAC N6000
+   card has implemented this model.
+   In this model, the AFU/PR slot was not connected to port device. For DFL's view,
+   the Next_AFU pointer in FIU feature header of port device points to NULL in this
+   model. On the other hand, each VF can start with an AFU feature header without
+   being connected to a FIU Port feature header.
+
+The VFs are created through the Linux kernel driver before we use them in DPDK.
+
+OFS provides the diversity for accessing the AFU resource to RTL developer.
+An IP designer may choose to add more than one PF for interfacing with IP
+on the FPGA and choose different model to access the AFU resource.
+
+There is one reference architecture design using the "Multiple VFs per PR slot"
+model for OFS as illustrated below. In this reference design, it exports the
+FPGA management functions via PF0. PF1 will bind with DPDK virtio driver
+presenting itself as a network interface to the application. PF2 will bind to the
+vfio-pci driver allowing the user space software to discover and interface
+with the specific workload like diagnostic test. It leverages AFU PMD driver to
+access the AFU resources in DPDK.::
+
+                              +----------------------+
+                              |   PF/VF mux/demux    |
+                              +--+--+-----+------+-+-+
+                                 |  |     |      | |
+        +------------------------+  |     |      | |
+  PF0   |                 +---------+   +-+      | |
+    +---+---+             |         +---+----+   | |
+    |  DFH  |             |         |   DFH  |   | |
+    +-------+       +-----+----+    +--------+   | |
+    |  FME  |       |  VirtIO  |    |  Test  |   | |
+    +---+---+       +----------+    +--------+   | |
+        |                PF1            PF2      | |
+        |                                        | |
+        |                             +----------+ |
+        |                             |           ++
+        |                             |           |
+        |                             | PF0_VF0   | PF0_VF1
+        |           +-----------------+-----------+------------+
+        |           |           +-----+-----------+--------+   |
+        |           |           |     |           |        |   |
+        |           | +------+  |  +--+ -+     +--+---+    |   |
+        |           | | Port |  |  | DFH |     |  DFH |    |   |
+        +-----------+ +------+  |  +-----+     +------+    |   |
+                    |           |  | DEV |     |  DEV |    |   |
+                    |           |  +-----+     +------+    |   |
+                    |           |            PR Slot       |   |
+                    |           +--------------------------+   |
+                    | Port Gasket                              |
+                    +------------------------------------------+
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v5 0/5] Support OFS card
  2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
                             ` (4 preceding siblings ...)
  2022-06-07  9:07           ` [PATCH v5 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
@ 2022-06-07 13:53           ` Thomas Monjalon
  5 siblings, 0 replies; 47+ messages in thread
From: Thomas Monjalon @ 2022-06-07 13:53 UTC (permalink / raw)
  To: Wei Huang
  Cc: dev, nipun.gupta, hemant.agrawal, stable, rosen.xu,
	tianfei.zhang, qi.z.zhang

> Wei Huang (5):
>   raw/ifpga: remove experimental tag from ifpga APIs
>   raw/ifpga: remove vdev when ifpga is closed
>   raw/ifpga: unregister interrupt in ifpga close function
>   raw/ifpga: support ofs card probe
>   guides/rawdevs: add description of ofs in ifpga doc

Applied, thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2022-06-07 13:53 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-17  6:28 [PATCH v1 0/4] Support OFS card Wei Huang
2022-05-17  6:28 ` [PATCH v1 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
2022-05-17  6:28 ` [PATCH v1 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
2022-05-17  6:28 ` [PATCH v1 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
2022-05-17  6:28 ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Wei Huang
2022-05-18  8:29   ` [PATCH v2 0/4] Support OFS card Wei Huang
2022-05-18  8:29     ` [PATCH v2 1/4] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
2022-05-25  3:22       ` Zhang, Tianfei
2022-05-18  8:29     ` [PATCH v2 2/4] raw/ifpga: remove vdev when ifpga is closed Wei Huang
2022-05-25  4:09       ` Zhang, Tianfei
2022-05-18  8:29     ` [PATCH v2 3/4] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
2022-05-25  3:26       ` Zhang, Tianfei
2022-05-18  8:29     ` [PATCH v2 4/4] raw/ifpga: support ofs card probe Wei Huang
2022-05-26  3:32     ` [PATCH v3 0/5] Support OFS card Wei Huang
2022-05-26  3:32       ` [PATCH v3 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
2022-05-26  6:29         ` Xu, Rosen
2022-05-26  3:32       ` [PATCH v3 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
2022-05-26  6:34         ` Xu, Rosen
2022-05-26  3:32       ` [PATCH v3 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
2022-05-26  6:41         ` Xu, Rosen
2022-05-27  2:57         ` Zhang, Tianfei
2022-05-26  3:32       ` [PATCH v3 4/5] raw/ifpga: support ofs card probe Wei Huang
2022-05-26  6:46         ` Xu, Rosen
2022-05-27  3:10         ` Zhang, Tianfei
2022-05-26  3:32       ` [PATCH v3 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
2022-05-26  6:47         ` Xu, Rosen
2022-05-27  3:19         ` Zhang, Tianfei
2022-05-27  8:33       ` [PATCH v4 0/5] Support OFS card Wei Huang
2022-05-27  8:33         ` [PATCH v4 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
2022-05-27  8:33         ` [PATCH v4 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
2022-06-06  6:46           ` Zhang, Tianfei
2022-06-07  6:02           ` Xu, Rosen
2022-05-27  8:33         ` [PATCH v4 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
2022-06-07  6:03           ` Xu, Rosen
2022-05-27  8:33         ` [PATCH v4 4/5] raw/ifpga: support ofs card probe Wei Huang
2022-06-07  6:04           ` Xu, Rosen
2022-05-27  8:33         ` [PATCH v4 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
2022-05-31  0:24           ` Zhang, Tianfei
2022-06-06  6:45           ` Zhang, Tianfei
2022-06-07  9:07         ` [PATCH v5 0/5] Support OFS card Wei Huang
2022-06-07  9:07           ` [PATCH v5 1/5] raw/ifpga: remove experimental tag from ifpga APIs Wei Huang
2022-06-07  9:07           ` [PATCH v5 2/5] raw/ifpga: remove vdev when ifpga is closed Wei Huang
2022-06-07  9:07           ` [PATCH v5 3/5] raw/ifpga: unregister interrupt in ifpga close function Wei Huang
2022-06-07  9:07           ` [PATCH v5 4/5] raw/ifpga: support ofs card probe Wei Huang
2022-06-07  9:07           ` [PATCH v5 5/5] guides/rawdevs: add description of ofs in ifpga doc Wei Huang
2022-06-07 13:53           ` [PATCH v5 0/5] Support OFS card Thomas Monjalon
2022-05-25  3:18   ` [PATCH v1 4/4] raw/ifpga: support ofs card probe Zhang, Tianfei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).