[v4,2/4] eal: fix IOVA mode selection as VA for PCI drivers

Message ID 1563800213-29839-3-git-send-email-david.marchand@redhat.com (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers
Series Fixes on IOVA mode selection |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

David Marchand July 22, 2019, 12:56 p.m. UTC
  The incriminated commit broke the use of RTE_PCI_DRV_IOVA_AS_VA which
was intended to mean "driver only supports VA" but had been understood
as "driver supports both PA and VA" by most net drivers and used to let
dpdk processes to run as non root (which do not have access to physical
addresses on recent kernels).

The check on physical addresses actually closed the gap for those
drivers. We don't need to mark them with RTE_PCI_DRV_IOVA_AS_VA and this
flag can retain its intended meaning.
Document explicitly its meaning.

We can check that a driver requirement wrt to IOVA mode is fulfilled
before trying to probe a device.

Finally, document the heuristic used to select the IOVA mode and hope
that we won't break it again.

Fixes: 703458e19c16 ("bus/pci: consider only usable devices for IOVA mode")

Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Jerin Jacob <jerinj@marvell.com>
Tested-by: Jerin Jacob <jerinj@marvell.com>
Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
---
Changelog since v3:
- fixed typos,

---
 doc/guides/prog_guide/env_abstraction_layer.rst | 31 +++++++++++++++++++++++++
 drivers/bus/pci/linux/pci.c                     | 16 +++++--------
 drivers/bus/pci/pci_common.c                    | 30 +++++++++++++++++++-----
 drivers/bus/pci/rte_bus_pci.h                   |  4 ++--
 drivers/net/atlantic/atl_ethdev.c               |  3 +--
 drivers/net/bnxt/bnxt_ethdev.c                  |  3 +--
 drivers/net/e1000/em_ethdev.c                   |  3 +--
 drivers/net/e1000/igb_ethdev.c                  |  5 ++--
 drivers/net/enic/enic_ethdev.c                  |  3 +--
 drivers/net/fm10k/fm10k_ethdev.c                |  3 +--
 drivers/net/i40e/i40e_ethdev.c                  |  3 +--
 drivers/net/i40e/i40e_ethdev_vf.c               |  2 +-
 drivers/net/iavf/iavf_ethdev.c                  |  3 +--
 drivers/net/ice/ice_ethdev.c                    |  3 +--
 drivers/net/ixgbe/ixgbe_ethdev.c                |  5 ++--
 drivers/net/mlx4/mlx4.c                         |  3 +--
 drivers/net/mlx5/mlx5.c                         |  2 +-
 drivers/net/nfp/nfp_net.c                       |  6 ++---
 drivers/net/octeontx2/otx2_ethdev.c             |  5 ----
 drivers/net/qede/qede_ethdev.c                  |  6 ++---
 drivers/raw/ioat/ioat_rawdev.c                  |  3 +--
 lib/librte_eal/common/eal_common_bus.c          | 30 +++++++++++++++++++++---
 22 files changed, 110 insertions(+), 62 deletions(-)
  

Comments

Ferruh Yigit Nov. 25, 2019, 9:33 a.m. UTC | #1
On 7/22/2019 1:56 PM, David Marchand wrote:
> The incriminated commit broke the use of RTE_PCI_DRV_IOVA_AS_VA which
> was intended to mean "driver only supports VA" but had been understood
> as "driver supports both PA and VA" by most net drivers and used to let
> dpdk processes to run as non root (which do not have access to physical
> addresses on recent kernels).
> 
> The check on physical addresses actually closed the gap for those
> drivers. We don't need to mark them with RTE_PCI_DRV_IOVA_AS_VA and this
> flag can retain its intended meaning.
> Document explicitly its meaning.
> 
> We can check that a driver requirement wrt to IOVA mode is fulfilled
> before trying to probe a device.
> 
> Finally, document the heuristic used to select the IOVA mode and hope
> that we won't break it again.
> 
> Fixes: 703458e19c16 ("bus/pci: consider only usable devices for IOVA mode")
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> Reviewed-by: Jerin Jacob <jerinj@marvell.com>
> Tested-by: Jerin Jacob <jerinj@marvell.com>
> Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
<...>

> diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
> index d2af472..9794552 100644
> --- a/drivers/bus/pci/pci_common.c
> +++ b/drivers/bus/pci/pci_common.c
> @@ -169,8 +169,22 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
>  	 * This needs to be before rte_pci_map_device(), as it enables to use
>  	 * driver flags for adjusting configuration.
>  	 */
> -	if (!already_probed)
> +	if (!already_probed) {
> +		enum rte_iova_mode dev_iova_mode;
> +		enum rte_iova_mode iova_mode;
> +
> +		dev_iova_mode = pci_device_iova_mode(dr, dev);
> +		iova_mode = rte_eal_iova_mode();
> +		if (dev_iova_mode != RTE_IOVA_DC &&
> +		    dev_iova_mode != iova_mode) {
> +			RTE_LOG(ERR, EAL, "  Expecting '%s' IOVA mode but current mode is '%s', not initializing\n",
> +				dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA",
> +				iova_mode == RTE_IOVA_PA ? "PA" : "VA");
> +			return -EINVAL;
> +		}
> +

OvS reported an error while hotplugging a device.

It looks like DPDK application initialized as IOVA=VA, and the new device is bound to 'igb_uio' which forces it to PA, fails on above check.

I would like to get your comment on the issue.

For the OvS mode, hopefully binding the device to 'vfio-pci' can be a solution, but for the cases we don't have that option, can/should we force the DPDK to PA mode after initialization?
  
Thomas Monjalon Nov. 25, 2019, 10:22 a.m. UTC | #2
25/11/2019 10:33, Ferruh Yigit:
> It looks like DPDK application initialized as IOVA=VA,
> and the new device is bound to 'igb_uio' which forces it to PA,
> fails on above check.

Do you mean this use case was not tested earlier with DPDK 19.08?


> I would like to get your comment on the issue.
> 
> For the OvS mode, hopefully binding the device to 'vfio-pci'
> can be a solution, but for the cases we don't have that option,
> can/should we force the DPDK to PA mode after initialization?

I think this is expected, because VA is the new default since 19.08:
http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features

In case, there is no constraint on initialization,
we have to decide which mode is preferred.
Previously PA was preferred.
For the sake of modernity (and because it fits with some new devices),
the preference has been changed to VA.

If igb_uio device is used at initialization,
the PA mode should be used.
If igb_uio (PA-only) device is hotplugged, no luck!
If VA-only device is hotplugged, it works!

I think this change is one step in deprecating igb_uio.
  
Jerin Jacob Nov. 25, 2019, 11:07 a.m. UTC | #3
On Mon, Nov 25, 2019 at 6:33 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>
>
> On 7/22/2019 1:56 PM, David Marchand wrote:
> > The incriminated commit broke the use of RTE_PCI_DRV_IOVA_AS_VA which
> > was intended to mean "driver only supports VA" but had been understood
> > as "driver supports both PA and VA" by most net drivers and used to let
> > dpdk processes to run as non root (which do not have access to physical
> > addresses on recent kernels).
> >
> > The check on physical addresses actually closed the gap for those
> > drivers. We don't need to mark them with RTE_PCI_DRV_IOVA_AS_VA and this
> > flag can retain its intended meaning.
> > Document explicitly its meaning.
> >
> > We can check that a driver requirement wrt to IOVA mode is fulfilled
> > before trying to probe a device.
> >
> > Finally, document the heuristic used to select the IOVA mode and hope
> > that we won't break it again.
> >
> > Fixes: 703458e19c16 ("bus/pci: consider only usable devices for IOVA mode")
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > Reviewed-by: Jerin Jacob <jerinj@marvell.com>
> > Tested-by: Jerin Jacob <jerinj@marvell.com>
> > Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
> <...>
>
> > diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
> > index d2af472..9794552 100644
> > --- a/drivers/bus/pci/pci_common.c
> > +++ b/drivers/bus/pci/pci_common.c
> > @@ -169,8 +169,22 @@ static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
> >        * This needs to be before rte_pci_map_device(), as it enables to use
> >        * driver flags for adjusting configuration.
> >        */
> > -     if (!already_probed)
> > +     if (!already_probed) {
> > +             enum rte_iova_mode dev_iova_mode;
> > +             enum rte_iova_mode iova_mode;
> > +
> > +             dev_iova_mode = pci_device_iova_mode(dr, dev);
> > +             iova_mode = rte_eal_iova_mode();
> > +             if (dev_iova_mode != RTE_IOVA_DC &&
> > +                 dev_iova_mode != iova_mode) {
> > +                     RTE_LOG(ERR, EAL, "  Expecting '%s' IOVA mode but current mode is '%s', not initializing\n",
> > +                             dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA",
> > +                             iova_mode == RTE_IOVA_PA ? "PA" : "VA");
> > +                     return -EINVAL;
> > +             }
> > +
>
> OvS reported an error while hotplugging a device.
>
> It looks like DPDK application initialized as IOVA=VA, and the new device is bound to 'igb_uio' which forces it to PA, fails on above check.

Why they are binding to igb_uio if there is NO need for it?

>
> I would like to get your comment on the issue.
>
> For the OvS mode, hopefully binding the device to 'vfio-pci' can be a solution, but for the cases we don't have that option, can/should we force the DPDK to PA mode after initialization?

On the other side, If we are forcing DPDK to PA then the same fate
will be for VFIO only devices.
There are two cases:
1) The system has a limitation on the specific mode
2) The devices have a limitation on the specific mod.e.

Case (1), It is not applicable for hotplug cases as the system can run
only one mode. We should able to detect in the first pass(Before the
hotplug devices runs)
Case (2), Is there any devices that can work ONLY in IOVA as PA mode?
If yes, Please enumerate. Maybe something in the storage domain.



>
  
Ferruh Yigit Nov. 25, 2019, 12:03 p.m. UTC | #4
On 11/25/2019 10:22 AM, Thomas Monjalon wrote:
> 25/11/2019 10:33, Ferruh Yigit:
>> It looks like DPDK application initialized as IOVA=VA,
>> and the new device is bound to 'igb_uio' which forces it to PA,
>> fails on above check.
> 
> Do you mean this use case was not tested earlier with DPDK 19.08?

Perhaps, just a guess, this can be side affect of only using LTS.

> 
> 
>> I would like to get your comment on the issue.
>>
>> For the OvS mode, hopefully binding the device to 'vfio-pci'
>> can be a solution, but for the cases we don't have that option,
>> can/should we force the DPDK to PA mode after initialization?
> 
> I think this is expected, because VA is the new default since 19.08:
> http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
> 
> In case, there is no constraint on initialization,
> we have to decide which mode is preferred.
> Previously PA was preferred.
> For the sake of modernity (and because it fits with some new devices),
> the preference has been changed to VA.
> 
> If igb_uio device is used at initialization,
> the PA mode should be used.
> If igb_uio (PA-only) device is hotplugged, no luck!
> If VA-only device is hotplugged, it works!
> 
> I think this change is one step in deprecating igb_uio.
> 

I just want to confirm/clarify that this behavior change is by design, not a defect.
Should we document this behavior change more clearly, or highlight more, to not 
let catch others too?
  
David Marchand Nov. 25, 2019, 12:36 p.m. UTC | #5
On Mon, Nov 25, 2019 at 1:03 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> >> I would like to get your comment on the issue.
> >>
> >> For the OvS mode, hopefully binding the device to 'vfio-pci'
> >> can be a solution, but for the cases we don't have that option,
> >> can/should we force the DPDK to PA mode after initialization?
> >
> > I think this is expected, because VA is the new default since 19.08:
> > http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
> >
> > In case, there is no constraint on initialization,
> > we have to decide which mode is preferred.
> > Previously PA was preferred.
> > For the sake of modernity (and because it fits with some new devices),
> > the preference has been changed to VA.
> >
> > If igb_uio device is used at initialization,
> > the PA mode should be used.
> > If igb_uio (PA-only) device is hotplugged, no luck!
> > If VA-only device is hotplugged, it works!
> >
> > I think this change is one step in deprecating igb_uio.
> >
>
> I just want to confirm/clarify that this behavior change is by design, not a defect.
> Should we document this behavior change more clearly, or highlight more, to not
> let catch others too?

The behavior change happened with:
https://git.dpdk.org/dpdk/commit?id=bbe29a9bd7ab6feab9a52051c32092a94ee886eb
And there is an entry in the 19.08 release notes:
http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
  
Anatoly Burakov Nov. 25, 2019, 12:58 p.m. UTC | #6
On 25-Nov-19 12:36 PM, David Marchand wrote:
> On Mon, Nov 25, 2019 at 1:03 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>>> I would like to get your comment on the issue.
>>>>
>>>> For the OvS mode, hopefully binding the device to 'vfio-pci'
>>>> can be a solution, but for the cases we don't have that option,
>>>> can/should we force the DPDK to PA mode after initialization?
>>>
>>> I think this is expected, because VA is the new default since 19.08:
>>> http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
>>>
>>> In case, there is no constraint on initialization,
>>> we have to decide which mode is preferred.
>>> Previously PA was preferred.
>>> For the sake of modernity (and because it fits with some new devices),
>>> the preference has been changed to VA.
>>>
>>> If igb_uio device is used at initialization,
>>> the PA mode should be used.
>>> If igb_uio (PA-only) device is hotplugged, no luck!
>>> If VA-only device is hotplugged, it works!
>>>
>>> I think this change is one step in deprecating igb_uio.
>>>
>>
>> I just want to confirm/clarify that this behavior change is by design, not a defect.
>> Should we document this behavior change more clearly, or highlight more, to not
>> let catch others too?
> 
> The behavior change happened with:
> https://git.dpdk.org/dpdk/commit?id=bbe29a9bd7ab6feab9a52051c32092a94ee886eb
> And there is an entry in the 19.08 release notes:
> http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
> 
> 

Should we perhaps also provide LTS release notes, i.e. "all changes 
since last LTS"? I think it's unreasonable to expect people using LTS's 
to trace through every release notes between LTS's.
  
Thomas Monjalon Nov. 25, 2019, 2:29 p.m. UTC | #7
25/11/2019 13:58, Burakov, Anatoly:
> On 25-Nov-19 12:36 PM, David Marchand wrote:
> > On Mon, Nov 25, 2019 at 1:03 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> >>>> I would like to get your comment on the issue.
> >>>>
> >>>> For the OvS mode, hopefully binding the device to 'vfio-pci'
> >>>> can be a solution, but for the cases we don't have that option,
> >>>> can/should we force the DPDK to PA mode after initialization?
> >>>
> >>> I think this is expected, because VA is the new default since 19.08:
> >>> http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
> >>>
> >>> In case, there is no constraint on initialization,
> >>> we have to decide which mode is preferred.
> >>> Previously PA was preferred.
> >>> For the sake of modernity (and because it fits with some new devices),
> >>> the preference has been changed to VA.
> >>>
> >>> If igb_uio device is used at initialization,
> >>> the PA mode should be used.
> >>> If igb_uio (PA-only) device is hotplugged, no luck!
> >>> If VA-only device is hotplugged, it works!
> >>>
> >>> I think this change is one step in deprecating igb_uio.
> >>>
> >>
> >> I just want to confirm/clarify that this behavior change is by design, not a defect.
> >> Should we document this behavior change more clearly, or highlight more, to not
> >> let catch others too?
> > 
> > The behavior change happened with:
> > https://git.dpdk.org/dpdk/commit?id=bbe29a9bd7ab6feab9a52051c32092a94ee886eb
> > And there is an entry in the 19.08 release notes:
> > http://doc.dpdk.org/guides/rel_notes/release_19_08.html#new-features
> > 
> > 
> 
> Should we perhaps also provide LTS release notes, i.e. "all changes 
> since last LTS"? I think it's unreasonable to expect people using LTS's 
> to trace through every release notes between LTS's.

I don't think it is unreasonable.
There are only 4 releases since last LTS.
But I am OK for switching to 3 releases per year :)
  

