Re: [PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-11 Thread Christoph Hellwig
On Fri, Sep 11, 2020 at 05:12:36PM +0100, Robin Murphy wrote:
> (apologies to Jim - I did look through one of the previous versions since I 
> last commented and thought it looked OK, but never actually replied as 
> such)
>
> On 2020-09-10 06:40, Christoph Hellwig wrote:
>> From: Jim Quinlan 
>>
>> The new field 'dma_range_map' in struct device is used to facilitate the
>> use of single or multiple offsets between mapping regions of cpu addrs and
>> dma addrs.  It subsumes the role of "dev->dma_pfn_offset" which was only
>> capable of holding a single uniform offset and had no region bounds
>> checking.
>>
>> The function of_dma_get_range() has been modified so that it takes a single
>> argument -- the device node -- and returns a map, NULL, or an error code.
>> The map is an array that holds the information regarding the DMA regions.
>> Each range entry contains the address offset, the cpu_start address, the
>> dma_start address, and the size of the region.
>>
>> of_dma_configure() is the typical manner to set range offsets but there are
>> a number of ad hoc assignments to "dev->dma_pfn_offset" in the kernel
>> driver code.  These cases now invoke the function
>> dma_attach_offset_range(dev, cpu_addr, dma_addr, size).
>
> This is now called dma_direct_set_offset(), right?

Yes.

>> +int ret = dma_direct_set_offset(dev, KEYSTONE_HIGH_PHYS_START,
>> +KEYSTONE_LOW_PHYS_START,
>> +KEYSTONE_HIGH_PHYS_SIZE);
>> +dev_err(dev, "set dma_offset%08llx%s\n",
>> +KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START,
>> +ret ? " failed" : "");
>
> FWIW I've already been thinking of some optimisations which would have the 
> happy side-effect of removing many of these allocation failure scenarios, 
> but at this point I reckon it's more practical to just get the current 
> implementation landed and working.

Given that no one deals or can easily deal with these failures we
should probably take care of that.  IMHO we could just allocate a
single static range and point all the devices to it, what would
you think of that?

>>   @@ -811,8 +812,13 @@ static int sun4i_backend_bind(struct device *dev, 
>> struct device *master,
>>   * because of an old DT, we need to set the DMA offset by hand
>>   * on our device since the RAM mapping is at 0 for the DMA bus,
>>   * unlike the CPU.
>> + *
>> + * XXX(hch): this has no business in a driver and needs to move
>> + * to the device tree.
>
> As the context implies, this has actually grown a proper DT description of 
> the funky interconnect layout (see 564d6fd611f9 and the linked patch 
> series), and this is just an ugly fallback path to prevent regressions with 
> old DTBs that are already out there. So unless you can fire up the time 
> machine to fix those, this extra comment is really just beating a dead 
> horse :(

Well, I need to beat the dead horse to avoid having to export the
function, which will really just bread new users.  So at the minimum
we'd need to move the setup to platform code that is always built in.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-11 Thread Robin Murphy
(apologies to Jim - I did look through one of the previous versions 
since I last commented and thought it looked OK, but never actually 
replied as such)


On 2020-09-10 06:40, Christoph Hellwig wrote:

From: Jim Quinlan 

The new field 'dma_range_map' in struct device is used to facilitate the
use of single or multiple offsets between mapping regions of cpu addrs and
dma addrs.  It subsumes the role of "dev->dma_pfn_offset" which was only
capable of holding a single uniform offset and had no region bounds
checking.

The function of_dma_get_range() has been modified so that it takes a single
argument -- the device node -- and returns a map, NULL, or an error code.
The map is an array that holds the information regarding the DMA regions.
Each range entry contains the address offset, the cpu_start address, the
dma_start address, and the size of the region.

of_dma_configure() is the typical manner to set range offsets but there are
a number of ad hoc assignments to "dev->dma_pfn_offset" in the kernel
driver code.  These cases now invoke the function
dma_attach_offset_range(dev, cpu_addr, dma_addr, size).


This is now called dma_direct_set_offset(), right?


Signed-off-by: Jim Quinlan 
[hch: various interface cleanups]
Signed-off-by: Christoph Hellwig 
Tested-by: Nathan Chancellor 
---
  arch/arm/include/asm/dma-direct.h |  9 +--
  arch/arm/mach-keystone/keystone.c | 17 ++--
  arch/sh/drivers/pci/pcie-sh7786.c |  9 ++-
  arch/x86/pci/sta2x11-fixup.c  |  6 +-
  drivers/acpi/arm64/iort.c |  6 +-
  drivers/base/core.c   |  2 +
  drivers/gpu/drm/sun4i/sun4i_backend.c |  8 +-
  drivers/iommu/io-pgtable-arm.c|  2 +-
  .../platform/sunxi/sun4i-csi/sun4i_csi.c  |  9 ++-
  .../platform/sunxi/sun6i-csi/sun6i_csi.c  | 11 ++-
  drivers/of/address.c  | 73 -
  drivers/of/device.c   | 44 ++
  drivers/of/of_private.h   | 11 +--
  drivers/of/unittest.c | 34 +---
  drivers/remoteproc/remoteproc_core.c  |  4 +-
  .../staging/media/sunxi/cedrus/cedrus_hw.c| 10 ++-
  drivers/usb/core/message.c|  5 +-
  drivers/usb/core/usb.c|  3 +-
  include/linux/device.h|  4 +-
  include/linux/dma-direct.h| 52 ++--
  include/linux/dma-mapping.h   | 19 -
  kernel/dma/coherent.c |  7 +-
  kernel/dma/direct.c   | 81 ++-
  23 files changed, 303 insertions(+), 123 deletions(-)

diff --git a/arch/arm/include/asm/dma-direct.h 
b/arch/arm/include/asm/dma-direct.h
index de0f4ff9279615..a443d5257a21ed 100644
--- a/arch/arm/include/asm/dma-direct.h
+++ b/arch/arm/include/asm/dma-direct.h
@@ -16,8 +16,8 @@
  #ifndef __arch_pfn_to_dma
  static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
  {
-   if (dev)
-   pfn -= dev->dma_pfn_offset;
+   if (dev && dev->dma_range_map)
+   pfn = PFN_DOWN(translate_phys_to_dma(dev, PFN_PHYS(pfn)));
return (dma_addr_t)__pfn_to_bus(pfn);
  }
  
@@ -25,9 +25,8 @@ static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)

  {
unsigned long pfn = __bus_to_pfn(addr);
  
-	if (dev)

-   pfn += dev->dma_pfn_offset;
-
+   if (dev && dev->dma_range_map)
+   pfn = PFN_DOWN(translate_dma_to_phys(dev, PFN_PHYS(pfn)));
return pfn;
  }
  
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c

index dcd031ba84c2e0..09a65c2dfd7327 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -8,6 +8,7 @@
   */
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -25,8 +26,6 @@
  #include "keystone.h"
  
  #ifdef CONFIG_ARM_LPAE

-static unsigned long keystone_dma_pfn_offset __read_mostly;
-
  static int keystone_platform_notifier(struct notifier_block *nb,
  unsigned long event, void *data)
  {
@@ -39,9 +38,12 @@ static int keystone_platform_notifier(struct notifier_block 
*nb,
return NOTIFY_BAD;
  
  	if (!dev->of_node) {

-   dev->dma_pfn_offset = keystone_dma_pfn_offset;
-   dev_err(dev, "set dma_pfn_offset%08lx\n",
-   dev->dma_pfn_offset);
+   int ret = dma_direct_set_offset(dev, KEYSTONE_HIGH_PHYS_START,
+   KEYSTONE_LOW_PHYS_START,
+   KEYSTONE_HIGH_PHYS_SIZE);
+   dev_err(dev, "set dma_offset%08llx%s\n",
+   KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START,
+   ret ? " failed" : "");


FWIW I've already been thinking of some optimisations which would have

Re: [PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-10 Thread Greg KH
On Thu, Sep 10, 2020 at 11:13:51AM +0200, Christoph Hellwig wrote:
> On Thu, Sep 10, 2020 at 09:53:51AM +0200, Greg KH wrote:
> > >   /*
> > >* Please refer to usb_alloc_dev() to see why we set
> > > -  * dma_mask and dma_pfn_offset.
> > > +  * dma_mask and dma_range_map.
> > >*/
> > >   intf->dev.dma_mask = dev->dev.dma_mask;
> > > - intf->dev.dma_pfn_offset = dev->dev.dma_pfn_offset;
> > > + if (dma_direct_copy_range_map(&intf->dev, &dev->dev))
> > > + dev_err(&dev->dev, "failed to copy DMA map\n");
> > 
> > We tell the user, but then just keep on running?  Is there anything that
> > we can do here?
> > 
> > If not, why not have dma_direct_copy_range_map() print out the error?
> 
> At least for USB I'm pretty sure this isn't required at all.  I've been
> running with the patch below on my desktop for two days now trying all
> the usb toys I have (in addition to grepping for obvious abuses in
> the drivers).  remoteproc is a different story, but the DMA handling
> seems there is sketchy to start with..
> 
> ---
> >From 8bae3e6833f2ca431dcfcbc8f9cced7d5e972a01 Mon Sep 17 00:00:00 2001
> From: Christoph Hellwig 
> Date: Wed, 9 Sep 2020 08:28:59 +0200
> Subject: usb: don't inherity DMA properties for USB devices
> 
> As the comment in usb_alloc_dev correctly states, drivers can't use
> the DMA API on usb device, and at least calling dma_set_mask on them
> is highly dangerous.  Unlike what the comment states upper level drivers
> also can't really use the presence of a dma mask to check for DMA
> support, as the dma_mask is set by default for most busses.
> 
> Remove the copying over of DMA information, and remove the now unused
> dma_direct_copy_range_map export.
> 
> Signed-off-by: Christoph Hellwig 
> ---
>  drivers/usb/core/message.c |  7 ---
>  drivers/usb/core/usb.c | 13 -
>  kernel/dma/direct.c|  1 -
>  3 files changed, 21 deletions(-)
> 
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 935ee98e049f65..9e45732dc1d1d1 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -1954,13 +1954,6 @@ int usb_set_configuration(struct usb_device *dev, int 
> configuration)
>   intf->dev.bus = &usb_bus_type;
>   intf->dev.type = &usb_if_device_type;
>   intf->dev.groups = usb_interface_groups;
> - /*
> -  * Please refer to usb_alloc_dev() to see why we set
> -  * dma_mask and dma_range_map.
> -  */
> - intf->dev.dma_mask = dev->dev.dma_mask;
> - if (dma_direct_copy_range_map(&intf->dev, &dev->dev))
> - dev_err(&dev->dev, "failed to copy DMA map\n");
>   INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
>   intf->minor = -1;
>   device_initialize(&intf->dev);
> diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
> index 23d451f6894d70..9b4ac4415f1a47 100644
> --- a/drivers/usb/core/usb.c
> +++ b/drivers/usb/core/usb.c
> @@ -599,19 +599,6 @@ struct usb_device *usb_alloc_dev(struct usb_device 
> *parent,
>   dev->dev.bus = &usb_bus_type;
>   dev->dev.type = &usb_device_type;
>   dev->dev.groups = usb_device_groups;
> - /*
> -  * Fake a dma_mask/offset for the USB device:
> -  * We cannot really use the dma-mapping API (dma_alloc_* and
> -  * dma_map_*) for USB devices but instead need to use
> -  * usb_alloc_coherent and pass data in 'urb's, but some subsystems
> -  * manually look into the mask/offset pair to determine whether
> -  * they need bounce buffers.
> -  * Note: calling dma_set_mask() on a USB device would set the
> -  * mask for the entire HCD, so don't do that.
> -  */
> - dev->dev.dma_mask = bus->sysdev->dma_mask;
> - if (dma_direct_copy_range_map(&dev->dev, bus->sysdev))
> - dev_err(&dev->dev, "failed to copy DMA map\n");
>   set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
>   dev->state = USB_STATE_ATTACHED;
>   dev->lpm_disable_count = 1;
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index fc815f7375e282..3af257571a3b42 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -552,4 +552,3 @@ int dma_direct_copy_range_map(struct device *to, struct 
> device *from)
>   to->dma_range_map = new_map;
>   return 0;
>  }
> -EXPORT_SYMBOL_GPL(dma_direct_copy_range_map);

If you think this is safe to do, great, but for some reason I thought
host controllers wanted this information, and that the scsi layer was
the offending layer that also wanted this type of thing.  But it's been
a really long time so I don't remember for sure, sorry.

thanks,

greg k-h
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-10 Thread Christoph Hellwig
On Thu, Sep 10, 2020 at 09:53:51AM +0200, Greg KH wrote:
> > /*
> >  * Please refer to usb_alloc_dev() to see why we set
> > -* dma_mask and dma_pfn_offset.
> > +* dma_mask and dma_range_map.
> >  */
> > intf->dev.dma_mask = dev->dev.dma_mask;
> > -   intf->dev.dma_pfn_offset = dev->dev.dma_pfn_offset;
> > +   if (dma_direct_copy_range_map(&intf->dev, &dev->dev))
> > +   dev_err(&dev->dev, "failed to copy DMA map\n");
> 
> We tell the user, but then just keep on running?  Is there anything that
> we can do here?
> 
> If not, why not have dma_direct_copy_range_map() print out the error?

At least for USB I'm pretty sure this isn't required at all.  I've been
running with the patch below on my desktop for two days now trying all
the usb toys I have (in addition to grepping for obvious abuses in
the drivers).  remoteproc is a different story, but the DMA handling
seems there is sketchy to start with..

---
>From 8bae3e6833f2ca431dcfcbc8f9cced7d5e972a01 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig 
Date: Wed, 9 Sep 2020 08:28:59 +0200
Subject: usb: don't inherity DMA properties for USB devices

As the comment in usb_alloc_dev correctly states, drivers can't use
the DMA API on usb device, and at least calling dma_set_mask on them
is highly dangerous.  Unlike what the comment states upper level drivers
also can't really use the presence of a dma mask to check for DMA
support, as the dma_mask is set by default for most busses.

Remove the copying over of DMA information, and remove the now unused
dma_direct_copy_range_map export.

Signed-off-by: Christoph Hellwig 
---
 drivers/usb/core/message.c |  7 ---
 drivers/usb/core/usb.c | 13 -
 kernel/dma/direct.c|  1 -
 3 files changed, 21 deletions(-)

diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 935ee98e049f65..9e45732dc1d1d1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1954,13 +1954,6 @@ int usb_set_configuration(struct usb_device *dev, int 
configuration)
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;
-   /*
-* Please refer to usb_alloc_dev() to see why we set
-* dma_mask and dma_range_map.
-*/
-   intf->dev.dma_mask = dev->dev.dma_mask;
-   if (dma_direct_copy_range_map(&intf->dev, &dev->dev))
-   dev_err(&dev->dev, "failed to copy DMA map\n");
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
intf->minor = -1;
device_initialize(&intf->dev);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 23d451f6894d70..9b4ac4415f1a47 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -599,19 +599,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;
-   /*
-* Fake a dma_mask/offset for the USB device:
-* We cannot really use the dma-mapping API (dma_alloc_* and
-* dma_map_*) for USB devices but instead need to use
-* usb_alloc_coherent and pass data in 'urb's, but some subsystems
-* manually look into the mask/offset pair to determine whether
-* they need bounce buffers.
-* Note: calling dma_set_mask() on a USB device would set the
-* mask for the entire HCD, so don't do that.
-*/
-   dev->dev.dma_mask = bus->sysdev->dma_mask;
-   if (dma_direct_copy_range_map(&dev->dev, bus->sysdev))
-   dev_err(&dev->dev, "failed to copy DMA map\n");
set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
dev->state = USB_STATE_ATTACHED;
dev->lpm_disable_count = 1;
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index fc815f7375e282..3af257571a3b42 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -552,4 +552,3 @@ int dma_direct_copy_range_map(struct device *to, struct 
device *from)
to->dma_range_map = new_map;
return 0;
 }
-EXPORT_SYMBOL_GPL(dma_direct_copy_range_map);
-- 
2.28.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-10 Thread Greg KH
On Thu, Sep 10, 2020 at 07:40:38AM +0200, Christoph Hellwig wrote:
> From: Jim Quinlan 
> 
> The new field 'dma_range_map' in struct device is used to facilitate the
> use of single or multiple offsets between mapping regions of cpu addrs and
> dma addrs.  It subsumes the role of "dev->dma_pfn_offset" which was only
> capable of holding a single uniform offset and had no region bounds
> checking.
> 
> The function of_dma_get_range() has been modified so that it takes a single
> argument -- the device node -- and returns a map, NULL, or an error code.
> The map is an array that holds the information regarding the DMA regions.
> Each range entry contains the address offset, the cpu_start address, the
> dma_start address, and the size of the region.
> 
> of_dma_configure() is the typical manner to set range offsets but there are
> a number of ad hoc assignments to "dev->dma_pfn_offset" in the kernel
> driver code.  These cases now invoke the function
> dma_attach_offset_range(dev, cpu_addr, dma_addr, size).

So if an error happens, we don't do anything?

ice_init(dev->dev);
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 6197938dcc2d8f..935ee98e049f65 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -1956,10 +1956,11 @@ int usb_set_configuration(struct usb_device *dev, int 
> configuration)
>   intf->dev.groups = usb_interface_groups;
>   /*
>* Please refer to usb_alloc_dev() to see why we set
> -  * dma_mask and dma_pfn_offset.
> +  * dma_mask and dma_range_map.
>*/
>   intf->dev.dma_mask = dev->dev.dma_mask;
> - intf->dev.dma_pfn_offset = dev->dev.dma_pfn_offset;
> + if (dma_direct_copy_range_map(&intf->dev, &dev->dev))
> + dev_err(&dev->dev, "failed to copy DMA map\n");

We tell the user, but then just keep on running?  Is there anything that
we can do here?

If not, why not have dma_direct_copy_range_map() print out the error?

thanks,

greg k-h
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 3/3] dma-mapping: introduce DMA range map, supplanting dma_pfn_offset

2020-09-09 Thread Christoph Hellwig
From: Jim Quinlan 

The new field 'dma_range_map' in struct device is used to facilitate the
use of single or multiple offsets between mapping regions of cpu addrs and
dma addrs.  It subsumes the role of "dev->dma_pfn_offset" which was only
capable of holding a single uniform offset and had no region bounds
checking.

The function of_dma_get_range() has been modified so that it takes a single
argument -- the device node -- and returns a map, NULL, or an error code.
The map is an array that holds the information regarding the DMA regions.
Each range entry contains the address offset, the cpu_start address, the
dma_start address, and the size of the region.

of_dma_configure() is the typical manner to set range offsets but there are
a number of ad hoc assignments to "dev->dma_pfn_offset" in the kernel
driver code.  These cases now invoke the function
dma_attach_offset_range(dev, cpu_addr, dma_addr, size).

Signed-off-by: Jim Quinlan 
[hch: various interface cleanups]
Signed-off-by: Christoph Hellwig 
Tested-by: Nathan Chancellor 
---
 arch/arm/include/asm/dma-direct.h |  9 +--
 arch/arm/mach-keystone/keystone.c | 17 ++--
 arch/sh/drivers/pci/pcie-sh7786.c |  9 ++-
 arch/x86/pci/sta2x11-fixup.c  |  6 +-
 drivers/acpi/arm64/iort.c |  6 +-
 drivers/base/core.c   |  2 +
 drivers/gpu/drm/sun4i/sun4i_backend.c |  8 +-
 drivers/iommu/io-pgtable-arm.c|  2 +-
 .../platform/sunxi/sun4i-csi/sun4i_csi.c  |  9 ++-
 .../platform/sunxi/sun6i-csi/sun6i_csi.c  | 11 ++-
 drivers/of/address.c  | 73 -
 drivers/of/device.c   | 44 ++
 drivers/of/of_private.h   | 11 +--
 drivers/of/unittest.c | 34 +---
 drivers/remoteproc/remoteproc_core.c  |  4 +-
 .../staging/media/sunxi/cedrus/cedrus_hw.c| 10 ++-
 drivers/usb/core/message.c|  5 +-
 drivers/usb/core/usb.c|  3 +-
 include/linux/device.h|  4 +-
 include/linux/dma-direct.h| 52 ++--
 include/linux/dma-mapping.h   | 19 -
 kernel/dma/coherent.c |  7 +-
 kernel/dma/direct.c   | 81 ++-
 23 files changed, 303 insertions(+), 123 deletions(-)

diff --git a/arch/arm/include/asm/dma-direct.h 
b/arch/arm/include/asm/dma-direct.h
index de0f4ff9279615..a443d5257a21ed 100644
--- a/arch/arm/include/asm/dma-direct.h
+++ b/arch/arm/include/asm/dma-direct.h
@@ -16,8 +16,8 @@
 #ifndef __arch_pfn_to_dma
 static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
 {
-   if (dev)
-   pfn -= dev->dma_pfn_offset;
+   if (dev && dev->dma_range_map)
+   pfn = PFN_DOWN(translate_phys_to_dma(dev, PFN_PHYS(pfn)));
return (dma_addr_t)__pfn_to_bus(pfn);
 }
 
@@ -25,9 +25,8 @@ static inline unsigned long dma_to_pfn(struct device *dev, 
dma_addr_t addr)
 {
unsigned long pfn = __bus_to_pfn(addr);
 
-   if (dev)
-   pfn += dev->dma_pfn_offset;
-
+   if (dev && dev->dma_range_map)
+   pfn = PFN_DOWN(translate_dma_to_phys(dev, PFN_PHYS(pfn)));
return pfn;
 }
 
diff --git a/arch/arm/mach-keystone/keystone.c 
b/arch/arm/mach-keystone/keystone.c
index dcd031ba84c2e0..09a65c2dfd7327 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -8,6 +8,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -25,8 +26,6 @@
 #include "keystone.h"
 
 #ifdef CONFIG_ARM_LPAE
-static unsigned long keystone_dma_pfn_offset __read_mostly;
-
 static int keystone_platform_notifier(struct notifier_block *nb,
  unsigned long event, void *data)
 {
@@ -39,9 +38,12 @@ static int keystone_platform_notifier(struct notifier_block 
*nb,
return NOTIFY_BAD;
 
if (!dev->of_node) {
-   dev->dma_pfn_offset = keystone_dma_pfn_offset;
-   dev_err(dev, "set dma_pfn_offset%08lx\n",
-   dev->dma_pfn_offset);
+   int ret = dma_direct_set_offset(dev, KEYSTONE_HIGH_PHYS_START,
+   KEYSTONE_LOW_PHYS_START,
+   KEYSTONE_HIGH_PHYS_SIZE);
+   dev_err(dev, "set dma_offset%08llx%s\n",
+   KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START,
+   ret ? " failed" : "");
}
return NOTIFY_OK;
 }
@@ -54,11 +56,8 @@ static struct notifier_block platform_nb = {
 static void __init keystone_init(void)
 {
 #ifdef CONFIG_ARM_LPAE
-   if (PHYS_OFFSET >= KEYSTONE_HIGH_PHYS_START) {
-   keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START -
-  KEYSTONE_LOW_