Patch

diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst
index f15bcd9..1d63675 100644
--- a/doc/guides/prog_guide/env_abstraction_layer.rst
+++ b/doc/guides/prog_guide/env_abstraction_layer.rst
@@ -419,6 +419,37 @@  Misc Functions
 
 Locks and atomic operations are per-architecture (i686 and x86_64).
 
+IOVA Mode Detection
+~~~~~~~~~~~~~~~~~~~
+
+IOVA Mode is selected by considering what the current usable Devices on the
+system require and/or support.
+
+Below is the 2-step heuristic for this choice.
+
+For the first step, EAL asks each bus its requirement in terms of IOVA mode
+and decides on a preferred IOVA mode.
+
+- if all buses report RTE_IOVA_PA, then the preferred IOVA mode is RTE_IOVA_PA,
+- if all buses report RTE_IOVA_VA, then the preferred IOVA mode is RTE_IOVA_VA,
+- if all buses report RTE_IOVA_DC, no bus expressed a preferrence, then the
+  preferred mode is RTE_IOVA_DC,
+- if the buses disagree (at least one wants RTE_IOVA_PA and at least one wants
+  RTE_IOVA_VA), then the preferred IOVA mode is RTE_IOVA_DC (see below with the
+  check on Physical Addresses availability),
+
+The second step checks if the preferred mode complies with the Physical
+Addresses availability since those are only available to root user in recent
+kernels.
+
+- if the preferred mode is RTE_IOVA_PA but there is no access to Physical
+  Addresses, then EAL init fails early, since later probing of the devices
+  would fail anyway,
+- if the preferred mode is RTE_IOVA_DC then based on the Physical Addresses
+  availability, the preferred mode is adjusted to RTE_IOVA_PA or RTE_IOVA_VA.
+  In the case when the buses had disagreed on the IOVA Mode at the first step,
+  part of the buses won't work because of this decision.
+
 IOVA Mode Configuration
 ~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index b12f10a..1a2f99b 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -578,12 +578,10 @@  enum rte_iova_mode
 			else
 				is_vfio_noiommu_enabled = 0;
 		}
-		if ((pdrv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) == 0) {
+		if (is_vfio_noiommu_enabled != 0)
 			iova_mode = RTE_IOVA_PA;
-		} else if (is_vfio_noiommu_enabled != 0) {
-			RTE_LOG(DEBUG, EAL, "Forcing to 'PA', vfio-noiommu mode configured\n");
-			iova_mode = RTE_IOVA_PA;
-		}
+		else if ((pdrv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) != 0)
+			iova_mode = RTE_IOVA_VA;
 #endif
 		break;
 	}
@@ -594,8 +592,8 @@  enum rte_iova_mode
 		break;
 
 	default:
-		RTE_LOG(DEBUG, EAL, "Unsupported kernel driver? Defaulting to IOVA as 'PA'\n");
-		iova_mode = RTE_IOVA_PA;
+		if ((pdrv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) != 0)
+			iova_mode = RTE_IOVA_VA;
 		break;
 	}
 
@@ -607,10 +605,8 @@  enum rte_iova_mode
 		if (iommu_no_va == -1)
 			iommu_no_va = pci_one_device_iommu_support_va(pdev)
 					? 0 : 1;
-		if (iommu_no_va != 0) {
-			RTE_LOG(DEBUG, EAL, "Forcing to 'PA', IOMMU does not support IOVA as 'VA'\n");
+		if (iommu_no_va != 0)
 			iova_mode = RTE_IOVA_PA;
-		}
 	}
 	return iova_mode;
 }
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index d2af472..9794552 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -169,8 +169,22 @@  static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
 	 * This needs to be before rte_pci_map_device(), as it enables to use
 	 * driver flags for adjusting configuration.
 	 */
-	if (!already_probed)
+	if (!already_probed) {
+		enum rte_iova_mode dev_iova_mode;
+		enum rte_iova_mode iova_mode;
+
+		dev_iova_mode = pci_device_iova_mode(dr, dev);
+		iova_mode = rte_eal_iova_mode();
+		if (dev_iova_mode != RTE_IOVA_DC &&
+		    dev_iova_mode != iova_mode) {
+			RTE_LOG(ERR, EAL, "  Expecting '%s' IOVA mode but current mode is '%s', not initializing\n",
+				dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA",
+				iova_mode == RTE_IOVA_PA ? "PA" : "VA");
+			return -EINVAL;
+		}
+
 		dev->driver = dr;
+	}
 
 	if (!already_probed && (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)) {
 		/* map resources for devices that use igb_uio */
@@ -629,12 +643,16 @@  enum rte_iova_mode
 				devices_want_va = true;
 		}
 	}
-	if (devices_want_pa) {
-		iova_mode = RTE_IOVA_PA;
-		if (devices_want_va)
-			RTE_LOG(WARNING, EAL, "Some devices want 'VA' but forcing 'PA' because other devices want it\n");
-	} else if (devices_want_va) {
+	if (devices_want_va && !devices_want_pa) {
 		iova_mode = RTE_IOVA_VA;
+	} else if (devices_want_pa && !devices_want_va) {
+		iova_mode = RTE_IOVA_PA;
+	} else {
+		iova_mode = RTE_IOVA_DC;
+		if (devices_want_va) {
+			RTE_LOG(WARNING, EAL, "Some devices want 'VA' but forcing 'DC' because other devices want 'PA'.\n");
+			RTE_LOG(WARNING, EAL, "Depending on the final decision by the EAL, not all devices may be able to initialize.\n");
+		}
 	}
 	return iova_mode;
 }
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 06e004c..0f21775 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -187,8 +187,8 @@  struct rte_pci_bus {
 #define RTE_PCI_DRV_INTR_RMV 0x0010
 /** Device driver needs to keep mapped resources if unsupported dev detected */
 #define RTE_PCI_DRV_KEEP_MAPPED_RES 0x0020
-/** Device driver supports IOVA as VA */
-#define RTE_PCI_DRV_IOVA_AS_VA 0X0040
+/** Device driver only supports IOVA as VA and cannot work with IOVA as PA */
+#define RTE_PCI_DRV_IOVA_AS_VA 0x0040
 
 /**
  * Map the PCI device resources in user space virtual memory address
diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index fdc0a7f..fa89ae7 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -157,8 +157,7 @@  static void atl_dev_info_get(struct rte_eth_dev *dev,
 
 static struct rte_pci_driver rte_atl_pmd = {
 	.id_table = pci_id_atl_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_atl_pci_probe,
 	.remove = eth_atl_pci_remove,
 };
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 8fc5103..9306d56 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -4028,8 +4028,7 @@  static int bnxt_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver bnxt_rte_pmd = {
 	.id_table = bnxt_pci_id_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING |
-		RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = bnxt_pci_probe,
 	.remove = bnxt_pci_remove,
 };
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index dc88661..0c859e5 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -352,8 +352,7 @@  static int eth_em_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_em_pmd = {
 	.id_table = pci_id_em_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_em_pci_probe,
 	.remove = eth_em_pci_remove,
 };
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 3ee28cf..e784eeb 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -1116,8 +1116,7 @@  static int eth_igb_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_igb_pmd = {
 	.id_table = pci_id_igb_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_igb_pci_probe,
 	.remove = eth_igb_pci_remove,
 };
@@ -1140,7 +1139,7 @@  static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
  */
 static struct rte_pci_driver rte_igbvf_pmd = {
 	.id_table = pci_id_igbvf_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 	.probe = eth_igbvf_pci_probe,
 	.remove = eth_igbvf_pci_remove,
 };
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index 5cfbd31..e9c6f83 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -1247,8 +1247,7 @@  static int eth_enic_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_enic_pmd = {
 	.id_table = pci_id_enic_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_enic_pci_probe,
 	.remove = eth_enic_pci_remove,
 };
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index a1e3836..2d3c477 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -3268,8 +3268,7 @@  static int eth_fm10k_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_pmd_fm10k = {
 	.id_table = pci_id_fm10k_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_fm10k_pci_probe,
 	.remove = eth_fm10k_pci_remove,
 };
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2b9fc45..dd46d4d 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -696,8 +696,7 @@  static int eth_i40e_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_i40e_pmd = {
 	.id_table = pci_id_i40e_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_i40e_pci_probe,
 	.remove = eth_i40e_pci_remove,
 };
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index 5be32b0..3ff2f60 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -1557,7 +1557,7 @@  static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
  */
 static struct rte_pci_driver rte_i40evf_pmd = {
 	.id_table = pci_id_i40evf_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 	.probe = eth_i40evf_pci_probe,
 	.remove = eth_i40evf_pci_remove,
 };
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 53dc05c..a97cd76 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1402,8 +1402,7 @@  static int eth_iavf_pci_remove(struct rte_pci_device *pci_dev)
 /* Adaptive virtual function driver struct */
 static struct rte_pci_driver rte_iavf_pmd = {
 	.id_table = pci_id_iavf_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_iavf_pci_probe,
 	.remove = eth_iavf_pci_remove,
 };
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 9ce730c..f05b48c 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -3737,8 +3737,7 @@  static int ice_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
 static struct rte_pci_driver rte_ice_pmd = {
 	.id_table = pci_id_ice_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = ice_pci_probe,
 	.remove = ice_pci_remove,
 };
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 22c5b2c..4a6e5c3 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1869,8 +1869,7 @@  static int eth_ixgbe_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_ixgbe_pmd = {
 	.id_table = pci_id_ixgbe_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_ixgbe_pci_probe,
 	.remove = eth_ixgbe_pci_remove,
 };
@@ -1892,7 +1891,7 @@  static int eth_ixgbevf_pci_remove(struct rte_pci_device *pci_dev)
  */
 static struct rte_pci_driver rte_ixgbevf_pmd = {
 	.id_table = pci_id_ixgbevf_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
 	.probe = eth_ixgbevf_pci_probe,
 	.remove = eth_ixgbevf_pci_remove,
 };
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 2e169b0..d6e5753 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -1142,8 +1142,7 @@  struct mlx4_conf {
 	},
 	.id_table = mlx4_pci_id_map,
 	.probe = mlx4_pci_probe,
-	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
 };
 
 #ifdef RTE_IBVERBS_LINK_DLOPEN
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index d93f92d..0f05853 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2087,7 +2087,7 @@  struct mlx5_dev_spawn_data {
 	.dma_map = mlx5_dma_map,
 	.dma_unmap = mlx5_dma_unmap,
 	.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV |
-		     RTE_PCI_DRV_PROBE_AGAIN | RTE_PCI_DRV_IOVA_AS_VA,
+		     RTE_PCI_DRV_PROBE_AGAIN,
 };
 
 #ifdef RTE_IBVERBS_LINK_DLOPEN
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 1a7aa17..f5d33ef 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -3760,16 +3760,14 @@  static int eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_nfp_net_pf_pmd = {
 	.id_table = pci_id_nfp_pf_net_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = nfp_pf_pci_probe,
 	.remove = eth_nfp_pci_remove,
 };
 
 static struct rte_pci_driver rte_nfp_net_vf_pmd = {
 	.id_table = pci_id_nfp_vf_net_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_nfp_pci_probe,
 	.remove = eth_nfp_pci_remove,
 };
diff --git a/drivers/net/octeontx2/otx2_ethdev.c b/drivers/net/octeontx2/otx2_ethdev.c
index fcb1869..5ec5551 100644
--- a/drivers/net/octeontx2/otx2_ethdev.c
+++ b/drivers/net/octeontx2/otx2_ethdev.c
@@ -1188,11 +1188,6 @@ 
 		goto fail;
 	}
 
-	if (rte_eal_iova_mode() != RTE_IOVA_VA) {
-		otx2_err("iova mode should be va");
-		goto fail;
-	}
-
 	if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
 		otx2_err("Setting link speed/duplex not supported");
 		goto fail;
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 82363e6..0b3046a 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -2737,8 +2737,7 @@  static int qedevf_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_qedevf_pmd = {
 	.id_table = pci_id_qedevf_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = qedevf_eth_dev_pci_probe,
 	.remove = qedevf_eth_dev_pci_remove,
 };
@@ -2757,8 +2756,7 @@  static int qede_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_qede_pmd = {
 	.id_table = pci_id_qede_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = qede_eth_dev_pci_probe,
 	.remove = qede_eth_dev_pci_remove,
 };
diff --git a/drivers/raw/ioat/ioat_rawdev.c b/drivers/raw/ioat/ioat_rawdev.c
index d509b66..7270ad7 100644
--- a/drivers/raw/ioat/ioat_rawdev.c
+++ b/drivers/raw/ioat/ioat_rawdev.c
@@ -338,8 +338,7 @@ 
 
 static struct rte_pci_driver ioat_pmd_drv = {
 	.id_table = pci_id_ioat_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-		     RTE_PCI_DRV_IOVA_AS_VA,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = ioat_rawdev_probe,
 	.remove = ioat_rawdev_remove,
 };
diff --git a/lib/librte_eal/common/eal_common_bus.c b/lib/librte_eal/common/eal_common_bus.c
index 77f1be1..0459048 100644
--- a/lib/librte_eal/common/eal_common_bus.c
+++ b/lib/librte_eal/common/eal_common_bus.c
@@ -228,13 +228,37 @@  struct rte_bus *
 enum rte_iova_mode
 rte_bus_get_iommu_class(void)
 {
-	int mode = RTE_IOVA_DC;
+	enum rte_iova_mode mode = RTE_IOVA_DC;
+	bool buses_want_va = false;
+	bool buses_want_pa = false;
 	struct rte_bus *bus;
 
 	TAILQ_FOREACH(bus, &rte_bus_list, next) {
+		enum rte_iova_mode bus_iova_mode;
 
-		if (bus->get_iommu_class)
-			mode |= bus->get_iommu_class();
+		if (bus->get_iommu_class == NULL)
+			continue;
+
+		bus_iova_mode = bus->get_iommu_class();
+		RTE_LOG(DEBUG, EAL, "Bus %s wants IOVA as '%s'\n",
+			bus->name,
+			bus_iova_mode == RTE_IOVA_DC ? "DC" :
+			(bus_iova_mode == RTE_IOVA_PA ? "PA" : "VA"));
+		if (bus_iova_mode == RTE_IOVA_PA)
+			buses_want_pa = true;
+		else if (bus_iova_mode == RTE_IOVA_VA)
+			buses_want_va = true;
+	}
+	if (buses_want_va && !buses_want_pa) {
+		mode = RTE_IOVA_VA;
+	} else if (buses_want_pa && !buses_want_va) {
+		mode = RTE_IOVA_PA;
+	} else {
+		mode = RTE_IOVA_DC;
+		if (buses_want_va) {
+			RTE_LOG(WARNING, EAL, "Some buses want 'VA' but forcing 'DC' because other buses want 'PA'.\n");
+			RTE_LOG(WARNING, EAL, "Depending on the final decision by the EAL, not all buses may be able to initialize.\n");
+		}
 	}
 
 	return mode;