Re: [PATCH 1/2] staging: fsl-dpaa2/eth: Fix address translations

2017-05-24 Thread Laurentiu Tudor
Hi Ioana,

Debatable nit inline.

On 05/24/2017 03:13 PM, Ioana Radulescu wrote:
> Use the correct mechanisms for translating a DMA-mapped IOVA
> address into a virtual one. Without this fix, once SMMU is
> enabled on Layerscape platforms, the Ethernet driver throws
> IOMMU translation faults.
>
> Signed-off-by: Nipun Gupta 
> Signed-off-by: Ioana Radulescu 
> ---
>   drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 25 
> +++--
>   drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h |  1 +
>   2 files changed, 20 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c 
> b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
> index 6f9eed66c64d..3fee0d6f17e0 100644
> --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
> +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
> @@ -37,6 +37,7 @@
>   #include 
>   #include 
>   #include 
> +#include 
>
>   #include "../../fsl-mc/include/mc.h"
>   #include "../../fsl-mc/include/mc-sys.h"
> @@ -54,6 +55,16 @@ MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
>
>   const char dpaa2_eth_drv_version[] = "0.1";
>
> +static void *dpaa2_iova_to_virt(struct iommu_domain *domain,

if you pass a "struct dpaa2_eth_priv *priv" instead of "iommu_domain" 
you can move the priv->iommu_domain reference in the function and 
slightly simplify the call sites.

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


Re: [PATCH 1/2] staging: fsl-dpaa2/eth: Fix address translations

2017-05-29 Thread Laurentiu Tudor


On 05/25/2017 03:31 PM, Ruxandra Ioana Radulescu wrote:
>> -Original Message-
>> From: Laurentiu Tudor
>> Sent: Wednesday, May 24, 2017 3:34 PM
>> To: Ruxandra Ioana Radulescu ;
>> gre...@linuxfoundation.org
>> Cc: de...@driverdev.osuosl.org; linux-ker...@vger.kernel.org;
>> ag...@suse.de; a...@arndb.de; linux-arm-ker...@lists.infradead.org;
>> iommu@lists.linux-foundation.org; Bogdan Purcareata
>> ; stuyo...@gmail.com; Nipun Gupta
>> 
>> Subject: Re: [PATCH 1/2] staging: fsl-dpaa2/eth: Fix address translations
>>
>> Hi Ioana,
>>
>> Debatable nit inline.
>>
>> On 05/24/2017 03:13 PM, Ioana Radulescu wrote:
>>> Use the correct mechanisms for translating a DMA-mapped IOVA
>>> address into a virtual one. Without this fix, once SMMU is
>>> enabled on Layerscape platforms, the Ethernet driver throws
>>> IOMMU translation faults.
>>>
>>> Signed-off-by: Nipun Gupta 
>>> Signed-off-by: Ioana Radulescu 
>>> ---
>>>drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 25
>> +++--
>>>drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h |  1 +
>>>2 files changed, 20 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
>> b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
>>> index 6f9eed66c64d..3fee0d6f17e0 100644
>>> --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
>>> +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
>>> @@ -37,6 +37,7 @@
>>>#include 
>>>#include 
>>>#include 
>>> +#include 
>>>
>>>#include "../../fsl-mc/include/mc.h"
>>>#include "../../fsl-mc/include/mc-sys.h"
>>> @@ -54,6 +55,16 @@ MODULE_DESCRIPTION("Freescale DPAA2 Ethernet
>> Driver");
>>>
>>>const char dpaa2_eth_drv_version[] = "0.1";
>>>
>>> +static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
>>
>> if you pass a "struct dpaa2_eth_priv *priv" instead of "iommu_domain"
>> you can move the priv->iommu_domain reference in the function and
>> slightly simplify the call sites.
>
> Fair point, but I'd prefer keeping this function independent of the
> Ethernet driver's private data structure. This way, if other (future)
> DPAA2 drivers will need a similar function, we can just move it
> to a common area instead of duplicating the code.

Understood. Fine by me then.

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


[RFC PATCH] i2c: imx: dma map the i2c data i/o register

2019-01-16 Thread Laurentiu Tudor
This is an attempt to fix an iommu exception when doing dma to the
i2c controller with EDMA. Without these mappings the smmu raises a
context fault [1] exactly with the address of the i2c data i/o reg.
This was seen on an NXP LS1043A chip while working on enabling SMMU.

[1] arm-smmu 900.iommu: Unhandled context fault: fsr=0x402,
iova=0x02180004, fsynr=0x150021, cb=7

Signed-off-by: Laurentiu Tudor 
---
 drivers/i2c/busses/i2c-imx.c | 57 +---
 1 file changed, 47 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4e34b1572756..07cc8f4b45b9 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -202,6 +202,9 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
 
struct imx_i2c_dma  *dma;
+
+   dma_addr_t  dma_tx_addr;
+   dma_addr_t  dma_rx_addr;
 };
 
 static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
@@ -274,17 +277,20 @@ static inline unsigned char imx_i2c_read_reg(struct 
imx_i2c_struct *i2c_imx,
 
 /* Functions for DMA support */
 static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
-  dma_addr_t phy_addr)
+  phys_addr_t phy_addr)
 {
struct imx_i2c_dma *dma;
struct dma_slave_config dma_sconfig;
struct device *dev = &i2c_imx->adapter.dev;
int ret;
+   phys_addr_t i2dr_pa;
 
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
if (!dma)
return -ENOMEM;
 
+   i2dr_pa = phy_addr + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
+
dma->chan_tx = dma_request_chan(dev, "tx");
if (IS_ERR(dma->chan_tx)) {
ret = PTR_ERR(dma->chan_tx);
@@ -293,15 +299,25 @@ static int i2c_imx_dma_request(struct imx_i2c_struct 
*i2c_imx,
goto fail_al;
}
 
-   dma_sconfig.dst_addr = phy_addr +
-   (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
+   i2c_imx->dma_tx_addr = dma_map_resource(dma->chan_tx->device->dev,
+   i2dr_pa,
+   DMA_SLAVE_BUSWIDTH_1_BYTE,
+   DMA_MEM_TO_DEV, 0);
+   ret = dma_mapping_error(dma->chan_tx->device->dev,
+   i2c_imx->dma_tx_addr);
+   if (ret) {
+   dev_err(dev, "can't dma map tx destination (%d)\n", ret);
+   goto fail_tx;
+   }
+
+   dma_sconfig.dst_addr = i2c_imx->dma_tx_addr;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_sconfig.dst_maxburst = 1;
dma_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
if (ret < 0) {
dev_err(dev, "can't configure tx channel (%d)\n", ret);
-   goto fail_tx;
+   goto fail_tx_dma;
}
 
dma->chan_rx = dma_request_chan(dev, "rx");
@@ -309,18 +325,28 @@ static int i2c_imx_dma_request(struct imx_i2c_struct 
*i2c_imx,
ret = PTR_ERR(dma->chan_rx);
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(dev, "can't request DMA rx channel (%d)\n", 
ret);
-   goto fail_tx;
+   goto fail_tx_dma;
}
 
-   dma_sconfig.src_addr = phy_addr +
-   (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
+   i2c_imx->dma_rx_addr = dma_map_resource(dma->chan_rx->device->dev,
+   i2dr_pa,
+   DMA_SLAVE_BUSWIDTH_1_BYTE,
+   DMA_DEV_TO_MEM, 0);
+   ret = dma_mapping_error(dma->chan_rx->device->dev,
+   i2c_imx->dma_rx_addr);
+   if (ret) {
+   dev_err(dev, "can't dma map rx source (%d)\n", ret);
+   goto fail_rx;
+   }
+
+   dma_sconfig.src_addr = i2c_imx->dma_rx_addr;
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_sconfig.src_maxburst = 1;
dma_sconfig.direction = DMA_DEV_TO_MEM;
ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
if (ret < 0) {
dev_err(dev, "can't configure rx channel (%d)\n", ret);
-   goto fail_rx;
+   goto fail_rx_dma;
}
 
i2c_imx->dma = dma;
@@ -330,8 +356,14 @@ static int i2c_imx_dma_request(struct imx_i2c_struct 
*i2c_imx,
 
return 0;
 
+fail_rx_dma:
+   dma_unmap_resource(dma->chan_rx->device

Re: [RFC PATCH] i2c: imx: dma map the i2c data i/o register

2019-01-17 Thread Laurentiu Tudor
Hi Robin,

On 16.01.2019 19:55, Robin Murphy wrote:
> On 16/01/2019 16:17, Laurentiu Tudor wrote:
>> This is an attempt to fix an iommu exception when doing dma to the
>> i2c controller with EDMA. Without these mappings the smmu raises a
>> context fault [1] exactly with the address of the i2c data i/o reg.
>> This was seen on an NXP LS1043A chip while working on enabling SMMU.
> 
> Rather than gradually adding much the same code to potentially every 
> possible client driver, can it not be implemented once in the edma 
> driver as was done for pl330 and rcar-dmac? That also sidesteps any of 
> the nastiness of smuggling a dma_addr_t via a phys_addr_t variable.

Thanks for the pointer. I was actually unsure where this should be 
tackled: either i2c or dma side. Plus I somehow managed to completely 
miss the support added in the dma drivers you mention. I'll start 
looking into stealing some of your code [1]. :-)

[1] 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4d6d74e22096543cb3b35e717cf1b9aea3655f37

---
Best Regards, Laurentiu


> 
>> [1] arm-smmu 900.iommu: Unhandled context fault: fsr=0x402,
>>      iova=0x02180004, fsynr=0x150021, cb=7
>>
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>   drivers/i2c/busses/i2c-imx.c | 57 +---
>>   1 file changed, 47 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
>> index 4e34b1572756..07cc8f4b45b9 100644
>> --- a/drivers/i2c/busses/i2c-imx.c
>> +++ b/drivers/i2c/busses/i2c-imx.c
>> @@ -202,6 +202,9 @@ struct imx_i2c_struct {
>>   struct pinctrl_state *pinctrl_pins_gpio;
>>   struct imx_i2c_dma    *dma;
>> +
>> +    dma_addr_t    dma_tx_addr;
>> +    dma_addr_t    dma_rx_addr;
>>   };
>>   static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
>> @@ -274,17 +277,20 @@ static inline unsigned char 
>> imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
>>   /* Functions for DMA support */
>>   static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
>> -   dma_addr_t phy_addr)
>> +   phys_addr_t phy_addr)
>>   {
>>   struct imx_i2c_dma *dma;
>>   struct dma_slave_config dma_sconfig;
>>   struct device *dev = &i2c_imx->adapter.dev;
>>   int ret;
>> +    phys_addr_t i2dr_pa;
>>   dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
>>   if (!dma)
>>   return -ENOMEM;
>> +    i2dr_pa = phy_addr + (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
>> +
>>   dma->chan_tx = dma_request_chan(dev, "tx");
>>   if (IS_ERR(dma->chan_tx)) {
>>   ret = PTR_ERR(dma->chan_tx);
>> @@ -293,15 +299,25 @@ static int i2c_imx_dma_request(struct 
>> imx_i2c_struct *i2c_imx,
>>   goto fail_al;
>>   }
>> -    dma_sconfig.dst_addr = phy_addr +
>> -    (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
>> +    i2c_imx->dma_tx_addr = dma_map_resource(dma->chan_tx->device->dev,
>> +    i2dr_pa,
>> +    DMA_SLAVE_BUSWIDTH_1_BYTE,
>> +    DMA_MEM_TO_DEV, 0);
>> +    ret = dma_mapping_error(dma->chan_tx->device->dev,
>> +    i2c_imx->dma_tx_addr);
>> +    if (ret) {
>> +    dev_err(dev, "can't dma map tx destination (%d)\n", ret);
>> +    goto fail_tx;
>> +    }
>> +
>> +    dma_sconfig.dst_addr = i2c_imx->dma_tx_addr;
>>   dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>>   dma_sconfig.dst_maxburst = 1;
>>   dma_sconfig.direction = DMA_MEM_TO_DEV;
>>   ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
>>   if (ret < 0) {
>>   dev_err(dev, "can't configure tx channel (%d)\n", ret);
>> -    goto fail_tx;
>> +    goto fail_tx_dma;
>>   }
>>   dma->chan_rx = dma_request_chan(dev, "rx");
>> @@ -309,18 +325,28 @@ static int i2c_imx_dma_request(struct 
>> imx_i2c_struct *i2c_imx,
>>   ret = PTR_ERR(dma->chan_rx);
>>   if (ret != -ENODEV && ret != -EPROBE_DEFER)
>>   dev_err(dev, "can't request DMA rx channel (%d)\n", ret);
>> -    goto fail_tx;
>> +    goto fail_tx_dma;
>>   }
>> -    dma_sconfig.src_addr = phy_addr +
>> -    (IMX_I2C_I2DR << i2c_imx->hwdata->regshift);
>> +    i2c_imx->

[PATCH] dmaengine: fsl-edma: dma map slave device address

2019-01-18 Thread Laurentiu Tudor
This mapping needs to be created in order for slave dma transfers
to work on systems with SMMU. The implementation mostly mimics the
one in pl330 dma driver, authored by Robin Murphy.

Signed-off-by: Laurentiu Tudor 
Suggested-by: Robin Murphy 
---
Original approach was to add the missing mappings in the i2c client driver,
see here for discussion: https://patchwork.ozlabs.org/patch/1026013/

 drivers/dma/fsl-edma-common.c | 66 ---
 drivers/dma/fsl-edma-common.h |  4 +++
 drivers/dma/fsl-edma.c|  1 +
 drivers/dma/mcf-edma.c|  1 +
 4 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 8876c4c1bb2c..0e95ee24b6d4 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -6,6 +6,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "fsl-edma-common.h"
 
@@ -173,12 +174,62 @@ int fsl_edma_resume(struct dma_chan *chan)
 }
 EXPORT_SYMBOL_GPL(fsl_edma_resume);
 
+static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan)
+{
+   if (fsl_chan->dma_dir != DMA_NONE)
+   dma_unmap_resource(fsl_chan->vchan.chan.device->dev,
+  fsl_chan->dma_dev_addr,
+  fsl_chan->dma_dev_size,
+  fsl_chan->dma_dir, 0);
+   fsl_chan->dma_dir = DMA_NONE;
+}
+
+static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
+   enum dma_transfer_direction dir)
+{
+   struct device *dev = fsl_chan->vchan.chan.device->dev;
+   enum dma_data_direction dma_dir;
+   phys_addr_t addr = 0;
+   u32 size = 0;
+
+   switch (dir) {
+   case DMA_MEM_TO_DEV:
+   dma_dir = DMA_FROM_DEVICE;
+   addr = fsl_chan->cfg.dst_addr;
+   size = fsl_chan->cfg.dst_maxburst;
+   break;
+   case DMA_DEV_TO_MEM:
+   dma_dir = DMA_TO_DEVICE;
+   addr = fsl_chan->cfg.src_addr;
+   size = fsl_chan->cfg.src_maxburst;
+   break;
+   default:
+   dma_dir = DMA_NONE;
+   break;
+   }
+
+   /* Already mapped for this config? */
+   if (fsl_chan->dma_dir == dma_dir)
+   return true;
+
+   fsl_edma_unprep_slave_dma(fsl_chan);
+
+   fsl_chan->dma_dev_addr = dma_map_resource(dev, addr, size, dma_dir, 0);
+   if (dma_mapping_error(dev, fsl_chan->dma_dev_addr))
+   return false;
+   fsl_chan->dma_dev_size = size;
+   fsl_chan->dma_dir = dma_dir;
+
+   return true;
+}
+
 int fsl_edma_slave_config(struct dma_chan *chan,
 struct dma_slave_config *cfg)
 {
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
 
memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
+   fsl_edma_unprep_slave_dma(fsl_chan);
 
return 0;
 }
@@ -378,6 +429,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
if (!is_slave_direction(direction))
return NULL;
 
+   if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
+   return NULL;
+
sg_len = buf_len / period_len;
fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
if (!fsl_desc)
@@ -409,11 +463,11 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
 
if (direction == DMA_MEM_TO_DEV) {
src_addr = dma_buf_next;
-   dst_addr = fsl_chan->cfg.dst_addr;
+   dst_addr = fsl_chan->dma_dev_addr;
soff = fsl_chan->cfg.dst_addr_width;
doff = 0;
} else {
-   src_addr = fsl_chan->cfg.src_addr;
+   src_addr = fsl_chan->dma_dev_addr;
dst_addr = dma_buf_next;
soff = 0;
doff = fsl_chan->cfg.src_addr_width;
@@ -444,6 +498,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
if (!is_slave_direction(direction))
return NULL;
 
+   if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
+   return NULL;
+
fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
if (!fsl_desc)
return NULL;
@@ -468,11 +525,11 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
 
if (direction == DMA_MEM_TO_DEV) {
src_addr = sg_dma_address(sg);
-   dst_addr = fsl_chan->cfg.dst_addr;
+   dst_addr = fsl_chan->dma_dev_addr;
soff = fsl_chan->cfg.dst_addr_width;
doff = 0;
} else {
-   src_addr = fsl_chan->cfg.src_addr;
+   src_addr = fsl_chan-&

Re: [PATCH] dmaengine: fsl-edma: dma map slave device address

2019-01-21 Thread Laurentiu Tudor
Hi Angelo,

On 18.01.2019 23:50, Angelo Dureghello wrote:
> Hi Laurentiu,
> 
> On Fri, Jan 18, 2019 at 12:06:23PM +0200, Laurentiu Tudor wrote:
>> This mapping needs to be created in order for slave dma transfers
>> to work on systems with SMMU. The implementation mostly mimics the
>> one in pl330 dma driver, authored by Robin Murphy.
>>
>> Signed-off-by: Laurentiu Tudor 
>> Suggested-by: Robin Murphy 
>> ---
>> Original approach was to add the missing mappings in the i2c client driver,
>> see here for discussion: 
>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.ozlabs.org%2Fpatch%2F1026013%2F&data=02%7C01%7Claurentiu.tudor%40nxp.com%7C7861dfe95dfb4fceeb8208d67d907488%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C1%7C636834456718898365&sdata=XM5shQdcIRgFLtCmuRuFtViR6ttPDWI%2BNHXoPi68Xs8%3D&reserved=0
>>
>>   drivers/dma/fsl-edma-common.c | 66 ---
>>   drivers/dma/fsl-edma-common.h |  4 +++
>>   drivers/dma/fsl-edma.c|  1 +
>>   drivers/dma/mcf-edma.c|  1 +
>>   4 files changed, 68 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
>> index 8876c4c1bb2c..0e95ee24b6d4 100644
>> --- a/drivers/dma/fsl-edma-common.c
>> +++ b/drivers/dma/fsl-edma-common.c
>> @@ -6,6 +6,7 @@
>>   #include 
>>   #include 
>>   #include 
>> +#include 
>>   
>>   #include "fsl-edma-common.h"
>>   
>> @@ -173,12 +174,62 @@ int fsl_edma_resume(struct dma_chan *chan)
>>   }
>>   EXPORT_SYMBOL_GPL(fsl_edma_resume);
>>   
>> +static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan)
>> +{
>> +if (fsl_chan->dma_dir != DMA_NONE)
>> +dma_unmap_resource(fsl_chan->vchan.chan.device->dev,
>> +   fsl_chan->dma_dev_addr,
>> +   fsl_chan->dma_dev_size,
>> +   fsl_chan->dma_dir, 0);
>> +fsl_chan->dma_dir = DMA_NONE;
>> +}
>> +
>> +static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan,
>> +enum dma_transfer_direction dir)
>> +{
>> +struct device *dev = fsl_chan->vchan.chan.device->dev;
>> +enum dma_data_direction dma_dir;
>> +phys_addr_t addr = 0;
>> +u32 size = 0;
>> +
>> +switch (dir) {
>> +case DMA_MEM_TO_DEV:
>> +dma_dir = DMA_FROM_DEVICE;
>> +addr = fsl_chan->cfg.dst_addr;
>> +size = fsl_chan->cfg.dst_maxburst;
>> +break;
>> +case DMA_DEV_TO_MEM:
>> +dma_dir = DMA_TO_DEVICE;
>> +addr = fsl_chan->cfg.src_addr;
>> +size = fsl_chan->cfg.src_maxburst;
>> +break;
>> +default:
>> +dma_dir = DMA_NONE;
>> +break;
>> +}
>> +
>> +/* Already mapped for this config? */
>> +if (fsl_chan->dma_dir == dma_dir)
>> +return true;
>> +
>> +fsl_edma_unprep_slave_dma(fsl_chan);
>> +
>> +fsl_chan->dma_dev_addr = dma_map_resource(dev, addr, size, dma_dir, 0);
>> +if (dma_mapping_error(dev, fsl_chan->dma_dev_addr))
>> +return false;
>> +fsl_chan->dma_dev_size = size;
>> +fsl_chan->dma_dir = dma_dir;
>> +
>> +return true;
>> +}
>> +
>>   int fsl_edma_slave_config(struct dma_chan *chan,
>>   struct dma_slave_config *cfg)
>>   {
>>  struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
>>   
>>  memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
>> +fsl_edma_unprep_slave_dma(fsl_chan);
>>   
>>  return 0;
>>   }
>> @@ -378,6 +429,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
>>  if (!is_slave_direction(direction))
>>  return NULL;
>>   
>> +if (!fsl_edma_prep_slave_dma(fsl_chan, direction))
>> +return NULL;
>> +
>>  sg_len = buf_len / period_len;
>>  fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
>>  if (!fsl_desc)
>> @@ -409,11 +463,11 @@ struct dma_async_tx_descriptor 
>> *fsl_edma_prep_dma_cyclic(
>>   
>>  if (direction == DMA_MEM_TO_DEV) {
>>  src_addr = dma_buf_next;
>> -dst_addr = fsl_chan->cfg.dst_addr;
>> +dst_addr = fsl_chan->dma_dev_addr;
>>

[PATCH 11/13] dpaa_eth: fix iova handling for contiguous frames

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this by adding a function that does
proper iova -> phys conversions using the iommu api and update the code
to use it.
Also, a dma_unmap_single() call had to be moved further down the code
because iova -> vaddr conversions were required before the unmap.
For now only the contiguous frame case is handled and the SG case is
split in a following patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 44 ++-
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index cdc7e6d83f77..f17edc80dc37 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -50,6 +50,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1595,6 +1596,17 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv)
return 0;
 }
 
+static phys_addr_t dpaa_iova_to_phys(struct device *dev, dma_addr_t addr)
+{
+   struct iommu_domain *domain;
+
+   domain = iommu_get_domain_for_dev(dev);
+   if (domain)
+   return iommu_iova_to_phys(domain, addr);
+   else
+   return addr;
+}
+
 /* Cleanup function for outgoing frame descriptors that were built on Tx path,
  * either contiguous frames or scatter/gather ones.
  * Skb freeing is not handled here.
@@ -1617,7 +1629,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
int nr_frags, i;
u64 ns;
 
-   skbh = (struct sk_buff **)phys_to_virt(addr);
+   skbh = (struct sk_buff **)phys_to_virt(dpaa_iova_to_phys(dev, addr));
skb = *skbh;
 
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
@@ -1687,25 +1699,21 @@ static u8 rx_csum_offload(const struct dpaa_priv *priv, 
const struct qm_fd *fd)
  * accommodate the shared info area of the skb.
  */
 static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
-   const struct qm_fd *fd)
+   const struct qm_fd *fd,
+   struct dpaa_bp *dpaa_bp,
+   void *vaddr)
 {
ssize_t fd_off = qm_fd_get_offset(fd);
-   dma_addr_t addr = qm_fd_addr(fd);
-   struct dpaa_bp *dpaa_bp;
struct sk_buff *skb;
-   void *vaddr;
 
-   vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
 
-   dpaa_bp = dpaa_bpid2pool(fd->bpid);
-   if (!dpaa_bp)
-   goto free_buffer;
-
skb = build_skb(vaddr, dpaa_bp->size +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
-   if (WARN_ONCE(!skb, "Build skb failure on Rx\n"))
-   goto free_buffer;
+   if (WARN_ONCE(!skb, "Build skb failure on Rx\n")) {
+   skb_free_frag(vaddr);
+   return NULL;
+   }
WARN_ON(fd_off != priv->rx_headroom);
skb_reserve(skb, fd_off);
skb_put(skb, qm_fd_get_length(fd));
@@ -1713,10 +1721,6 @@ static struct sk_buff *contig_fd_to_skb(const struct 
dpaa_priv *priv,
skb->ip_summed = rx_csum_offload(priv, fd);
 
return skb;
-
-free_buffer:
-   skb_free_frag(vaddr);
-   return NULL;
 }
 
 /* Build an skb with the data of the first S/G entry in the linear portion and
@@ -2309,12 +2313,12 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct 
qman_portal *portal,
if (!dpaa_bp)
return qman_cb_dqrr_consume;
 
-   dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
-
/* prefetch the first 64 bytes of the frame or the SGT start */
-   vaddr = phys_to_virt(addr);
+   vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev, addr));
prefetch(vaddr + qm_fd_get_offset(fd));
 
+   dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
+
/* The only FD types that we may receive are contig and S/G */
WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
 
@@ -2325,7 +2329,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct 
qman_portal *portal,
(*count_ptr)--;
 
if (likely(fd_format == qm_fd_contig))
-   skb = contig_fd_to_skb(priv, fd);
+   skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
else
skb = sg_fd_to_skb(priv, fd);
if (!skb)
-- 
2.17.1

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


[PATCH 13/13] dpaa_eth: fix SG frame cleanup

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Fix issue with the entry indexing in the sg frame cleanup code being
off-by-1. This problem showed up when doing some basic iperf tests and
manifested in traffic coming to a halt.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index daede7272768..40420edc9ce6 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1663,7 +1663,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
 qm_sg_entry_get_len(&sgt[0]), dma_dir);
 
/* remaining pages were mapped with skb_frag_dma_map() */
-   for (i = 1; i < nr_frags; i++) {
+   for (i = 1; i <= nr_frags; i++) {
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
 
dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
-- 
2.17.1

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


[PATCH 00/13] Prerequisites for NXP LS104xA SMMU enablement

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

This patch series contains several fixes in preparation for SMMU
support on NXP LS1043A and LS1046A chips. Once these get picked up,
I'll submit the actual SMMU enablement patches consisting in the
required device tree changes.

This patch series contains only part of the previously submitted one,
(including also the device tree changes) available here:

https://patchwork.kernel.org/cover/10634443/

There are a couple of changes/fixes since then:
 - for consistency, renamed mmu node to smmu
 - new patch page aligning the sizes of the qbman reserved memory
 - rebased on 5.1.0-rc2

Laurentiu Tudor (13):
  soc/fsl/qman: fixup liodns only on ppc targets
  soc/fsl/bman: map FBPR area in the iommu
  soc/fsl/qman: map FQD and PFDR areas in the iommu
  soc/fsl/qman-portal: map CENA area in the iommu
  soc/fsl/bqman: page align iommu mapping sizes
  soc/fsl/qbman_portals: add APIs to retrieve the probing status
  fsl/fman: backup and restore ICID registers
  fsl/fman: add API to get the device behind a fman port
  dpaa_eth: defer probing after qbman
  dpaa_eth: base dma mappings on the fman rx port
  dpaa_eth: fix iova handling for contiguous frames
  dpaa_eth: fix iova handling for sg frames
  dpaa_eth: fix SG frame cleanup

 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 136 --
 drivers/net/ethernet/freescale/fman/fman.c|  35 -
 drivers/net/ethernet/freescale/fman/fman.h|   4 +
 .../net/ethernet/freescale/fman/fman_port.c   |  14 ++
 .../net/ethernet/freescale/fman/fman_port.h   |   2 +
 drivers/soc/fsl/qbman/bman_ccsr.c |  11 ++
 drivers/soc/fsl/qbman/bman_portal.c   |  22 ++-
 drivers/soc/fsl/qbman/qman_ccsr.c |  17 +++
 drivers/soc/fsl/qbman/qman_portal.c   |  40 +-
 include/soc/fsl/bman.h|   8 ++
 include/soc/fsl/qman.h|   9 ++
 11 files changed, 242 insertions(+), 56 deletions(-)

-- 
2.17.1

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


[PATCH 10/13] dpaa_eth: base dma mappings on the fman rx port

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

The dma transactions initiator is the rx fman port so that's the device
that the dma mappings should be done. Previously the mappings were done
through the MAC device which makes no sense because it's neither dma-able
nor connected in any way to smmu.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 647e90e7434f..cdc7e6d83f77 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2805,8 +2805,15 @@ static int dpaa_eth_probe(struct platform_device *pdev)
return -ENODEV;
}
 
+   mac_dev = dpaa_mac_dev_get(pdev);
+   if (IS_ERR(mac_dev)) {
+   dev_err(&pdev->dev, "dpaa_mac_dev_get() failed\n");
+   err = PTR_ERR(mac_dev);
+   goto probe_err;
+   }
+
/* device used for DMA mapping */
-   dev = pdev->dev.parent;
+   dev = fman_port_get_device(mac_dev->port[RX]);
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
if (err) {
dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
@@ -2831,13 +2838,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)
 
priv->msg_enable = netif_msg_init(debug, DPAA_MSG_DEFAULT);
 
-   mac_dev = dpaa_mac_dev_get(pdev);
-   if (IS_ERR(mac_dev)) {
-   dev_err(dev, "dpaa_mac_dev_get() failed\n");
-   err = PTR_ERR(mac_dev);
-   goto free_netdev;
-   }
-
/* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
 * we choose conservatively and let the user explicitly set a higher
 * MTU via ifconfig. Otherwise, the user may end up with different MTUs
@@ -2973,9 +2973,9 @@ static int dpaa_eth_probe(struct platform_device *pdev)
qman_release_cgrid(priv->cgr_data.cgr.cgrid);
 free_dpaa_bps:
dpaa_bps_free(priv);
-free_netdev:
dev_set_drvdata(dev, NULL);
free_netdev(net_dev);
+probe_err:
 
return err;
 }
-- 
2.17.1

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


[PATCH 04/13] soc/fsl/qman-portal: map CENA area in the iommu

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add a one-to-one iommu mapping for qman portal CENA register area.
This is required for QMAN stashing to work without faults behind
an iommu.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/qman_portal.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index 661c9b234d32..dfb62f9815e9 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -29,6 +29,7 @@
  */
 
 #include "qman_priv.h"
+#include 
 
 struct qman_portal *qman_dma_portal;
 EXPORT_SYMBOL(qman_dma_portal);
@@ -224,6 +225,7 @@ static int qman_portal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
+   struct iommu_domain *domain;
struct qm_portal_config *pcfg;
struct resource *addr_phys[2];
int irq, cpu, err;
@@ -286,6 +288,21 @@ static int qman_portal_probe(struct platform_device *pdev)
goto err_ioremap2;
}
 
+   /* Create an 1-to-1 iommu mapping for cena portal area */
+   domain = iommu_get_domain_for_dev(dev);
+   if (domain) {
+   /*
+* Note: not mapping this as cacheable triggers the infamous
+* QMan CIDE error.
+*/
+   err = iommu_map(domain,
+   addr_phys[0]->start, addr_phys[0]->start,
+   resource_size(addr_phys[0]),
+   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+   if (err)
+   dev_warn(dev, "failed to iommu_map() %d\n", err);
+   }
+
pcfg->pools = qm_get_pools_sdqcr();
 
spin_lock(&qman_lock);
-- 
2.17.1

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


[PATCH 07/13] fsl/fman: backup and restore ICID registers

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

During probing, FMAN is reset thus losing all its register
settings. Backup port ICID registers before reset and restore
them after, similarly to how it's done on powerpc / PAMU based
platforms.
This also has the side effect of disabling the old code path
(liodn backup/restore handling) that obviously make no sense
in the context of SMMU on ARMs.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/fman/fman.c | 35 +-
 drivers/net/ethernet/freescale/fman/fman.h |  4 +++
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman.c 
b/drivers/net/ethernet/freescale/fman/fman.c
index e80fedb27cee..ae833e215b74 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -629,6 +629,7 @@ static void set_port_order_restoration(struct fman_fpm_regs 
__iomem *fpm_rg,
iowrite32be(tmp, &fpm_rg->fmfp_prc);
 }
 
+#ifdef CONFIG_PPC
 static void set_port_liodn(struct fman *fman, u8 port_id,
   u32 liodn_base, u32 liodn_ofst)
 {
@@ -646,6 +647,27 @@ static void set_port_liodn(struct fman *fman, u8 port_id,
iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]);
iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
 }
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+static void save_restore_port_icids(struct fman *fman, bool save)
+{
+   int port_idxes[] = {
+   0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc,
+   0xd, 0xe, 0xf, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+   0x10, 0x11, 0x30, 0x31
+   };
+   int idx, i;
+
+   for (i = 0; i < ARRAY_SIZE(port_idxes); i++) {
+   idx = port_idxes[i];
+   if (save)
+   fman->sp_icids[idx] =
+   ioread32be(&fman->bmi_regs->fmbm_spliodn[idx]);
+   else
+   iowrite32be(fman->sp_icids[idx],
+   &fman->bmi_regs->fmbm_spliodn[idx]);
+   }
+}
+#endif
 
 static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
 {
@@ -1914,7 +1936,10 @@ static int fman_reset(struct fman *fman)
 static int fman_init(struct fman *fman)
 {
struct fman_cfg *cfg = NULL;
-   int err = 0, i, count;
+   int err = 0, count;
+#ifdef CONFIG_PPC
+   int i;
+#endif
 
if (is_init_done(fman->cfg))
return -EINVAL;
@@ -1934,6 +1959,7 @@ static int fman_init(struct fman *fman)
memset_io((void __iomem *)(fman->base_addr + CGP_OFFSET), 0,
  fman->state->fm_port_num_of_cg);
 
+#ifdef CONFIG_PPC
/* Save LIODN info before FMan reset
 * Skipping non-existent port 0 (i = 1)
 */
@@ -1953,6 +1979,9 @@ static int fman_init(struct fman *fman)
}
fman->liodn_base[i] = liodn_base;
}
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   save_restore_port_icids(fman, true);
+#endif
 
err = fman_reset(fman);
if (err)
@@ -2181,8 +2210,12 @@ int fman_set_port_params(struct fman *fman,
if (err)
goto return_err;
 
+#ifdef CONFIG_PPC
set_port_liodn(fman, port_id, fman->liodn_base[port_id],
   fman->liodn_offset[port_id]);
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   save_restore_port_icids(fman, false);
+#endif
 
if (fman->state->rev_info.major < 6)
set_port_order_restoration(fman->fpm_regs, port_id);
diff --git a/drivers/net/ethernet/freescale/fman/fman.h 
b/drivers/net/ethernet/freescale/fman/fman.h
index 935c317fa696..19f20fa58053 100644
--- a/drivers/net/ethernet/freescale/fman/fman.h
+++ b/drivers/net/ethernet/freescale/fman/fman.h
@@ -346,8 +346,12 @@ struct fman {
unsigned long fifo_offset;
size_t fifo_size;
 
+#ifdef CONFIG_PPC
u32 liodn_base[64];
u32 liodn_offset[64];
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   u32 sp_icids[64];
+#endif
 
struct fman_dts_params dts_params;
 };
-- 
2.17.1

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


[PATCH 05/13] soc/fsl/bqman: page align iommu mapping sizes

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Prior to calling iommu_map()/iommu_unmap() page align the size or
failures such as below could happen:

iommu: unaligned: iova 0x... pa 0x... size 0x4000 min_pagesz 0x1
qman_portal 5.qman-portal: failed to iommu_map() -22

Seen when booted a kernel compiled with 64K page size support.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/bman_ccsr.c   | 2 +-
 drivers/soc/fsl/qbman/qman_ccsr.c   | 4 ++--
 drivers/soc/fsl/qbman/qman_portal.c | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c 
b/drivers/soc/fsl/qbman/bman_ccsr.c
index b209c79511bb..3a6e01bde32d 100644
--- a/drivers/soc/fsl/qbman/bman_ccsr.c
+++ b/drivers/soc/fsl/qbman/bman_ccsr.c
@@ -230,7 +230,7 @@ static int fsl_bman_probe(struct platform_device *pdev)
/* Create an 1-to-1 iommu mapping for FBPR area */
domain = iommu_get_domain_for_dev(dev);
if (domain) {
-   ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
+   ret = iommu_map(domain, fbpr_a, fbpr_a, PAGE_ALIGN(fbpr_sz),
IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
if (ret)
dev_warn(dev, "failed to iommu_map() %d\n", ret);
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c 
b/drivers/soc/fsl/qbman/qman_ccsr.c
index eec7700507e1..8d3c950ce52d 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -783,11 +783,11 @@ static int fsl_qman_probe(struct platform_device *pdev)
/* Create an 1-to-1 iommu mapping for fqd and pfdr areas */
domain = iommu_get_domain_for_dev(dev);
if (domain) {
-   ret = iommu_map(domain, fqd_a, fqd_a, fqd_sz,
+   ret = iommu_map(domain, fqd_a, fqd_a, PAGE_ALIGN(fqd_sz),
IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
if (ret)
dev_warn(dev, "iommu_map(fqd) failed %d\n", ret);
-   ret = iommu_map(domain, pfdr_a, pfdr_a, pfdr_sz,
+   ret = iommu_map(domain, pfdr_a, pfdr_a, PAGE_ALIGN(pfdr_sz),
IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
if (ret)
dev_warn(dev, "iommu_map(pfdr) failed %d\n", ret);
diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index dfb62f9815e9..bce56da2b01f 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -297,7 +297,7 @@ static int qman_portal_probe(struct platform_device *pdev)
 */
err = iommu_map(domain,
addr_phys[0]->start, addr_phys[0]->start,
-   resource_size(addr_phys[0]),
+   PAGE_ALIGN(resource_size(addr_phys[0])),
IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
if (err)
dev_warn(dev, "failed to iommu_map() %d\n", err);
-- 
2.17.1

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


[PATCH 09/13] dpaa_eth: defer probing after qbman

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Enabling SMMU altered the order of device probing causing the dpaa1
ethernet driver to get probed before qbman and causing a boot crash.
Add predictability in the probing order by deferring the ethernet
driver probe after qbman and portals by using the recently introduced
qbman APIs.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index dfebc30c4841..647e90e7434f 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2774,6 +2774,37 @@ static int dpaa_eth_probe(struct platform_device *pdev)
int err = 0, i, channel;
struct device *dev;
 
+   err = bman_is_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev, "failing probe due to bman probe error\n");
+   return -ENODEV;
+   }
+   err = qman_is_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev, "failing probe due to qman probe error\n");
+   return -ENODEV;
+   }
+   err = bman_portals_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev,
+   "failing probe due to bman portals probe error\n");
+   return -ENODEV;
+   }
+   err = qman_portals_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev,
+   "failing probe due to qman portals probe error\n");
+   return -ENODEV;
+   }
+
/* device used for DMA mapping */
dev = pdev->dev.parent;
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
-- 
2.17.1

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


[PATCH 01/13] soc/fsl/qman: fixup liodns only on ppc targets

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

ARM SoCs use SMMU so the liodn fixup done in the qman driver is no
longer making sense and it also breaks the ICID settings inherited
from u-boot. Do the fixups only for PPC targets.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/qman_ccsr.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c 
b/drivers/soc/fsl/qbman/qman_ccsr.c
index 109b38de3176..12e414ca3b03 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -598,6 +598,7 @@ static int qman_init_ccsr(struct device *dev)
 #define LIO_CFG_LIODN_MASK 0x0fff
 void qman_liodn_fixup(u16 channel)
 {
+#ifdef CONFIG_PPC
static int done;
static u32 liodn_offset;
u32 before, after;
@@ -617,6 +618,7 @@ void qman_liodn_fixup(u16 channel)
qm_ccsr_out(REG_REV3_QCSP_LIO_CFG(idx), after);
else
qm_ccsr_out(REG_QCSP_LIO_CFG(idx), after);
+#endif
 }
 
 #define IO_CFG_SDEST_MASK 0x00ff
-- 
2.17.1

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


[PATCH 03/13] soc/fsl/qman: map FQD and PFDR areas in the iommu

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add a one-to-one iommu mapping for qman private data memory areas
(FQD and PFDR). This is required for QMAN to work without faults
behind an iommu.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/qman_ccsr.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c 
b/drivers/soc/fsl/qbman/qman_ccsr.c
index 12e414ca3b03..eec7700507e1 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -29,6 +29,7 @@
  */
 
 #include "qman_priv.h"
+#include 
 
 u16 qman_ip_rev;
 EXPORT_SYMBOL(qman_ip_rev);
@@ -699,6 +700,7 @@ static int fsl_qman_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
+   struct iommu_domain *domain;
struct resource *res;
int ret, err_irq;
u16 id;
@@ -778,6 +780,19 @@ static int fsl_qman_probe(struct platform_device *pdev)
}
dev_dbg(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz);
 
+   /* Create an 1-to-1 iommu mapping for fqd and pfdr areas */
+   domain = iommu_get_domain_for_dev(dev);
+   if (domain) {
+   ret = iommu_map(domain, fqd_a, fqd_a, fqd_sz,
+   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+   if (ret)
+   dev_warn(dev, "iommu_map(fqd) failed %d\n", ret);
+   ret = iommu_map(domain, pfdr_a, pfdr_a, pfdr_sz,
+   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+   if (ret)
+   dev_warn(dev, "iommu_map(pfdr) failed %d\n", ret);
+   }
+
ret = qman_init_ccsr(dev);
if (ret) {
dev_err(dev, "CCSR setup failed\n");
-- 
2.17.1

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


[PATCH 02/13] soc/fsl/bman: map FBPR area in the iommu

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add a one-to-one iommu mapping for bman private data memory (FBPR).
This is required for BMAN to work without faults behind an iommu.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/bman_ccsr.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c 
b/drivers/soc/fsl/qbman/bman_ccsr.c
index 7c3cc968053c..b209c79511bb 100644
--- a/drivers/soc/fsl/qbman/bman_ccsr.c
+++ b/drivers/soc/fsl/qbman/bman_ccsr.c
@@ -29,6 +29,7 @@
  */
 
 #include "bman_priv.h"
+#include 
 
 u16 bman_ip_rev;
 EXPORT_SYMBOL(bman_ip_rev);
@@ -178,6 +179,7 @@ static int fsl_bman_probe(struct platform_device *pdev)
int ret, err_irq;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
+   struct iommu_domain *domain;
struct resource *res;
u16 id, bm_pool_cnt;
u8 major, minor;
@@ -225,6 +227,15 @@ static int fsl_bman_probe(struct platform_device *pdev)
 
dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
 
+   /* Create an 1-to-1 iommu mapping for FBPR area */
+   domain = iommu_get_domain_for_dev(dev);
+   if (domain) {
+   ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
+   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+   if (ret)
+   dev_warn(dev, "failed to iommu_map() %d\n", ret);
+   }
+
bm_set_memory(fbpr_a, fbpr_sz);
 
err_irq = platform_get_irq(pdev, 0);
-- 
2.17.1

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


[PATCH 06/13] soc/fsl/qbman_portals: add APIs to retrieve the probing status

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add a couple of new APIs to check the probing status of the required
cpu bound qman and bman portals:
 'int bman_portals_probed()' and 'int qman_portals_probed()'.
They return the following values.
 *  1 if qman/bman portals were all probed correctly
 *  0 if qman/bman portals were not yet probed
 * -1 if probing of qman/bman portals failed
Portals are considered successful probed if no error occurred during
the probing of any of the portals and if enough portals were probed
to have one available for each cpu.
The error handling paths were slightly rearranged in order to fit this
new functionality without being too intrusive.
Drivers that use qman/bman portal driver services are required to use
these APIs before calling any functions exported by these drivers or
otherwise they will crash the kernel.
First user will be the dpaa1 ethernet driver, coming in a subsequent
patch.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/bman_portal.c | 22 ++
 drivers/soc/fsl/qbman/qman_portal.c | 23 +++
 include/soc/fsl/bman.h  |  8 
 include/soc/fsl/qman.h  |  9 +
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/fsl/qbman/bman_portal.c 
b/drivers/soc/fsl/qbman/bman_portal.c
index 2c95cf59f3e7..7819bc29936d 100644
--- a/drivers/soc/fsl/qbman/bman_portal.c
+++ b/drivers/soc/fsl/qbman/bman_portal.c
@@ -32,6 +32,7 @@
 
 static struct bman_portal *affine_bportals[NR_CPUS];
 static struct cpumask portal_cpus;
+static int __bman_portals_probed;
 /* protect bman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(bman_lock);
 
@@ -87,6 +88,12 @@ static int bman_online_cpu(unsigned int cpu)
return 0;
 }
 
+int bman_portals_probed(void)
+{
+   return __bman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(bman_portals_probed);
+
 static int bman_portal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -104,8 +111,10 @@ static int bman_portal_probe(struct platform_device *pdev)
}
 
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-   if (!pcfg)
+   if (!pcfg) {
+   __bman_portals_probed = -1;
return -ENOMEM;
+   }
 
pcfg->dev = dev;
 
@@ -113,14 +122,14 @@ static int bman_portal_probe(struct platform_device *pdev)
 DPAA_PORTAL_CE);
if (!addr_phys[0]) {
dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
 
addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
 DPAA_PORTAL_CI);
if (!addr_phys[1]) {
dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
 
pcfg->cpu = -1;
@@ -128,7 +137,7 @@ static int bman_portal_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "Can't get %pOF IRQ'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
pcfg->irq = irq;
 
@@ -156,6 +165,9 @@ static int bman_portal_probe(struct platform_device *pdev)
}
 
cpumask_set_cpu(cpu, &portal_cpus);
+   if (!__bman_portals_probed &&
+   cpumask_weight(&portal_cpus) == num_online_cpus())
+   __bman_portals_probed = 1;
spin_unlock(&bman_lock);
pcfg->cpu = cpu;
 
@@ -175,6 +187,8 @@ static int bman_portal_probe(struct platform_device *pdev)
 err_ioremap2:
memunmap(pcfg->addr_virt_ce);
 err_ioremap1:
+__bman_portals_probed = -1;
+
return -ENXIO;
 }
 
diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index bce56da2b01f..11ba6c77c0d6 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -39,6 +39,7 @@ EXPORT_SYMBOL(qman_dma_portal);
 #define CONFIG_FSL_DPA_PIRQ_FAST  1
 
 static struct cpumask portal_cpus;
+static int __qman_portals_probed;
 /* protect qman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(qman_lock);
 
@@ -221,6 +222,12 @@ static int qman_online_cpu(unsigned int cpu)
return 0;
 }
 
+int qman_portals_probed(void)
+{
+   return __qman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(qman_portals_probed);
+
 static int qman_portal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -240,8 +247,10 @@ static int qman_portal_probe(struct platform_device *pdev)
}
 
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-   if (!pcfg)
+   if (!pcfg) {
+   __qman_

[PATCH 12/13] dpaa_eth: fix iova handling for sg frames

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this also for scatter-gather frames
using the iova -> phys conversion function added in the previous patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 41 +++
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index f17edc80dc37..daede7272768 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1646,14 +1646,17 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
 
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
-   dma_unmap_single(dev, addr,
-qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
-dma_dir);
 
/* The sgt buffer has been allocated with netdev_alloc_frag(),
 * it's from lowmem.
 */
-   sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
+   sgt = phys_to_virt(dpaa_iova_to_phys(dev,
+addr +
+qm_fd_get_offset(fd)));
+
+   dma_unmap_single(dev, addr,
+qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+dma_dir);
 
/* sgt[0] is from lowmem, was dma_map_single()-ed */
dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
@@ -1668,7 +1671,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
}
 
/* Free the page frag that we allocated on Tx */
-   skb_free_frag(phys_to_virt(addr));
+   skb_free_frag(skbh);
} else {
dma_unmap_single(dev, addr,
 skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
@@ -1729,14 +1732,14 @@ static struct sk_buff *contig_fd_to_skb(const struct 
dpaa_priv *priv,
  * The page fragment holding the S/G Table is recycled here.
  */
 static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
-   const struct qm_fd *fd)
+   const struct qm_fd *fd,
+   struct dpaa_bp *dpaa_bp,
+   void *vaddr)
 {
ssize_t fd_off = qm_fd_get_offset(fd);
-   dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct page *page, *head_page;
-   struct dpaa_bp *dpaa_bp;
-   void *vaddr, *sg_vaddr;
+   void *sg_vaddr;
int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
@@ -1745,7 +1748,6 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
int *count_ptr;
int i;
 
-   vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
 
/* Iterate through the SGT entries and add data buffers to the skb */
@@ -1756,14 +1758,18 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
 
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
-   SMP_CACHE_BYTES));
 
/* We may use multiple Rx pools */
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
-   if (!dpaa_bp)
+   if (!dpaa_bp) {
+   pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
+   __func__, sgt[i].bpid);
goto free_buffers;
+   }
+   sg_vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev,
+ sg_addr));
+   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+   SMP_CACHE_BYTES));
 
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
@@ -1835,10 +1841,11 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
/* free all the SG entries */
for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   skb_free_frag(sg_vaddr);
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
if (dpaa_bp

[PATCH 08/13] fsl/fman: add API to get the device behind a fman port

2019-03-29 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add an API that retrieves the 'struct device' that the specified fman
port probed against. The new API will be used in a subsequent iommu
enablement related patch.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/fman/fman_port.c | 14 ++
 drivers/net/ethernet/freescale/fman/fman_port.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c 
b/drivers/net/ethernet/freescale/fman/fman_port.c
index ee82ee1384eb..bd76c9730692 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1728,6 +1728,20 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port)
 }
 EXPORT_SYMBOL(fman_port_get_qman_channel_id);
 
+/**
+ * fman_port_get_device
+ * port:   Pointer to the FMan port device
+ *
+ * Get the 'struct device' associated to the specified FMan port device
+ *
+ * Return: pointer to associated 'struct device'
+ */
+struct device *fman_port_get_device(struct fman_port *port)
+{
+   return port->dev;
+}
+EXPORT_SYMBOL(fman_port_get_device);
+
 int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
 {
if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE)
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h 
b/drivers/net/ethernet/freescale/fman/fman_port.h
index 9dbb69f40121..82f12661a46d 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.h
+++ b/drivers/net/ethernet/freescale/fman/fman_port.h
@@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_port *port, const void 
*data, u64 *tstamp);
 
 struct fman_port *fman_port_bind(struct device *dev);
 
+struct device *fman_port_get_device(struct fman_port *port);
+
 #endif /* __FMAN_PORT_H */
-- 
2.17.1

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


[RFC PATCH 3/4] bus: fsl-mc: Add ACPI support for fsl-mc

2020-02-27 Thread laurentiu . tudor
From: Makarand Pawagi 

ACPI support is added in the fsl-mc driver. Driver will parse
MC DSDT table to extract memory and other resorces.

Interrupt (GIC ITS) information will be extracted from MADT table
by drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c.

IORT table will be parsed to configure DMA.

Signed-off-by: Makarand Pawagi 
---
Previous attempt, here: https://patchwork.kernel.org/patch/11353735/

 drivers/bus/fsl-mc/fsl-mc-bus.c | 35 ++-
 drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c | 69 -
 2 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index eafaa0e0b906..c4742a9c0714 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -941,7 +941,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
phys_addr_t mc_portal_phys_addr;
u32 mc_portal_size;
struct mc_version mc_version;
-   struct resource res;
+   struct resource *plat_res;
 
/*
 * The MC firmware requires full access to the whole address space plus
@@ -967,16 +967,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
/*
 * Get physical address of MC portal for the root DPRC:
 */
-   error = of_address_to_resource(pdev->dev.of_node, 0, &res);
-   if (error < 0) {
-   dev_err(&pdev->dev,
-   "of_address_to_resource() failed for %pOF\n",
-   pdev->dev.of_node);
-   return error;
-   }
-
-   mc_portal_phys_addr = res.start;
-   mc_portal_size = resource_size(&res);
+   plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   mc_portal_phys_addr = plat_res->start;
+   mc_portal_size = resource_size(plat_res);
error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
 mc_portal_size, NULL,
 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io);
@@ -993,11 +986,13 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n",
 mc_version.major, mc_version.minor, mc_version.revision);
 
-   error = get_mc_addr_translation_ranges(&pdev->dev,
-  &mc->translation_ranges,
-  &mc->num_translation_ranges);
-   if (error < 0)
-   goto error_cleanup_mc_io;
+   if (dev_of_node(&pdev->dev)) {
+   error = get_mc_addr_translation_ranges(&pdev->dev,
+   &mc->translation_ranges,
+   &mc->num_translation_ranges);
+   if (error < 0)
+   goto error_cleanup_mc_io;
+   }
 
error = dprc_get_container_id(mc_io, 0, &container_id);
if (error < 0) {
@@ -1024,6 +1019,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
goto error_cleanup_mc_io;
 
mc->root_mc_bus_dev = mc_bus_dev;
+   mc_bus_dev->dev.fwnode = pdev->dev.fwnode;
return 0;
 
 error_cleanup_mc_io:
@@ -1064,11 +1060,18 @@ static const struct of_device_id 
fsl_mc_bus_match_table[] = {
 
 MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table);
 
+static const struct acpi_device_id fsl_mc_bus_acpi_match_table[] = {
+   {"NXP0008", 0 },
+   { }
+};
+MODULE_DEVICE_TABLE(acpi, fsl_mc_bus_acpi_match_table);
+
 static struct platform_driver fsl_mc_bus_driver = {
.driver = {
   .name = "fsl_mc_bus",
   .pm = NULL,
   .of_match_table = fsl_mc_bus_match_table,
+  .acpi_match_table = fsl_mc_bus_acpi_match_table,
   },
.probe = fsl_mc_bus_probe,
.remove = fsl_mc_bus_remove,
diff --git a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c 
b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
index 606efa64adff..6d67834722c9 100644
--- a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
@@ -4,9 +4,11 @@
  *
  * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
  * Author: German Rivera 
+ * Copyright 2020 NXP
  *
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -66,7 +68,65 @@ static const struct of_device_id its_device_id[] = {
{},
 };
 
-static int __init its_fsl_mc_msi_init(void)
+static int __init its_fsl_mc_msi_init_one(struct fwnode_handle *handle,
+ const char *name)
+{
+   struct irq_domain *parent;
+   struct irq_domain *mc_msi_domain;
+
+   parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
+   if (!parent || !msi_get_domain_info(parent)) {
+   pr_err("%s: Unable to locate ITS domain\n", name);
+   return -ENXIO;
+   }
+
+   mc_msi_domain = fsl_mc_msi_create_irq_domain(handle,
+   

[RFC PATCH 4/4] iommu/of: get rid of fsl-mc specific code

2020-02-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

Changing the way we configure dma for fsl-mc devices allows
us to get rid of our fsl-mc specific code in the generic
of iommu code.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/of_iommu.c | 20 
 1 file changed, 20 deletions(-)

diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 20738aacac89..332072ada474 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -15,7 +15,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #define NO_IOMMU   1
 
@@ -139,23 +138,6 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
return err;
 }
 
-static int of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev,
-   struct device_node *master_np)
-{
-   struct of_phandle_args iommu_spec = { .args_count = 1 };
-   int err;
-
-   err = of_map_rid(master_np, mc_dev->icid, "iommu-map",
-"iommu-map-mask", &iommu_spec.np,
-iommu_spec.args);
-   if (err)
-   return err == -ENODEV ? NO_IOMMU : err;
-
-   err = of_iommu_xlate(&mc_dev->dev, &iommu_spec);
-   of_node_put(iommu_spec.np);
-   return err;
-}
-
 const struct iommu_ops *of_iommu_configure(struct device *dev,
   struct device_node *master_np)
 {
@@ -188,8 +170,6 @@ const struct iommu_ops *of_iommu_configure(struct device 
*dev,
pci_request_acs();
err = pci_for_each_dma_alias(to_pci_dev(dev),
 of_pci_iommu_init, &info);
-   } else if (dev_is_fsl_mc(dev)) {
-   err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np);
} else {
struct of_phandle_args iommu_spec;
int idx = 0;
-- 
2.17.1

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


[RFC PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation

2020-02-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.

Signed-off-by: Laurentiu Tudor 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 36eb25f82c8e..eafaa0e0b906 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -132,11 +132,40 @@ static int fsl_mc_bus_uevent(struct device *dev, struct 
kobj_uevent_env *env)
 static int fsl_mc_dma_configure(struct device *dev)
 {
struct device *dma_dev = dev;
+   struct iommu_fwspec *fwspec;
+   const struct iommu_ops *iommu_ops;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   int ret;
+   u32 icid;
 
while (dev_is_fsl_mc(dma_dev))
dma_dev = dma_dev->parent;
 
-   return of_dma_configure(dev, dma_dev->of_node, 0);
+   fwspec = dev_iommu_fwspec_get(dma_dev);
+   if (!fwspec)
+   return -ENODEV;
+   iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
+   if (!iommu_ops)
+   return -ENODEV;
+
+   ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
+   if (ret)
+   return ret;
+
+   icid = mc_dev->icid;
+   ret = iommu_fwspec_add_ids(dev, &icid, 1);
+   if (ret)
+   return ret;
+
+   if (!device_iommu_mapped(dev)) {
+   ret = iommu_probe_device(dev);
+   if (ret)
+   return ret;
+   }
+
+   arch_setup_dma_ops(dev, 0, *dma_dev->dma_mask + 1, iommu_ops, true);
+
+   return 0;
 }
 
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
-- 
2.17.1

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


[RFC PATCH 2/4] irqchip/fsl-mc: Change the way the IRQ domain is set for MC devices

2020-02-27 Thread laurentiu . tudor
From: Diana Craciun 

In ACPI the MC bus is represented as a platform device and a named
component in the IORT table. The mc-bus devices are discovered
dynamically at runtime but they share the same fwnode with the parent
platfom device. This patch changes the way the IRQ domain is searched
for the MC devices: it takes the fwnode reference from the parent and
uses the fwnode reference to find the MC IRQ domain.

Signed-off-by: Diana Craciun 
---
 drivers/bus/fsl-mc/fsl-mc-msi.c | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c
index 8b9c66d7c4ff..1e2e97329781 100644
--- a/drivers/bus/fsl-mc/fsl-mc-msi.c
+++ b/drivers/bus/fsl-mc/fsl-mc-msi.c
@@ -182,16 +182,23 @@ int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
 {
struct irq_domain *msi_domain;
struct device_node *mc_of_node = mc_platform_dev->of_node;
+   struct fwnode_handle *fwnode;
 
-   msi_domain = of_msi_get_domain(mc_platform_dev, mc_of_node,
-  DOMAIN_BUS_FSL_MC_MSI);
+   msi_domain = dev_get_msi_domain(mc_platform_dev);
if (!msi_domain) {
pr_err("Unable to find fsl-mc MSI domain for %pOF\n",
   mc_of_node);
 
return -ENOENT;
}
+   fwnode = msi_domain->fwnode;
+   msi_domain = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_FSL_MC_MSI);
+   if (!msi_domain) {
+   pr_err("Unable to find fsl-mc MSI domain for %pOF\n",
+  mc_of_node);
 
+   return -ENOENT;
+   }
*mc_msi_domain = msi_domain;
return 0;
 }
-- 
2.17.1

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


RE: [PATCH] iommu: silence iommu group prints

2020-03-02 Thread Laurentiu Tudor
Hi Robin,

> -Original Message-
> From: Robin Murphy 
> Sent: Friday, February 28, 2020 8:32 PM
> 
> [ +Laurentiu ]
> 
> Hi Russell,
> 
> Thanks for sharing a log, now I properly understand what's up... further
> comments at the end (for context).
> 
> On 28/02/2020 10:06 am, Russell King - ARM Linux admin wrote:
> > On Fri, Feb 28, 2020 at 09:33:40AM +, John Garry wrote:
> >> On 28/02/2020 02:16, Lu Baolu wrote:
> >>> Hi,
> >>>
> >>> On 2020/2/27 19:57, Russell King wrote:
>  On the LX2160A, there are lots (about 160) of IOMMU messages produced
>  during boot; this is excessive.  Reduce the severity of these
> messages
>  to debug level.
> 
>  Signed-off-by: Russell King 
>  ---
>     drivers/iommu/iommu.c | 4 ++--
>     1 file changed, 2 insertions(+), 2 deletions(-)
> 
>  diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>  index 3ead597e1c57..304281ec623b 100644
>  --- a/drivers/iommu/iommu.c
>  +++ b/drivers/iommu/iommu.c
>  @@ -741,7 +741,7 @@ int iommu_group_add_device(struct iommu_group
>  *group, struct device *dev)
>     trace_add_device_to_group(group->id, dev);
>  -    dev_info(dev, "Adding to iommu group %d\n", group->id);
>  +    dev_dbg(dev, "Adding to iommu group %d\n", group->id);
> >>>
> >>> I'm not strongly against this. But to me this message seems to be a
> good
> >>> indicator that a device was probed successfully by the iommu subsystem.
> >>> Keeping it in the default kernel message always helps to the kernel
> >>> debugging.
> >>>
> >>
> >> I would tend to agree.
> >

[snip]

> >
> > # dmesg |grep 'Adding to iommu' | wc -l
> > 164
> > # dmesg |grep -v 'Adding to iommu' | wc -l
> > 551
> >
> > So, 23% of the kernel messages on this platform are "Adding to iommu",
> > which is excessive.
> 
> Indeed, however I would note that on most platforms bringing up a
> network interface involves hot-adding 0 devices, so hot-adding 19
> devices as full-blown DMA masters is arguably the root of "excessive"
> already. Per the concern I initially raised, each of those messages
> represents a whole bunch of internal allocation and bookkeeping going
> on, which if it isn't necessary would be far better avoided altogether,
> than simply done more quietly.
> 
> Laurentiu, I guess at the moment the nature of the of_dma_configure()
> integration means we end up treating all DPAA2 objects identically, but
> do you think we have scope to be a bit cleverer in that regard?
> Presumably not every type of object that shows up on the fsl_mc bus is
> really an independent DMA master, so if we could skip doing the full
> DMA/IOMMU/MSI setup for the ones that don't need it, it would work out
> nicer all round. In fact your .dma_configure proposal (which I'll try to
> take a proper look at next week) couldn't have come at a better time for
> that argument :)
 
Thanks! That's a very good point - I'll check on which devices we actually use 
dma apis and filter the rest out. Will keep in mind for the next spin of the 
patches.

---
Best Regards, Laurentiu

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

Re: [PATCH] iommu: silence iommu group prints

2020-03-03 Thread Laurentiu Tudor



On 28.02.2020 20:32, Robin Murphy wrote:

[ +Laurentiu ]

Hi Russell,

Thanks for sharing a log, now I properly understand what's up... further 
comments at the end (for context).


On 28/02/2020 10:06 am, Russell King - ARM Linux admin wrote:

On Fri, Feb 28, 2020 at 09:33:40AM +, John Garry wrote:

On 28/02/2020 02:16, Lu Baolu wrote:

Hi,

On 2020/2/27 19:57, Russell King wrote:

On the LX2160A, there are lots (about 160) of IOMMU messages produced
during boot; this is excessive.  Reduce the severity of these messages
to debug level.

Signed-off-by: Russell King 
---
   drivers/iommu/iommu.c | 4 ++--
   1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 3ead597e1c57..304281ec623b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -741,7 +741,7 @@ int iommu_group_add_device(struct iommu_group
*group, struct device *dev)
   trace_add_device_to_group(group->id, dev);
-    dev_info(dev, "Adding to iommu group %d\n", group->id);
+    dev_dbg(dev, "Adding to iommu group %d\n", group->id);


I'm not strongly against this. But to me this message seems to be a 
good

indicator that a device was probed successfully by the iommu subsystem.
Keeping it in the default kernel message always helps to the kernel
debugging.



I would tend to agree.


Here's the boot messages.  Notice how many of these "Adding to iommu
group" messages there are:

[    0.00] Booting Linux on physical CPU 0x00 [0x410fd083]
[    0.00] Linux version 5.5.0+ (rmk@rmk-PC) (gcc version 4.9.2 
(GCC)) #655 SMP PREEMPT Fri Feb 28 09:54:47 GMT 2020

[    0.00] Machine model: SolidRun LX2160A Clearfog CX
[    0.00] earlycon: pl11 at MMIO32 0x021c (options '')
[    0.00] printk: bootconsole [pl11] enabled
[    0.00] efi: Getting EFI parameters from FDT:
[    0.00] efi: UEFI not found.
[    0.00] cma: Reserved 32 MiB at 0xf9c0
[    0.00] On node 0 totalpages: 1555968
[    0.00]   DMA zone: 4096 pages used for memmap
[    0.00]   DMA zone: 0 pages reserved
[    0.00]   DMA zone: 262144 pages, LIFO batch:63
[    0.00]   DMA32 zone: 3832 pages used for memmap
[    0.00]   DMA32 zone: 245248 pages, LIFO batch:63
[    0.00]   Normal zone: 16384 pages used for memmap
[    0.00]   Normal zone: 1048576 pages, LIFO batch:63
[    0.00] psci: probing for conduit method from DT.
[    0.00] psci: PSCIv1.1 detected in firmware.
[    0.00] psci: Using standard PSCI v0.2 function IDs
[    0.00] psci: MIGRATE_INFO_TYPE not supported.
[    0.00] psci: SMC Calling Convention v1.1
[    0.00] percpu: Embedded 31 pages/cpu s88968 r8192 d29816 u126976
[    0.00] pcpu-alloc: s88968 r8192 d29816 u126976 alloc=31*4096
[    0.00] pcpu-alloc: [0] 00 [0] 01 [0] 02 [0] 03 [0] 04 [0] 05 
[0] 06 [0] 07
[    0.00] pcpu-alloc: [0] 08 [0] 09 [0] 10 [0] 11 [0] 12 [0] 13 
[0] 14 [0] 15

[    0.00] Detected PIPT I-cache on CPU0
[    0.00] CPU features: detected: GIC system register CPU interface
[    0.00] CPU features: detected: EL2 vector hardening
[    0.00] Speculative Store Bypass Disable mitigation not required
[    0.00] CPU features: detected: ARM erratum 1319367
[    0.00] Built 1 zonelists, mobility grouping on.  Total pages: 
1531656
[    0.00] Kernel command line: console=ttyAMA0,115200 
root=PARTUUID=c7837e2f-02 rootwait earlycon=pl011,mmio32,0x21c 
ramdisk_size=0 pci=pcie_bus_perf arm_smmu.disable_bypass=0 
iommu.passthrough=0
[    0.00] Dentry cache hash table entries: 1048576 (order: 11, 
8388608 bytes, linear)
[    0.00] Inode-cache hash table entries: 524288 (order: 10, 
4194304 bytes, linear)

[    0.00] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.00] software IO TLB: mapped [mem 0xbbfff000-0xb000] (64MB)
[    0.00] Memory: 5991500K/6223872K available (10172K kernel 
code, 1376K rwdata, 3888K rodata, 960K init, 4326K bss, 199604K 
reserved, 32768K cma-reserved)
[    0.00] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=16, 
Nodes=1

[    0.00] rcu: Preemptible hierarchical RCU implementation.
[    0.00] rcu: RCU restricting CPUs from NR_CPUS=64 to 
nr_cpu_ids=16.

[    0.00] Tasks RCU enabled.
[    0.00] rcu: RCU calculated value of scheduler-enlistment delay 
is 25 jiffies.
[    0.00] rcu: Adjusting geometry for rcu_fanout_leaf=16, 
nr_cpu_ids=16

[    0.00] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.00] GICv3: GIC: Using split EOI/Deactivate mode
[    0.00] GICv3: 256 SPIs implemented
[    0.00] GICv3: 0 Extended SPIs implemented
[    0.00] GICv3: Distributor has no Range Selector support
[    0.00] GICv3: 16 PPIs implemented
[    0.00] GICv3: no VLPI support, no direct LPI support
[    0.00] GICv3: CPU0: found redistributor 0 region 
0:0x0620

[    0.00] ITS [mem 0x0602-0x0603]
[ 

Re: [PATCH] iommu: silence iommu group prints

2020-03-03 Thread Laurentiu Tudor

Hi Russell,

On 03.03.2020 17:49, Russell King - ARM Linux admin wrote:

On Tue, Mar 03, 2020 at 04:18:57PM +0200, Laurentiu Tudor wrote:



On 28.02.2020 20:32, Robin Murphy wrote:

[ +Laurentiu ]

Hi Russell,

Thanks for sharing a log, now I properly understand what's up... further
comments at the end (for context).

On 28/02/2020 10:06 am, Russell King - ARM Linux admin wrote:

On Fri, Feb 28, 2020 at 09:33:40AM +, John Garry wrote:

On 28/02/2020 02:16, Lu Baolu wrote:

Hi,

On 2020/2/27 19:57, Russell King wrote:

On the LX2160A, there are lots (about 160) of IOMMU messages produced
during boot; this is excessive.  Reduce the severity of these messages
to debug level.

Signed-off-by: Russell King 
---
    drivers/iommu/iommu.c | 4 ++--
    1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 3ead597e1c57..304281ec623b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -741,7 +741,7 @@ int iommu_group_add_device(struct iommu_group
*group, struct device *dev)
    trace_add_device_to_group(group->id, dev);
-    dev_info(dev, "Adding to iommu group %d\n", group->id);
+    dev_dbg(dev, "Adding to iommu group %d\n", group->id);


I'm not strongly against this. But to me this message seems
to be a good
indicator that a device was probed successfully by the iommu subsystem.
Keeping it in the default kernel message always helps to the kernel
debugging.



I would tend to agree.


Here's the boot messages.  Notice how many of these "Adding to iommu
group" messages there are:

[    0.00] Booting Linux on physical CPU 0x00 [0x410fd083]
[    0.00] Linux version 5.5.0+ (rmk@rmk-PC) (gcc version 4.9.2
(GCC)) #655 SMP PREEMPT Fri Feb 28 09:54:47 GMT 2020
[    0.00] Machine model: SolidRun LX2160A Clearfog CX
[    0.00] earlycon: pl11 at MMIO32 0x021c (options '')
[    0.00] printk: bootconsole [pl11] enabled
[    0.00] efi: Getting EFI parameters from FDT:
[    0.00] efi: UEFI not found.
[    0.00] cma: Reserved 32 MiB at 0xf9c0
[    0.00] On node 0 totalpages: 1555968
[    0.00]   DMA zone: 4096 pages used for memmap
[    0.00]   DMA zone: 0 pages reserved
[    0.00]   DMA zone: 262144 pages, LIFO batch:63
[    0.00]   DMA32 zone: 3832 pages used for memmap
[    0.00]   DMA32 zone: 245248 pages, LIFO batch:63
[    0.00]   Normal zone: 16384 pages used for memmap
[    0.00]   Normal zone: 1048576 pages, LIFO batch:63
[    0.00] psci: probing for conduit method from DT.
[    0.00] psci: PSCIv1.1 detected in firmware.
[    0.00] psci: Using standard PSCI v0.2 function IDs
[    0.00] psci: MIGRATE_INFO_TYPE not supported.
[    0.00] psci: SMC Calling Convention v1.1
[    0.00] percpu: Embedded 31 pages/cpu s88968 r8192 d29816 u126976
[    0.00] pcpu-alloc: s88968 r8192 d29816 u126976 alloc=31*4096
[    0.00] pcpu-alloc: [0] 00 [0] 01 [0] 02 [0] 03 [0] 04 [0] 05
[0] 06 [0] 07
[    0.00] pcpu-alloc: [0] 08 [0] 09 [0] 10 [0] 11 [0] 12 [0] 13
[0] 14 [0] 15
[    0.00] Detected PIPT I-cache on CPU0
[    0.00] CPU features: detected: GIC system register CPU interface
[    0.00] CPU features: detected: EL2 vector hardening
[    0.00] Speculative Store Bypass Disable mitigation not required
[    0.00] CPU features: detected: ARM erratum 1319367
[    0.00] Built 1 zonelists, mobility grouping on.  Total
pages: 1531656
[    0.00] Kernel command line: console=ttyAMA0,115200
root=PARTUUID=c7837e2f-02 rootwait earlycon=pl011,mmio32,0x21c
ramdisk_size=0 pci=pcie_bus_perf arm_smmu.disable_bypass=0
iommu.passthrough=0
[    0.00] Dentry cache hash table entries: 1048576 (order: 11,
8388608 bytes, linear)
[    0.00] Inode-cache hash table entries: 524288 (order: 10,
4194304 bytes, linear)
[    0.00] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.00] software IO TLB: mapped [mem 0xbbfff000-0xb000] (64MB)
[    0.00] Memory: 5991500K/6223872K available (10172K kernel
code, 1376K rwdata, 3888K rodata, 960K init, 4326K bss, 199604K
reserved, 32768K cma-reserved)
[    0.00] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=16,
Nodes=1
[    0.00] rcu: Preemptible hierarchical RCU implementation.
[    0.00] rcu: RCU restricting CPUs from NR_CPUS=64 to
nr_cpu_ids=16.
[    0.00] Tasks RCU enabled.
[    0.00] rcu: RCU calculated value of scheduler-enlistment
delay is 25 jiffies.
[    0.00] rcu: Adjusting geometry for rcu_fanout_leaf=16,
nr_cpu_ids=16
[    0.00] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[    0.00] GICv3: GIC: Using split EOI/Deactivate mode
[    0.00] GICv3: 256 SPIs implemented
[    0.00] GICv3: 0 Extended SPIs implemented
[    0.00] GICv3: Distributor has no Range Selector support
[    0.00] GICv3: 16 PPIs implemen

Re: [PATCH] iommu: silence iommu group prints

2020-03-04 Thread Laurentiu Tudor


On 04.03.2020 00:17, Russell King - ARM Linux admin wrote:

On Tue, Mar 03, 2020 at 05:55:05PM +0200, Laurentiu Tudor wrote:

 From c98dc05cdd45ae923654f2427985bd28bcde4bb2 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Thu, 13 Feb 2020 11:59:12 +0200
Subject: [PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation
Content-Type: text/plain; charset="us-ascii"

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.


Firstly, applying this to v5.5 results in a build failure, due to a
missing linux/iommu.h include.

Secondly, this on its own appears to make the DPAA2 network interfaces
completely disappear.  Looking in /sys/bus/fsl-mc/drivers/*, none of
the DPAA2 drivers are bound to anything, and looking in
/sys/bus/fsl-mc/devices/, there is:

lrwxrwxrwx 1 root root 0 Mar  3 22:06 dprc.1 -> 
../../../devices/platform/soc/80c00.fsl-mc/dprc.1

This is booting with u-boot, so using DT rather than ACPI.


Signed-off-by: Laurentiu Tudor 
---
  drivers/bus/fsl-mc/fsl-mc-bus.c | 42 -
  1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 36eb25f82c8e..3df015eedae4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -132,11 +132,51 @@ static int fsl_mc_bus_uevent(struct device *dev, struct 
kobj_uevent_env *env)
  static int fsl_mc_dma_configure(struct device *dev)
  {
struct device *dma_dev = dev;
+   struct iommu_fwspec *fwspec;
+   const struct iommu_ops *iommu_ops;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   int ret;
+   u32 icid;
+
+   /* Skip DMA setup for devices that are not DMA masters */
+   if (dev->type == &fsl_mc_bus_dpmcp_type ||
+   dev->type == &fsl_mc_bus_dpbp_type ||
+   dev->type == &fsl_mc_bus_dpcon_type ||
+   dev->type == &fsl_mc_bus_dpio_type)
+   return 0;
  
  	while (dev_is_fsl_mc(dma_dev))

dma_dev = dma_dev->parent;
  
-	return of_dma_configure(dev, dma_dev->of_node, 0);

+   fwspec = dev_iommu_fwspec_get(dma_dev);
+   if (!fwspec)
+   return -ENODEV;


The problem appears to be here - fwspec is NULL for dprc.1.


Ok, that's because the iommu config is missing from the DT node that's 
exposing the MC firmware. I've attached a fresh set of patches that 
include on top the missing config and a workaround that makes MC work 
over SMMU. Also added the missing #include, thanks for pointing out.

Let me know how it goes.

---
Best Regards, Laurentiu
>From 3d418f04fed9c10b64b3b861d66378a8f7514cc4 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Thu, 13 Feb 2020 11:59:12 +0200
Subject: [PATCH 1/6] bus: fsl-mc: add custom .dma_configure implementation
Content-Type: text/plain; charset="us-ascii"

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.

Signed-off-by: Laurentiu Tudor 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 43 -
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a0f8854acb3a..e2682fbefb42 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "fsl-mc-private.h"
 
@@ -130,11 +131,51 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 static int fsl_mc_dma_configure(struct device *dev)
 {
 	struct device *dma_dev = dev;
+	struct iommu_fwspec *fwspec;
+	const struct iommu_ops *iommu_ops;
+	struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+	int ret;
+	u32 icid;
+
+	/* Skip DMA setup for devices that are not DMA masters */
+	if (dev->type == &fsl_mc_bus_dpmcp_type ||
+	dev->type == &fsl_mc_bus_dpbp_type ||
+	dev->type == &fsl_mc_bus_dpcon_type ||
+	dev->type == &fsl_mc_bus_dpio_type)
+		return 0;
 
 	while (dev_is_fsl_mc(dma_dev))
 		dma_dev = dma_dev->parent;
 
-	return of_dma_configure(dev, dma_dev->of_node, 0);
+	fwspec = dev_iommu_fwspec_get(dma_dev);
+	if (!fwspec)
+		return -ENODEV;
+	iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
+	if (!iommu_ops)
+		return -ENODEV;
+
+	ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
+	if (ret)
+		return ret;
+
+	icid = mc_dev->icid;
+	re

Re: [PATCH] iommu: silence iommu group prints

2020-03-04 Thread Laurentiu Tudor




On 04.03.2020 11:33, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 10:56:06AM +0200, Laurentiu Tudor wrote:


On 04.03.2020 00:17, Russell King - ARM Linux admin wrote:

On Tue, Mar 03, 2020 at 05:55:05PM +0200, Laurentiu Tudor wrote:

  From c98dc05cdd45ae923654f2427985bd28bcde4bb2 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Thu, 13 Feb 2020 11:59:12 +0200
Subject: [PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation
Content-Type: text/plain; charset="us-ascii"

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.


Firstly, applying this to v5.5 results in a build failure, due to a
missing linux/iommu.h include.

Secondly, this on its own appears to make the DPAA2 network interfaces
completely disappear.  Looking in /sys/bus/fsl-mc/drivers/*, none of
the DPAA2 drivers are bound to anything, and looking in
/sys/bus/fsl-mc/devices/, there is:

lrwxrwxrwx 1 root root 0 Mar  3 22:06 dprc.1 -> 
../../../devices/platform/soc/80c00.fsl-mc/dprc.1

This is booting with u-boot, so using DT rather than ACPI.


Signed-off-by: Laurentiu Tudor 
---
   drivers/bus/fsl-mc/fsl-mc-bus.c | 42 -
   1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 36eb25f82c8e..3df015eedae4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -132,11 +132,51 @@ static int fsl_mc_bus_uevent(struct device *dev, struct 
kobj_uevent_env *env)
   static int fsl_mc_dma_configure(struct device *dev)
   {
struct device *dma_dev = dev;
+   struct iommu_fwspec *fwspec;
+   const struct iommu_ops *iommu_ops;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   int ret;
+   u32 icid;
+
+   /* Skip DMA setup for devices that are not DMA masters */
+   if (dev->type == &fsl_mc_bus_dpmcp_type ||
+   dev->type == &fsl_mc_bus_dpbp_type ||
+   dev->type == &fsl_mc_bus_dpcon_type ||
+   dev->type == &fsl_mc_bus_dpio_type)
+   return 0;
while (dev_is_fsl_mc(dma_dev))
dma_dev = dma_dev->parent;
-   return of_dma_configure(dev, dma_dev->of_node, 0);
+   fwspec = dev_iommu_fwspec_get(dma_dev);
+   if (!fwspec)
+   return -ENODEV;


The problem appears to be here - fwspec is NULL for dprc.1.


Ok, that's because the iommu config is missing from the DT node that's
exposing the MC firmware. I've attached a fresh set of patches that include
on top the missing config and a workaround that makes MC work over SMMU.
Also added the missing #include, thanks for pointing out.
Let me know how it goes.


Shouldn't patch 6 should be first in the series, so that patch 1 does
not cause a regression and bisectability damage?



Correct, width one comment: both 5 and 6 should go first. Once iommu-map 
is added in the device tree the workaround for MC with the 
arm-smmu.disable_bypass boot arg will no longer work.


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


Re: [PATCH] iommu: silence iommu group prints

2020-03-04 Thread Laurentiu Tudor



On 04.03.2020 11:51, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 11:42:16AM +0200, Laurentiu Tudor wrote:

On 04.03.2020 11:33, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 10:56:06AM +0200, Laurentiu Tudor wrote:


On 04.03.2020 00:17, Russell King - ARM Linux admin wrote:

On Tue, Mar 03, 2020 at 05:55:05PM +0200, Laurentiu Tudor wrote:

   From c98dc05cdd45ae923654f2427985bd28bcde4bb2 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Thu, 13 Feb 2020 11:59:12 +0200
Subject: [PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation
Content-Type: text/plain; charset="us-ascii"

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.


Firstly, applying this to v5.5 results in a build failure, due to a
missing linux/iommu.h include.

Secondly, this on its own appears to make the DPAA2 network interfaces
completely disappear.  Looking in /sys/bus/fsl-mc/drivers/*, none of
the DPAA2 drivers are bound to anything, and looking in
/sys/bus/fsl-mc/devices/, there is:

lrwxrwxrwx 1 root root 0 Mar  3 22:06 dprc.1 -> 
../../../devices/platform/soc/80c00.fsl-mc/dprc.1

This is booting with u-boot, so using DT rather than ACPI.


Signed-off-by: Laurentiu Tudor 
---
drivers/bus/fsl-mc/fsl-mc-bus.c | 42 -
1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 36eb25f82c8e..3df015eedae4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -132,11 +132,51 @@ static int fsl_mc_bus_uevent(struct device *dev, struct 
kobj_uevent_env *env)
static int fsl_mc_dma_configure(struct device *dev)
{
struct device *dma_dev = dev;
+   struct iommu_fwspec *fwspec;
+   const struct iommu_ops *iommu_ops;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   int ret;
+   u32 icid;
+
+   /* Skip DMA setup for devices that are not DMA masters */
+   if (dev->type == &fsl_mc_bus_dpmcp_type ||
+   dev->type == &fsl_mc_bus_dpbp_type ||
+   dev->type == &fsl_mc_bus_dpcon_type ||
+   dev->type == &fsl_mc_bus_dpio_type)
+   return 0;
while (dev_is_fsl_mc(dma_dev))
dma_dev = dma_dev->parent;
-   return of_dma_configure(dev, dma_dev->of_node, 0);
+   fwspec = dev_iommu_fwspec_get(dma_dev);
+   if (!fwspec)
+   return -ENODEV;


The problem appears to be here - fwspec is NULL for dprc.1.


Ok, that's because the iommu config is missing from the DT node that's
exposing the MC firmware. I've attached a fresh set of patches that include
on top the missing config and a workaround that makes MC work over SMMU.
Also added the missing #include, thanks for pointing out.
Let me know how it goes.


Shouldn't patch 6 should be first in the series, so that patch 1 does
not cause a regression and bisectability damage?



Correct, width one comment: both 5 and 6 should go first. Once iommu-map is
added in the device tree the workaround for MC with the
arm-smmu.disable_bypass boot arg will no longer work.


So, wouldn't it be reasonable to arrange the patch series like that?



Sure, please see attached.

---
Best Regards, Laurentiu
>From 44ae46501b5379bd0890df87fd3827248626ed03 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Tue, 1 Oct 2019 16:22:48 +0300
Subject: [PATCH 1/6] bus: fsl-mc: make mc work with smmu disable bypass on
Content-Type: text/plain; charset="us-ascii"

Since this commit [1] booting kernel on MC based chips started to
fail because this firmware starts before the kernel and as soon as
SMMU is probed it starts to trigger contiguous faults.
This is a workaround that allows MC firmware to run with SMMU
in disable bypass mode. It consists of the following steps:
 1. pause the firmware at early boot to get a chance to setup SMMU
 2. request direct mapping for MC device
 3. resume the firmware
The workaround relies on the fact that no state is lost when
pausing / resuming firmware, as per the docs.
With this patch, platforms with MC firmware can now boot without
having to change the default config to set:
  CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT=n

[1] 954a03be033 ("iommu/arm-smmu: Break insecure users by disabling bypass by default")

Signed-off-by: Laurentiu Tudor 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 53 +
 1 file changed, 53 insertions(+)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a0f8854acb3a..683a6401ffe8 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fs

Re: [PATCH] iommu: silence iommu group prints

2020-03-04 Thread Laurentiu Tudor




On 04.03.2020 12:07, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 11:56:53AM +0200, Laurentiu Tudor wrote:

 From 44ae46501b5379bd0890df87fd3827248626ed03 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Tue, 1 Oct 2019 16:22:48 +0300
Subject: [PATCH 1/6] bus: fsl-mc: make mc work with smmu disable bypass on
Content-Type: text/plain; charset="us-ascii"

Since this commit [1] booting kernel on MC based chips started to
fail because this firmware starts before the kernel and as soon as
SMMU is probed it starts to trigger contiguous faults.


I think you mean "continuous" here.


Yes, thanks.


This is a workaround that allows MC firmware to run with SMMU
in disable bypass mode. It consists of the following steps:
  1. pause the firmware at early boot to get a chance to setup SMMU
  2. request direct mapping for MC device
  3. resume the firmware
The workaround relies on the fact that no state is lost when
pausing / resuming firmware, as per the docs.
With this patch, platforms with MC firmware can now boot without
having to change the default config to set:
   CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT=n


This alone is a definite improvement, and has been needed for a while.
Please submit this patch with an appropriate Fixes: tag so stable trees
can pick it up.


The thing is that probably this workaround will never make it in the 
kernel because it questionable to say the least, e.g. see [1]. My plan 
is to give this approach [2] a try sometime soon.


[1] https://patchwork.kernel.org/comment/23149049/
[2] https://patchwork.kernel.org/cover/11279577/

---
Best Regards, Laurentiu


[1] 954a03be033 ("iommu/arm-smmu: Break insecure users by disabling bypass by 
default")


Please put this where you're referencing it above - it's fine to wrap
the description of the commit when using it in the body of the commit
message.  However, that should _never_ when providing a Fixes: tag
(linux-next has a script which will detect and complain about broken
Fixes: tags.)

Thanks.



Signed-off-by: Laurentiu Tudor 
---
  drivers/bus/fsl-mc/fsl-mc-bus.c | 53 +
  1 file changed, 53 insertions(+)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a0f8854acb3a..683a6401ffe8 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -18,6 +18,8 @@
  #include 
  #include 
  #include 
+#include 
+#include 
  
  #include "fsl-mc-private.h"
  
@@ -889,6 +891,12 @@ static int get_mc_addr_translation_ranges(struct device *dev,

return 0;
  }
  
+#define FSL_MC_GCR1	0x0

+#define GCR1_P1_STOP   BIT(31)
+
+static u32 boot_gcr1;
+static void __iomem *fsl_mc_regs;
+
  /**
   * fsl_mc_bus_probe - callback invoked when the root MC bus is being
   * added
@@ -906,6 +914,21 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
struct mc_version mc_version;
struct resource res;
  
+	/*

+* The MC firmware requires full access to the whole address space plus
+* it has no way of dealing with any kind of address translation, so
+* request direct mapping for it.
+*/
+   error = iommu_request_dm_for_dev(&pdev->dev);
+   if (error)
+   dev_warn(&pdev->dev, "iommu_request_dm_for_dev() failed: %d\n",
+error);
+
+   if (fsl_mc_regs) {
+   /* Resume the firmware */
+   writel(boot_gcr1 & ~GCR1_P1_STOP, fsl_mc_regs + FSL_MC_GCR1);
+   }
+
mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
if (!mc)
return -ENOMEM;
@@ -990,6 +1013,13 @@ static int fsl_mc_bus_remove(struct platform_device *pdev)
if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev))
return -EINVAL;
  
+	/*

+* Pause back the firmware so that it doesn't trigger faults by the
+* time SMMU gets brought down.
+*/
+   writel(boot_gcr1 | GCR1_P1_STOP, fsl_mc_regs + FSL_MC_GCR1);
+   iounmap(fsl_mc_regs);
+
fsl_mc_device_remove(mc->root_mc_bus_dev);
  
  	fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io);

@@ -1018,6 +1048,8 @@ static struct platform_driver fsl_mc_bus_driver = {
  static int __init fsl_mc_bus_driver_init(void)
  {
int error;
+   struct device_node *np;
+   struct resource res;
  
  	error = bus_register(&fsl_mc_bus_type);

if (error < 0) {
@@ -1039,9 +1071,30 @@ static int __init fsl_mc_bus_driver_init(void)
if (error < 0)
goto error_cleanup_dprc_driver;
  
+	np = of_find_matching_node(NULL, fsl_mc_bus_match_table);

+   if (np && of_device_is_available(np)) {
+   error = of_address_to_resource(np, 1, &res);
+   if (error)
+   goto error_cleanup_dprc_driver;
+   fsl_mc_regs = ioremap(res.st

Re: [PATCH] iommu: silence iommu group prints

2020-03-04 Thread Laurentiu Tudor




On 04.03.2020 12:52, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 12:33:14PM +0200, Laurentiu Tudor wrote:



On 04.03.2020 12:07, Russell King - ARM Linux admin wrote:

On Wed, Mar 04, 2020 at 11:56:53AM +0200, Laurentiu Tudor wrote:

  From 44ae46501b5379bd0890df87fd3827248626ed03 Mon Sep 17 00:00:00 2001
From: Laurentiu Tudor 
Date: Tue, 1 Oct 2019 16:22:48 +0300
Subject: [PATCH 1/6] bus: fsl-mc: make mc work with smmu disable bypass on
Content-Type: text/plain; charset="us-ascii"

Since this commit [1] booting kernel on MC based chips started to
fail because this firmware starts before the kernel and as soon as
SMMU is probed it starts to trigger contiguous faults.


I think you mean "continuous" here.


Yes, thanks.


This is a workaround that allows MC firmware to run with SMMU
in disable bypass mode. It consists of the following steps:
   1. pause the firmware at early boot to get a chance to setup SMMU
   2. request direct mapping for MC device
   3. resume the firmware
The workaround relies on the fact that no state is lost when
pausing / resuming firmware, as per the docs.
With this patch, platforms with MC firmware can now boot without
having to change the default config to set:
CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT=n


This alone is a definite improvement, and has been needed for a while.
Please submit this patch with an appropriate Fixes: tag so stable trees
can pick it up.


The thing is that probably this workaround will never make it in the kernel
because it questionable to say the least, e.g. see [1]. My plan is to give
this approach [2] a try sometime soon.


So, if we want to reduce the iommu noise, we need to completely break
the ability to use a mainline kernel on the LX2160A.  This doesn't
seem practical nor sensible.  Someone has to give.



Well, I think it's a bit too early for such conclusions. I'd consider 
this stuff early / experimental work, probably will take quite a while 
for the dust to settle. Anyway, I'll take care not to break the kernel 
when I'll start submitting more official patches.

For now, I'm just hoping that this stuff helps fixing your local tree.

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


Re: [RFC 0/2] iommu: arm-smmu: Add support for early direct mappings

2020-03-04 Thread Laurentiu Tudor

Hello,

On 28.02.2020 04:57, Bjorn Andersson wrote:

On Mon 09 Dec 07:07 PST 2019, Thierry Reding wrote:


From: Thierry Reding 



Sorry for the slow response on this, finally got the time to go through
this in detail and try it out on some Qualcomm boards.


On some platforms, the firmware will setup hardware to read from a given
region of memory. One such example is a display controller that is
scanning out a splash screen from physical memory.



This particular use case is the one that we need to figure out for
Qualcomm devices as well; on some devices it's a simple splash screen
(that on many devices can be disabled), but for others we have EFIFB
on the display and no (sane) means to disable this.


During Linux' boot process, the ARM SMMU will configure all contexts to
fault by default. This means that memory accesses that happen by an SMMU
master before its driver has had a chance to properly set up the IOMMU
will cause a fault. This is especially annoying for something like the
display controller scanning out a splash screen because the faults will
result in the display controller getting bogus data (all-ones on Tegra)
and since it repeatedly scans that framebuffer, it will keep triggering
such faults and spam the boot log with them.



As my proposed patches indicated, the Qualcomm platform boots with
stream mapping setup for the hardware used by the bootloader, but
relying on the associated context banks not being enabled.

USFCFG in SCR0 is set and any faults resulting of this will trap into
secure world and the device will be reset.


In order to work around such problems, scan the device tree for IOMMU
masters and set up a special identity domain that will map 1:1 all of
the reserved regions associated with them. This happens before the SMMU
is enabled, so that the mappings are already set up before translations
begin.

One thing that was pointed out earlier, and which I don't have a good
idea on how to solve it, is that the early identity domain is not
discarded. The assumption is that the standard direct mappings code of
the IOMMU framework will replace the early identity domain once devices
are properly attached to domains, but we don't have a good point in time
when it would be safe to remove the early identity domain.

One option that I can think of would be to create an early identity
domain for each master and inherit it when that master is attached to
the domain later on, but that seems rather complicated from an book-
keeping point of view and tricky because we need to be careful not to
map regions twice, etc.



The one concern I ran into with this approach (after resolving below
issues) is that when the display driver probes a new domain will be
created automatically and I get a stream of "Unhandled context fault" in
the log until the driver has mapped the framebuffer in the newly
allocated context.

This is normally not a problem, as we seem to be able to do this
initialization in a few frames, but for the cases where the display
driver probe defer this is a problem.


Also gave this a go on one of NXP's layerscape platforms, and 
encountered the same issue. However, given that in our case it's not 
about a framebuffer device but a firmware, it cause it to crash. :-(


Another apparent problem is that in the current implementation only one 
memory-region per device is supported. Actually it appears that this is 
a limitation of the DT reservation binding - it doesn't seem to allow 
specifying multiple regions per device. In our firmware case we would 
need support for multiple reserved regions (FW memory, FW i/o registers 
a.s.o).


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


[RFC PATCH v2 1/2] iommu: arm-smmu: Extract arm_smmu_of_parse()

2020-03-17 Thread laurentiu . tudor
From: Thierry Reding 

This function will be subsequently used to extract stream ID information
early, before a struct device is available.

Signed-off-by: Thierry Reding 
---
 drivers/iommu/arm-smmu.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 16c4b87af42b..8a238d5a4b51 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1584,18 +1584,28 @@ static int arm_smmu_domain_set_attr(struct iommu_domain 
*domain,
return ret;
 }
 
-static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
+static int arm_smmu_of_parse(struct device_node *np, const u32 *args,
+unsigned int count)
 {
-   u32 mask, fwid = 0;
+   u32 fwid = 0, mask;
 
-   if (args->args_count > 0)
-   fwid |= FIELD_PREP(ARM_SMMU_SMR_ID, args->args[0]);
+   if (count > 0)
+   fwid |= FIELD_PREP(ARM_SMMU_SMR_ID, args[0]);
 
-   if (args->args_count > 1)
-   fwid |= FIELD_PREP(ARM_SMMU_SMR_MASK, args->args[1]);
-   else if (!of_property_read_u32(args->np, "stream-match-mask", &mask))
+   if (count > 1)
+   fwid |= FIELD_PREP(ARM_SMMU_SMR_MASK, args[1]);
+   else if (!of_property_read_u32(np, "stream-match-mask", &mask))
fwid |= FIELD_PREP(ARM_SMMU_SMR_MASK, mask);
 
+   return fwid;
+}
+
+static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+   u32 fwid;
+
+   fwid = arm_smmu_of_parse(args->np, args->args, args->args_count);
+
return iommu_fwspec_add_ids(dev, &fwid, 1);
 }
 
-- 
2.17.1

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


[RFC PATCH v2 2/2] iommu: arm-smmu: Add support for early direct mappings

2020-03-17 Thread laurentiu . tudor
From: Thierry Reding 

On platforms, the firmware will setup hardware to read from a given
region of memory. One such example is a display controller that is
scanning out a splash screen from physical memory.

During Linux's boot process, the ARM SMMU will configure all contexts to
fault by default. This means that memory accesses that happen by an SMMU
master before its driver has had a chance to properly set up the IOMMU
will cause a fault. This is especially annoying for something like the
display controller scanning out a splash screen because the faults will
result in the display controller getting bogus data (all-ones on Tegra)
and since it repeatedly scans that framebuffer, it will keep triggering
such faults and spam the boot log with them.

In order to work around such problems, scan the device tree for IOMMU
masters and set up a special identity domain that will map 1:1 all of
the reserved regions associated with them. This happens before the SMMU
is enabled, so that the mappings are already set up before translations
begin.

Signed-off-by: Thierry Reding 
Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/arm-smmu.c | 257 ++-
 drivers/iommu/arm-smmu.h |   3 +
 2 files changed, 259 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8a238d5a4b51..083566a27eef 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1158,6 +1158,135 @@ static int arm_smmu_domain_add_master(struct 
arm_smmu_domain *smmu_domain,
return 0;
 }
 
+static int arm_smmu_identity_map_regions(struct iommu_domain *dom,
+struct arm_smmu_device *smmu,
+struct device_node *np)
+{
+   struct device *dev = smmu->dev;
+   struct of_phandle_iterator it;
+   unsigned long page_size;
+   unsigned int count = 0;
+   int ret;
+
+   page_size = 1UL << __ffs(dom->pgsize_bitmap);
+
+   /* parse memory regions and add them to the identity mapping */
+   of_for_each_phandle(&it, ret, np, "memory-region", NULL, 0) {
+   int prot = IOMMU_READ | IOMMU_WRITE;
+   dma_addr_t start, limit, iova;
+   struct resource res;
+
+   ret = of_address_to_resource(it.node, 0, &res);
+   if (ret < 0) {
+   dev_err(dev, "failed to parse memory region %pOF: %d\n",
+   it.node, ret);
+   continue;
+   }
+
+   /* check that region is not empty */
+   if (resource_size(&res) == 0) {
+   dev_dbg(dev, "skipping empty memory region %pOF\n",
+   it.node);
+   continue;
+   }
+
+   start = ALIGN(res.start, page_size);
+   limit = ALIGN(res.start + resource_size(&res), page_size);
+
+   for (iova = start; iova < limit; iova += page_size) {
+   phys_addr_t phys;
+
+   /* check that this IOVA isn't already mapped */
+   phys = iommu_iova_to_phys(dom, iova);
+   if (phys)
+   continue;
+
+   ret = iommu_map(dom, iova, iova, page_size,
+   prot);
+   if (ret < 0) {
+   dev_err(dev, "failed to map %pad for %pOF: 
%d\n",
+   &iova, it.node, ret);
+   continue;
+   }
+   }
+
+   dev_dbg(dev, "identity mapped memory region %pR\n", &res);
+   count++;
+   }
+
+   return count;
+}
+
+static bool arm_smmu_identity_unmap_regions(struct arm_smmu_device *smmu,
+   struct device_node *np)
+{
+   struct device *dev = smmu->dev;
+   struct of_phandle_iterator it;
+   unsigned long page_size;
+   int ret;
+   bool unmapped = false;
+
+   page_size = 1UL << __ffs(smmu->identity->pgsize_bitmap);
+
+   /* parse memory regions and add them to the identity mapping */
+   of_for_each_phandle(&it, ret, np, "memory-region", NULL, 0) {
+   dma_addr_t start, limit, iova;
+   struct resource res;
+
+   ret = of_address_to_resource(it.node, 0, &res);
+   if (ret < 0) {
+   dev_err(dev, "failed to parse memory region %pOF: %d\n",
+   it.node, ret);
+   continue;
+   }
+
+   /* check that region is not empty */
+   if (resource_size(&res) == 0) {
+   dev_dbg(dev, "skipping empt

[RFC PATCH v2 0/2] iommu: arm-smmu: Add support for early direct mappings

2020-03-17 Thread laurentiu . tudor
From: Thierry Reding 

On some platforms, the firmware will setup hardware to read from a given
region of memory. One such example is a display controller that is
scanning out a splash screen from physical memory.

During Linux' boot process, the ARM SMMU will configure all contexts to
fault by default. This means that memory accesses that happen by an SMMU
master before its driver has had a chance to properly set up the IOMMU
will cause a fault. This is especially annoying for something like the
display controller scanning out a splash screen because the faults will
result in the display controller getting bogus data (all-ones on Tegra)
and since it repeatedly scans that framebuffer, it will keep triggering
such faults and spam the boot log with them.

In order to work around such problems, scan the device tree for IOMMU
masters and set up a special identity domain that will map 1:1 all of
the reserved regions associated with them. This happens before the SMMU
is enabled, so that the mappings are already set up before translations
begin.

One thing that was pointed out earlier, and which I don't have a good
idea on how to solve it, is that the early identity domain is not
discarded. The assumption is that the standard direct mappings code of
the IOMMU framework will replace the early identity domain once devices
are properly attached to domains, but we don't have a good point in time
when it would be safe to remove the early identity domain.

One option that I can think of would be to create an early identity
domain for each master and inherit it when that master is attached to
the domain later on, but that seems rather complicated from an book-
keeping point of view and tricky because we need to be careful not to
map regions twice, etc.

Any good ideas on how to solve this? It'd also be interesting to see if
there's a more generic way of doing this. I know that something like
this isn't necessary on earlier Tegra SoCs with the custom Tegra SMMU
because translations are only enabled when the devices are attached to a
domain. I'm not sure about other IOMMUs, but in the absence of a struct
device, I suspect that we can't really do anything really generic that
would work across drivers.

Previous version: https://patchwork.kernel.org/cover/11279577/

Changes in v2:
 - recreate identity mappings when the device is placed in its rightful domain
 - delete its original identity mappings from the identity domain
 - added a counter to keep track of number of devices with identity mappings
 - free identity domain when the counter reaches 0
 - this should help fix our firmware issue, mentioned here [1]

[1] https://patchwork.kernel.org/comment/23200041/

Thierry Reding (2):
  iommu: arm-smmu: Extract arm_smmu_of_parse()
  iommu: arm-smmu: Add support for early direct mappings

 drivers/iommu/arm-smmu.c | 280 +--
 drivers/iommu/arm-smmu.h |   3 +
 2 files changed, 275 insertions(+), 8 deletions(-)

-- 
2.17.1

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


Re: [RFC PATCH v2 0/2] iommu: arm-smmu: Add support for early direct mappings

2020-03-17 Thread Laurentiu Tudor

[ +Russell ]

Forgot to Cc: you Russell, sorry about that. This patch series could be 
an important step towards fixing the MC firmware over smmu issue on nxp 
layerscape chips.


---

Best Regards, Laurentiu

On 3/17/2020 4:21 PM, laurentiu.tu...@nxp.com wrote:

From: Thierry Reding 

On some platforms, the firmware will setup hardware to read from a given
region of memory. One such example is a display controller that is
scanning out a splash screen from physical memory.

During Linux' boot process, the ARM SMMU will configure all contexts to
fault by default. This means that memory accesses that happen by an SMMU
master before its driver has had a chance to properly set up the IOMMU
will cause a fault. This is especially annoying for something like the
display controller scanning out a splash screen because the faults will
result in the display controller getting bogus data (all-ones on Tegra)
and since it repeatedly scans that framebuffer, it will keep triggering
such faults and spam the boot log with them.

In order to work around such problems, scan the device tree for IOMMU
masters and set up a special identity domain that will map 1:1 all of
the reserved regions associated with them. This happens before the SMMU
is enabled, so that the mappings are already set up before translations
begin.

One thing that was pointed out earlier, and which I don't have a good
idea on how to solve it, is that the early identity domain is not
discarded. The assumption is that the standard direct mappings code of
the IOMMU framework will replace the early identity domain once devices
are properly attached to domains, but we don't have a good point in time
when it would be safe to remove the early identity domain.

One option that I can think of would be to create an early identity
domain for each master and inherit it when that master is attached to
the domain later on, but that seems rather complicated from an book-
keeping point of view and tricky because we need to be careful not to
map regions twice, etc.

Any good ideas on how to solve this? It'd also be interesting to see if
there's a more generic way of doing this. I know that something like
this isn't necessary on earlier Tegra SoCs with the custom Tegra SMMU
because translations are only enabled when the devices are attached to a
domain. I'm not sure about other IOMMUs, but in the absence of a struct
device, I suspect that we can't really do anything really generic that
would work across drivers.

Previous version: 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11279577%2F&data=02%7C01%7Claurentiu.tudor%40nxp.com%7Cb40c3ee306224a2fc8fe08d7ca7e8007%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637200517038451677&sdata=rq8Ojkh1fovakZ2jTGHjSUaYROtvjY8ZDItEiqCTuI4%3D&reserved=0

Changes in v2:
  - recreate identity mappings when the device is placed in its rightful domain
  - delete its original identity mappings from the identity domain
  - added a counter to keep track of number of devices with identity mappings
  - free identity domain when the counter reaches 0
  - this should help fix our firmware issue, mentioned here [1]

[1] 
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcomment%2F23200041%2F&data=02%7C01%7Claurentiu.tudor%40nxp.com%7Cb40c3ee306224a2fc8fe08d7ca7e8007%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637200517038451677&sdata=Q0T326D1QMz5EtWY%2BzVUxdd01AbKySe8Ota66H2rkiI%3D&reserved=0

Thierry Reding (2):
   iommu: arm-smmu: Extract arm_smmu_of_parse()
   iommu: arm-smmu: Add support for early direct mappings

  drivers/iommu/arm-smmu.c | 280 +--
  drivers/iommu/arm-smmu.h |   3 +
  2 files changed, 275 insertions(+), 8 deletions(-)


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


[RFC PATCH v2 1/4] bus: fsl-mc: add custom .dma_configure implementation

2020-03-24 Thread laurentiu . tudor
From: Laurentiu Tudor 

The devices on this bus are not discovered by way of device tree
but by queries to the firmware. It makes little sense to trick the
generic of layer into thinking that these devices are of related so
that we can get our dma configuration. Instead of doing that, add
our custom dma configuration implementation.

Signed-off-by: Laurentiu Tudor 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 50 -
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a0f8854acb3a..a3d25c1d4ff8 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "fsl-mc-private.h"
 
@@ -130,11 +131,58 @@ static int fsl_mc_bus_uevent(struct device *dev, struct 
kobj_uevent_env *env)
 static int fsl_mc_dma_configure(struct device *dev)
 {
struct device *dma_dev = dev;
+   struct iommu_fwspec *fwspec;
+   const struct iommu_ops *iommu_ops;
+   struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+   int ret;
+   u32 icid;
+
+   /* Skip DMA setup for devices that are not DMA masters */
+   if (dev->type == &fsl_mc_bus_dpmcp_type ||
+   dev->type == &fsl_mc_bus_dpbp_type ||
+   dev->type == &fsl_mc_bus_dpcon_type ||
+   dev->type == &fsl_mc_bus_dpio_type)
+   return 0;
 
while (dev_is_fsl_mc(dma_dev))
dma_dev = dma_dev->parent;
 
-   return of_dma_configure(dev, dma_dev->of_node, 0);
+   fwspec = dev_iommu_fwspec_get(dma_dev);
+   if (!fwspec)
+   return -ENODEV;
+   iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
+   if (!iommu_ops)
+   return -ENODEV;
+
+   ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
+   if (ret)
+   return ret;
+
+   if (iommu_ops->of_xlate) {
+   struct of_phandle_args iommu_spec = {
+   .np = fwspec->iommu_fwnode->dev->of_node,
+   .args[0] = mc_dev->icid,
+   .args_count = 1
+   };
+
+   ret = iommu_ops->of_xlate(dev, &iommu_spec);
+   if (ret) {
+   iommu_fwspec_free(dev);
+   return ret;
+   }
+   }
+
+   if (!device_iommu_mapped(dev)) {
+   ret = iommu_probe_device(dev);
+   if (ret) {
+   iommu_fwspec_free(dev);
+   return ret;
+   }
+   }
+
+   arch_setup_dma_ops(dev, 0, *dma_dev->dma_mask + 1, iommu_ops, true);
+
+   return 0;
 }
 
 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
-- 
2.17.1

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


[RFC PATCH v2 2/4] irqchip/fsl-mc: Change the way the IRQ domain is set for MC devices

2020-03-24 Thread laurentiu . tudor
From: Diana Craciun 

In ACPI the MC bus is represented as a platform device and a named
component in the IORT table. The mc-bus devices are discovered
dynamically at runtime but they share the same fwnode with the parent
platfom device. This patch changes the way the IRQ domain is searched
for the MC devices: it takes the fwnode reference from the parent and
uses the fwnode reference to find the MC IRQ domain.

Signed-off-by: Diana Craciun 
---
 drivers/bus/fsl-mc/fsl-mc-msi.c | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c
index 8b9c66d7c4ff..1e2e97329781 100644
--- a/drivers/bus/fsl-mc/fsl-mc-msi.c
+++ b/drivers/bus/fsl-mc/fsl-mc-msi.c
@@ -182,16 +182,23 @@ int fsl_mc_find_msi_domain(struct device *mc_platform_dev,
 {
struct irq_domain *msi_domain;
struct device_node *mc_of_node = mc_platform_dev->of_node;
+   struct fwnode_handle *fwnode;
 
-   msi_domain = of_msi_get_domain(mc_platform_dev, mc_of_node,
-  DOMAIN_BUS_FSL_MC_MSI);
+   msi_domain = dev_get_msi_domain(mc_platform_dev);
if (!msi_domain) {
pr_err("Unable to find fsl-mc MSI domain for %pOF\n",
   mc_of_node);
 
return -ENOENT;
}
+   fwnode = msi_domain->fwnode;
+   msi_domain = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_FSL_MC_MSI);
+   if (!msi_domain) {
+   pr_err("Unable to find fsl-mc MSI domain for %pOF\n",
+  mc_of_node);
 
+   return -ENOENT;
+   }
*mc_msi_domain = msi_domain;
return 0;
 }
-- 
2.17.1

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


[RFC PATCH v2 0/4] bus: fsl-mc: Add ACPI support for fsl-mc

2020-03-24 Thread laurentiu . tudor
From: Laurentiu Tudor 

This patch adds ACPI support for the fsl-mc bus driver. First 2 patches
are prerequsite that remove dependencies on device tree. Third patch
adds the actual ACPI support and the final one drops some fsl-mc
specific code in the generic device tree handling code.

Changes in v2:
 - add missing of_xlate call in custom .dma_configure (patch 1)
 - added a cover letter

Diana Craciun (1):
  irqchip/fsl-mc: Change the way the IRQ domain is set for MC devices

Laurentiu Tudor (2):
  bus: fsl-mc: add custom .dma_configure implementation
  iommu/of: get rid of fsl-mc specific code

Makarand Pawagi (1):
  bus: fsl-mc: Add ACPI support for fsl-mc

 drivers/bus/fsl-mc/fsl-mc-bus.c | 85 -
 drivers/bus/fsl-mc/fsl-mc-msi.c | 11 ++-
 drivers/iommu/of_iommu.c| 20 -
 drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c | 69 -
 4 files changed, 145 insertions(+), 40 deletions(-)

-- 
2.17.1

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


[RFC PATCH v2 3/4] bus: fsl-mc: Add ACPI support for fsl-mc

2020-03-24 Thread laurentiu . tudor
From: Makarand Pawagi 

ACPI support is added in the fsl-mc driver. Driver will parse
MC DSDT table to extract memory and other resorces.

Interrupt (GIC ITS) information will be extracted from MADT table
by drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c.

IORT table will be parsed to configure DMA.

Signed-off-by: Makarand Pawagi 
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 35 ++-
 drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c | 69 -
 2 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index a3d25c1d4ff8..fbd248597e88 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -952,7 +952,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
phys_addr_t mc_portal_phys_addr;
u32 mc_portal_size;
struct mc_version mc_version;
-   struct resource res;
+   struct resource *plat_res;
 
mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
if (!mc)
@@ -963,16 +963,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
/*
 * Get physical address of MC portal for the root DPRC:
 */
-   error = of_address_to_resource(pdev->dev.of_node, 0, &res);
-   if (error < 0) {
-   dev_err(&pdev->dev,
-   "of_address_to_resource() failed for %pOF\n",
-   pdev->dev.of_node);
-   return error;
-   }
-
-   mc_portal_phys_addr = res.start;
-   mc_portal_size = resource_size(&res);
+   plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+   mc_portal_phys_addr = plat_res->start;
+   mc_portal_size = resource_size(plat_res);
error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
 mc_portal_size, NULL,
 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io);
@@ -989,11 +982,13 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n",
 mc_version.major, mc_version.minor, mc_version.revision);
 
-   error = get_mc_addr_translation_ranges(&pdev->dev,
-  &mc->translation_ranges,
-  &mc->num_translation_ranges);
-   if (error < 0)
-   goto error_cleanup_mc_io;
+   if (dev_of_node(&pdev->dev)) {
+   error = get_mc_addr_translation_ranges(&pdev->dev,
+   &mc->translation_ranges,
+   &mc->num_translation_ranges);
+   if (error < 0)
+   goto error_cleanup_mc_io;
+   }
 
error = dprc_get_container_id(mc_io, 0, &container_id);
if (error < 0) {
@@ -1020,6 +1015,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
goto error_cleanup_mc_io;
 
mc->root_mc_bus_dev = mc_bus_dev;
+   mc_bus_dev->dev.fwnode = pdev->dev.fwnode;
return 0;
 
 error_cleanup_mc_io:
@@ -1053,11 +1049,18 @@ static const struct of_device_id 
fsl_mc_bus_match_table[] = {
 
 MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table);
 
+static const struct acpi_device_id fsl_mc_bus_acpi_match_table[] = {
+   {"NXP0008", 0 },
+   { }
+};
+MODULE_DEVICE_TABLE(acpi, fsl_mc_bus_acpi_match_table);
+
 static struct platform_driver fsl_mc_bus_driver = {
.driver = {
   .name = "fsl_mc_bus",
   .pm = NULL,
   .of_match_table = fsl_mc_bus_match_table,
+  .acpi_match_table = fsl_mc_bus_acpi_match_table,
   },
.probe = fsl_mc_bus_probe,
.remove = fsl_mc_bus_remove,
diff --git a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c 
b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
index 606efa64adff..6d67834722c9 100644
--- a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
@@ -4,9 +4,11 @@
  *
  * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
  * Author: German Rivera 
+ * Copyright 2020 NXP
  *
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -66,7 +68,65 @@ static const struct of_device_id its_device_id[] = {
{},
 };
 
-static int __init its_fsl_mc_msi_init(void)
+static int __init its_fsl_mc_msi_init_one(struct fwnode_handle *handle,
+ const char *name)
+{
+   struct irq_domain *parent;
+   struct irq_domain *mc_msi_domain;
+
+   parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
+   if (!parent || !msi_get_domain_info(parent)) {
+   pr_err("%s: Unable to locate ITS domain\n", name);
+   return -ENXIO;
+   }
+
+   mc_msi_domain = fsl_mc_msi_create_irq_domain(handle,
+
&its_fsl_mc_msi_domain_info,
+

[RFC PATCH v2 4/4] iommu/of: get rid of fsl-mc specific code

2020-03-24 Thread laurentiu . tudor
From: Laurentiu Tudor 

Changing the way we configure dma for fsl-mc devices allows
us to get rid of our fsl-mc specific code in the generic
of iommu code.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/of_iommu.c | 20 
 1 file changed, 20 deletions(-)

diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 20738aacac89..332072ada474 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -15,7 +15,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #define NO_IOMMU   1
 
@@ -139,23 +138,6 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 
alias, void *data)
return err;
 }
 
-static int of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev,
-   struct device_node *master_np)
-{
-   struct of_phandle_args iommu_spec = { .args_count = 1 };
-   int err;
-
-   err = of_map_rid(master_np, mc_dev->icid, "iommu-map",
-"iommu-map-mask", &iommu_spec.np,
-iommu_spec.args);
-   if (err)
-   return err == -ENODEV ? NO_IOMMU : err;
-
-   err = of_iommu_xlate(&mc_dev->dev, &iommu_spec);
-   of_node_put(iommu_spec.np);
-   return err;
-}
-
 const struct iommu_ops *of_iommu_configure(struct device *dev,
   struct device_node *master_np)
 {
@@ -188,8 +170,6 @@ const struct iommu_ops *of_iommu_configure(struct device 
*dev,
pci_request_acs();
err = pci_for_each_dma_alias(to_pci_dev(dev),
 of_pci_iommu_init, &info);
-   } else if (dev_is_fsl_mc(dev)) {
-   err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np);
} else {
struct of_phandle_args iommu_spec;
int idx = 0;
-- 
2.17.1

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


Re: [RFC PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation

2020-03-25 Thread Laurentiu Tudor
Hi Lorenzo,

On 3/25/2020 2:51 PM, Lorenzo Pieralisi wrote:
> On Thu, Feb 27, 2020 at 12:05:39PM +0200, laurentiu.tu...@nxp.com wrote:
>> From: Laurentiu Tudor 
>>
>> The devices on this bus are not discovered by way of device tree
>> but by queries to the firmware. It makes little sense to trick the
>> generic of layer into thinking that these devices are of related so
>> that we can get our dma configuration. Instead of doing that, add
>> our custom dma configuration implementation.
>>
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>  drivers/bus/fsl-mc/fsl-mc-bus.c | 31 ++-
>>  1 file changed, 30 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c 
>> b/drivers/bus/fsl-mc/fsl-mc-bus.c
>> index 36eb25f82c8e..eafaa0e0b906 100644
>> --- a/drivers/bus/fsl-mc/fsl-mc-bus.c
>> +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
>> @@ -132,11 +132,40 @@ static int fsl_mc_bus_uevent(struct device *dev, 
>> struct kobj_uevent_env *env)
>>  static int fsl_mc_dma_configure(struct device *dev)
>>  {
>>  struct device *dma_dev = dev;
>> +struct iommu_fwspec *fwspec;
>> +const struct iommu_ops *iommu_ops;
>> +struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
>> +int ret;
>> +u32 icid;
>>  
>>  while (dev_is_fsl_mc(dma_dev))
>>  dma_dev = dma_dev->parent;
>>  
>> -return of_dma_configure(dev, dma_dev->of_node, 0);
>> +fwspec = dev_iommu_fwspec_get(dma_dev);
>> +if (!fwspec)
>> +return -ENODEV;
>> +iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
>> +if (!iommu_ops)
>> +return -ENODEV;
>> +
>> +ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
>> +if (ret)
>> +return ret;
>> +
>> +icid = mc_dev->icid;
>> +ret = iommu_fwspec_add_ids(dev, &icid, 1);
> 
> I see. So with this patch we would use the MC named component only to
> retrieve the iommu_ops

Right. I'd also add that the implementation tries to follow the existing
standard .dma_configure implementations, e.g. of_dma_configure +
of_iommu_configure. I'd also note that similarly to the ACPI case, this
MC FW device is probed as a platform device in the DT scenario, binding
here [1].
A similar approach is used for the retrieval of the msi irq domain, see
following patch.

> - the streamid are injected directly here bypassing OF/IORT bindings 
> translations altogether. 

Actually I've submitted a v2 [2] that calls into .of_xlate() to allow
the smmu driver to do some processing on the raw streamid coming from
the firmware. I have not yet tested this with ACPI but expect it to
work, however, it's debatable how valid is this approach in the context
of ACPI.

> Am I reading this code correctly ?

Yes. Thanks for taking the time.

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
[2] https://www.spinics.net/lists/arm-kernel/msg794757.html

---
Best Regards, Laurentiu

> 
>> +if (ret)
>> +return ret;
>> +
>> +if (!device_iommu_mapped(dev)) {
>> +ret = iommu_probe_device(dev);
>> +if (ret)
>> +return ret;
>> +}
>> +
>> +arch_setup_dma_ops(dev, 0, *dma_dev->dma_mask + 1, iommu_ops, true);
>> +
>> +return 0;
>>  }
>>  
>>  static ssize_t modalias_show(struct device *dev, struct device_attribute 
>> *attr,
>> -- 
>> 2.17.1
>>
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [RFC PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation

2020-04-15 Thread Laurentiu Tudor



On 4/14/2020 5:32 PM, Lorenzo Pieralisi wrote:
> On Wed, Mar 25, 2020 at 06:48:55PM +0200, Laurentiu Tudor wrote:
>> Hi Lorenzo,
>>
>> On 3/25/2020 2:51 PM, Lorenzo Pieralisi wrote:
>>> On Thu, Feb 27, 2020 at 12:05:39PM +0200, laurentiu.tu...@nxp.com wrote:
>>>> From: Laurentiu Tudor 
>>>>
>>>> The devices on this bus are not discovered by way of device tree
>>>> but by queries to the firmware. It makes little sense to trick the
>>>> generic of layer into thinking that these devices are of related so
>>>> that we can get our dma configuration. Instead of doing that, add
>>>> our custom dma configuration implementation.
>>>>
>>>> Signed-off-by: Laurentiu Tudor 
>>>> ---
>>>>  drivers/bus/fsl-mc/fsl-mc-bus.c | 31 ++-
>>>>  1 file changed, 30 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c 
>>>> b/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>> index 36eb25f82c8e..eafaa0e0b906 100644
>>>> --- a/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>> +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>> @@ -132,11 +132,40 @@ static int fsl_mc_bus_uevent(struct device *dev, 
>>>> struct kobj_uevent_env *env)
>>>>  static int fsl_mc_dma_configure(struct device *dev)
>>>>  {
>>>>struct device *dma_dev = dev;
>>>> +  struct iommu_fwspec *fwspec;
>>>> +  const struct iommu_ops *iommu_ops;
>>>> +  struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
>>>> +  int ret;
>>>> +  u32 icid;
>>>>  
>>>>while (dev_is_fsl_mc(dma_dev))
>>>>dma_dev = dma_dev->parent;
>>>>  
>>>> -  return of_dma_configure(dev, dma_dev->of_node, 0);
>>>> +  fwspec = dev_iommu_fwspec_get(dma_dev);
>>>> +  if (!fwspec)
>>>> +  return -ENODEV;
>>>> +  iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
>>>> +  if (!iommu_ops)
>>>> +  return -ENODEV;
>>>> +
>>>> +  ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
>>>> +  if (ret)
>>>> +  return ret;
>>>> +
>>>> +  icid = mc_dev->icid;
>>>> +  ret = iommu_fwspec_add_ids(dev, &icid, 1);
>>>
>>> I see. So with this patch we would use the MC named component only to
>>> retrieve the iommu_ops
>>
>> Right. I'd also add that the implementation tries to follow the existing
>> standard .dma_configure implementations, e.g. of_dma_configure +
>> of_iommu_configure. I'd also note that similarly to the ACPI case, this
>> MC FW device is probed as a platform device in the DT scenario, binding
>> here [1].
>> A similar approach is used for the retrieval of the msi irq domain, see
>> following patch.
>>
>>> - the streamid are injected directly here bypassing OF/IORT bindings 
>>> translations altogether. 
>>
>> Actually I've submitted a v2 [2] that calls into .of_xlate() to allow
>> the smmu driver to do some processing on the raw streamid coming from
>> the firmware. I have not yet tested this with ACPI but expect it to
>> work, however, it's debatable how valid is this approach in the context
>> of ACPI.
> 
> Actually, what I think you need is of_map_rid() (and an IORT
> equivalent, that I am going to write - generalizing iort_msi_map_rid()).
> 
> Would that be enough to enable IORT "normal" mappings in the MC bus
> named components ?
> 

At a first glance, looks like this could very well fix the ACPI
scenario, but I have some unclarities on the approach:
 * are we going to rely in DT and ACPI generic layers even if these
devices are not published / enumerated through DT or ACPI tables?
 * the firmware manages and provides discrete streamids for the devices
it exposes so there's no translation involved. There's no
   requestor_id / input_id involved but it seems that we would still do
some kind of translation relying for this on the DT/ACPI functions.
 * MC firmware has its own stream_id (e.g. on some chips 0x4000, others
0xf00, so outside the range of stream_ids used for the mc devices)
   while for the devices on this bus, MC allocates stream_ids from a
range (e.g. 0x17 - 0x3f). Is it possible to describe this in the IORT table?
 * Regarding the of_map_rid() use you mentioned, I was planning to
decouple the mc bus from the DT layer by dropping the use of
of_map_rid(), see patch 4.
I briefly glanced over the iort code and spotted this static function:
iort_iommu_xlate(). Wouldn't it also help, of course after making it public?

---
Thanks & Best Regards, Laurentiu

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


Re: [RFC PATCH 1/4] bus: fsl-mc: add custom .dma_configure implementation

2020-04-16 Thread Laurentiu Tudor



On 4/15/2020 7:04 PM, Lorenzo Pieralisi wrote:
> On Wed, Apr 15, 2020 at 06:44:37PM +0300, Laurentiu Tudor wrote:
>>
>>
>> On 4/14/2020 5:32 PM, Lorenzo Pieralisi wrote:
>>> On Wed, Mar 25, 2020 at 06:48:55PM +0200, Laurentiu Tudor wrote:
>>>> Hi Lorenzo,
>>>>
>>>> On 3/25/2020 2:51 PM, Lorenzo Pieralisi wrote:
>>>>> On Thu, Feb 27, 2020 at 12:05:39PM +0200, laurentiu.tu...@nxp.com wrote:
>>>>>> From: Laurentiu Tudor 
>>>>>>
>>>>>> The devices on this bus are not discovered by way of device tree
>>>>>> but by queries to the firmware. It makes little sense to trick the
>>>>>> generic of layer into thinking that these devices are of related so
>>>>>> that we can get our dma configuration. Instead of doing that, add
>>>>>> our custom dma configuration implementation.
>>>>>>
>>>>>> Signed-off-by: Laurentiu Tudor 
>>>>>> ---
>>>>>>  drivers/bus/fsl-mc/fsl-mc-bus.c | 31 ++-
>>>>>>  1 file changed, 30 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c 
>>>>>> b/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>>>> index 36eb25f82c8e..eafaa0e0b906 100644
>>>>>> --- a/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>>>> +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
>>>>>> @@ -132,11 +132,40 @@ static int fsl_mc_bus_uevent(struct device *dev, 
>>>>>> struct kobj_uevent_env *env)
>>>>>>  static int fsl_mc_dma_configure(struct device *dev)
>>>>>>  {
>>>>>>  struct device *dma_dev = dev;
>>>>>> +struct iommu_fwspec *fwspec;
>>>>>> +const struct iommu_ops *iommu_ops;
>>>>>> +struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
>>>>>> +int ret;
>>>>>> +u32 icid;
>>>>>>  
>>>>>>  while (dev_is_fsl_mc(dma_dev))
>>>>>>  dma_dev = dma_dev->parent;
>>>>>>  
>>>>>> -return of_dma_configure(dev, dma_dev->of_node, 0);
>>>>>> +fwspec = dev_iommu_fwspec_get(dma_dev);
>>>>>> +if (!fwspec)
>>>>>> +return -ENODEV;
>>>>>> +iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode);
>>>>>> +if (!iommu_ops)
>>>>>> +return -ENODEV;
>>>>>> +
>>>>>> +ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops);
>>>>>> +if (ret)
>>>>>> +return ret;
>>>>>> +
>>>>>> +icid = mc_dev->icid;
>>>>>> +ret = iommu_fwspec_add_ids(dev, &icid, 1);
>>>>>
>>>>> I see. So with this patch we would use the MC named component only to
>>>>> retrieve the iommu_ops
>>>>
>>>> Right. I'd also add that the implementation tries to follow the existing
>>>> standard .dma_configure implementations, e.g. of_dma_configure +
>>>> of_iommu_configure. I'd also note that similarly to the ACPI case, this
>>>> MC FW device is probed as a platform device in the DT scenario, binding
>>>> here [1].
>>>> A similar approach is used for the retrieval of the msi irq domain, see
>>>> following patch.
>>>>
>>>>> - the streamid are injected directly here bypassing OF/IORT bindings 
>>>>> translations altogether. 
>>>>
>>>> Actually I've submitted a v2 [2] that calls into .of_xlate() to allow
>>>> the smmu driver to do some processing on the raw streamid coming from
>>>> the firmware. I have not yet tested this with ACPI but expect it to
>>>> work, however, it's debatable how valid is this approach in the context
>>>> of ACPI.
>>>
>>> Actually, what I think you need is of_map_rid() (and an IORT
>>> equivalent, that I am going to write - generalizing iort_msi_map_rid()).
>>>
>>> Would that be enough to enable IORT "normal" mappings in the MC bus
>>> named components ?
>>>
>>
>> At a first glance, looks like this could very well fix the ACPI
>> scenario, but I have some unclarities on the approach:

Re: [PATCH 12/12] bus: fsl-mc: Add ACPI support for fsl-mc

2020-05-21 Thread Laurentiu Tudor
Hi Lorenzo,

On 5/21/2020 4:00 PM, Lorenzo Pieralisi wrote:
> From: Diana Craciun 
> 
> Add ACPI support in the fsl-mc driver. Driver parses MC DSDT table to
> extract memory and other resources.
> 
> Interrupt (GIC ITS) information is extracted from the MADT table
> by drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c.
> 
> IORT table is parsed to configure DMA.
> 
> Signed-off-by: Makarand Pawagi 
> Signed-off-by: Diana Craciun 
> Signed-off-by: Laurentiu Tudor 
> ---

The author of this patch should be Makarand. I think I accidentaly broke
it when we exchanged the patches. Very sorry about it.

---
Best Regards, Laurentiu


>  drivers/bus/fsl-mc/fsl-mc-bus.c | 73 +++-
>  drivers/bus/fsl-mc/fsl-mc-msi.c | 37 +-
>  drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c | 75 -
>  3 files changed, 150 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
> index 824ff77bbe86..324d49d6df89 100644
> --- a/drivers/bus/fsl-mc/fsl-mc-bus.c
> +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
> @@ -18,6 +18,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  
>  #include "fsl-mc-private.h"
>  
> @@ -38,6 +40,7 @@ struct fsl_mc {
>   struct fsl_mc_device *root_mc_bus_dev;
>   u8 num_translation_ranges;
>   struct fsl_mc_addr_translation_range *translation_ranges;
> + void *fsl_mc_regs;
>  };
>  
>  /**
> @@ -56,6 +59,10 @@ struct fsl_mc_addr_translation_range {
>   phys_addr_t start_phys_addr;
>  };
>  
> +#define FSL_MC_FAPR  0x28
> +#define MC_FAPR_PL   BIT(18)
> +#define MC_FAPR_BMT  BIT(17)
> +
>  /**
>   * fsl_mc_bus_match - device to driver matching callback
>   * @dev: the fsl-mc device to match against
> @@ -124,7 +131,10 @@ static int fsl_mc_dma_configure(struct device *dev)
>   while (dev_is_fsl_mc(dma_dev))
>   dma_dev = dma_dev->parent;
>  
> - return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id);
> + if (dev_of_node(dma_dev))
> + return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id);
> +
> + return acpi_dma_configure_id(dev, DEV_DMA_COHERENT, &input_id);
>  }
>  
>  static ssize_t modalias_show(struct device *dev, struct device_attribute 
> *attr,
> @@ -865,8 +875,11 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
>   struct fsl_mc_io *mc_io = NULL;
>   int container_id;
>   phys_addr_t mc_portal_phys_addr;
> - u32 mc_portal_size;
> - struct resource res;
> + u32 mc_portal_size, mc_stream_id;
> + struct resource *plat_res;
> +
> + if (!iommu_present(&fsl_mc_bus_type))
> + return -EPROBE_DEFER;
>  
>   mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
>   if (!mc)
> @@ -874,19 +887,33 @@ static int fsl_mc_bus_probe(struct platform_device 
> *pdev)
>  
>   platform_set_drvdata(pdev, mc);
>  
> + plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + mc->fsl_mc_regs = devm_ioremap_resource(&pdev->dev, plat_res);
> + if (IS_ERR(mc->fsl_mc_regs))
> + return PTR_ERR(mc->fsl_mc_regs);
> +
> + if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) {
> + mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR);
> + /*
> +  * HW ORs the PL and BMT bit, places the result in bit 15 of
> +  * the StreamID and ORs in the ICID. Calculate it accordingly.
> +  */
> + mc_stream_id = (mc_stream_id & 0x) |
> + ((mc_stream_id & (MC_FAPR_PL | MC_FAPR_BMT)) ?
> + 0x4000 : 0);
> + error = acpi_dma_configure_id(&pdev->dev, DEV_DMA_COHERENT,
> +   &mc_stream_id);
> + if (error)
> + dev_warn(&pdev->dev, "failed to configure dma: %d.\n",
> +  error);
> + }
> +
>   /*
>* Get physical address of MC portal for the root DPRC:
>*/
> - error = of_address_to_resource(pdev->dev.of_node, 0, &res);
> - if (error < 0) {
> - dev_err(&pdev->dev,
> - "of_address_to_resource() failed for %pOF\n",
> - pdev->dev.of_node);
> - return error;
> - }
> -
> - mc_portal_phys_addr = res.start;
> - mc_portal_size = resource_size(&res);
> + plat_res = platform_get_resource(pdev, IORESOURCE_ME

Re: [PATCH 09/12] dt-bindings: arm: fsl: Add msi-map device-tree binding for fsl-mc bus

2020-05-22 Thread Laurentiu Tudor
On 5/22/2020 5:02 PM, Rob Herring wrote:
> On Fri, May 22, 2020 at 3:42 AM Robin Murphy  wrote:
>>
>> On 2020-05-22 00:10, Rob Herring wrote:
>>> On Thu, May 21, 2020 at 7:00 AM Lorenzo Pieralisi
>>>  wrote:
>>>>
>>>> From: Laurentiu Tudor 
>>>>
>>>> The existing bindings cannot be used to specify the relationship
>>>> between fsl-mc devices and GIC ITSes.
>>>>
>>>> Add a generic binding for mapping fsl-mc devices to GIC ITSes, using
>>>> msi-map property.
>>>>
>>>> Signed-off-by: Laurentiu Tudor 
>>>> Cc: Rob Herring 
>>>> ---
>>>>   .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 30 +--
>>>>   1 file changed, 27 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt 
>>>> b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> index 9134e9bcca56..b0813b2d0493 100644
>>>> --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> @@ -18,9 +18,9 @@ same hardware "isolation context" and a 10-bit value 
>>>> called an ICID
>>>>   the requester.
>>>>
>>>>   The generic 'iommus' property is insufficient to describe the 
>>>> relationship
>>>> -between ICIDs and IOMMUs, so an iommu-map property is used to define
>>>> -the set of possible ICIDs under a root DPRC and how they map to
>>>> -an IOMMU.
>>>> +between ICIDs and IOMMUs, so the iommu-map and msi-map properties are used
>>>> +to define the set of possible ICIDs under a root DPRC and how they map to
>>>> +an IOMMU and a GIC ITS respectively.
>>>>
>>>>   For generic IOMMU bindings, see
>>>>   Documentation/devicetree/bindings/iommu/iommu.txt.
>>>> @@ -28,6 +28,9 @@ Documentation/devicetree/bindings/iommu/iommu.txt.
>>>>   For arm-smmu binding, see:
>>>>   Documentation/devicetree/bindings/iommu/arm,smmu.yaml.
>>>>
>>>> +For GICv3 and GIC ITS bindings, see:
>>>> +Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml.
>>>> +
>>>>   Required properties:
>>>>
>>>>   - compatible
>>>> @@ -119,6 +122,15 @@ Optional properties:
>>>> associated with the listed IOMMU, with the iommu-specifier
>>>> (i - icid-base + iommu-base).
>>>>
>>>> +- msi-map: Maps an ICID to a GIC ITS and associated iommu-specifier
>>>> +  data.
>>>> +
>>>> +  The property is an arbitrary number of tuples of
>>>> +  (icid-base,iommu,iommu-base,length).
>>>
>>> I'm confused because the example has GIC ITS phandle, not an IOMMU.
>>>
>>> What is an iommu-base?
>>
>> Right, I was already halfway through writing a reply to say that all the
>> copy-pasted "iommu" references here should be using the terminology from
>> the pci-msi.txt binding instead.
>>
>>>> +
>>>> +  Any ICID in the interval [icid-base, icid-base + length) is
>>>> +  associated with the listed GIC ITS, with the iommu-specifier
>>>> +  (i - icid-base + iommu-base).
>>>>   Example:
>>>>
>>>>   smmu: iommu@500 {
>>>> @@ -128,6 +140,16 @@ Example:
>>>>  ...
>>>>   };
>>>>
>>>> +   gic: interrupt-controller@600 {
>>>> +   compatible = "arm,gic-v3";
>>>> +   ...
>>>> +   its: gic-its@602 {
>>>> +   compatible = "arm,gic-v3-its";
>>>> +   msi-controller;
>>>> +   ...
>>>> +   };
>>>> +   };
>>>> +
>>>>   fsl_mc: fsl-mc@80c00 {
>>>>   compatible = "fsl,qoriq-mc";
>>>>   reg = <0x0008 0x0c00 0 0x40>,/* MC portal 
>>>> base */
>>>> @@ -135,6 +157,8 @@ Example:
>>>>   msi-parent = <&its>;
>>
>> Side note: is it right to keep msi-parent here? It rather implies that
>> the MC itself has a 'native' Device ID rather than an ICID, which I
>> believe is not strictly true. Plus it

Re: [RFC 0/2] iommu: arm-smmu: Add support for early direct mappings

2020-05-27 Thread Laurentiu Tudor


On 5/26/2020 11:34 PM, John Stultz wrote:
> On Thu, May 14, 2020 at 12:34 PM  wrote:
>>
>> On Thu 27 Feb 18:57 PST 2020, Bjorn Andersson wrote:
>>
>> Rob, Will, we're reaching the point where upstream has enough
>> functionality that this is becoming a critical issue for us.
>>
>> E.g. Lenovo Yoga C630 is lacking this and a single dts patch to boot
>> mainline with display, GPU, WiFi and audio working and the story is
>> similar on several devboards.
>>
>> As previously described, the only thing I want is the stream mapping
>> related to the display controller in place, either with the CB with
>> translation disabled or possibly with a way to specify the framebuffer
>> region (although this turns out to mess things up in the display
>> driver...)
>>
>> I did pick this up again recently and concluded that by omitting the
>> streams for the USB controllers causes an instability issue seen on one
>> of the controller to disappear. So I would prefer if we somehow could
>> have a mechanism to only pick the display streams and the context
>> allocation for this.
>>
>>
>> Can you please share some pointers/insights/wishes for how we can
>> conclude on this subject?
> 
> Ping? I just wanted to follow up on this discussion as this small
> series is crucial for booting mainline on the Dragonboard 845c
> devboard. It would be really valuable to be able to get some solution
> upstream so we can test mainline w/o adding additional patches.

+1

There are also some NXP chips that depend on this. Also, I've submitted
a v2 [1] a while back that tries to address the feedback on the initial
implementation.

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=164853

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


[RFC PATCH 3/3] dpaa2_eth: use dma_addr_to_phys_addr() new dma api

2019-10-22 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Convert this driver to usage of the newly introduced
dma_addr_to_phys_addr() DMA API. This will get rid of the unsupported
direct usage of iommu_iova_to_phys() API.

Signed-off-by: Laurentiu Tudor 
---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 21 +++
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 2 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 19379bae0144..7332b91ca3a2 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -29,14 +29,9 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
 
-static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
-   dma_addr_t iova_addr)
+static void *dpaa2_iova_to_virt(struct device *dev, dma_addr_t dma_handle)
 {
-   phys_addr_t phys_addr;
-
-   phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
-
-   return phys_to_virt(phys_addr);
+   return phys_to_virt(dma_addr_to_phys_addr(dev, dma_handle));
 }
 
 static void validate_rx_csum(struct dpaa2_eth_priv *priv,
@@ -85,7 +80,7 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
sgt = vaddr + dpaa2_fd_get_offset(fd);
for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
addr = dpaa2_sg_get_addr(&sgt[i]);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
+   sg_vaddr = dpaa2_iova_to_virt(dev, addr);
dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
   DMA_BIDIRECTIONAL);
 
@@ -143,7 +138,7 @@ static struct sk_buff *build_frag_skb(struct dpaa2_eth_priv 
*priv,
 
/* Get the address and length from the S/G entry */
sg_addr = dpaa2_sg_get_addr(sge);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr);
+   sg_vaddr = dpaa2_iova_to_virt(dev, sg_addr);
dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE,
   DMA_BIDIRECTIONAL);
 
@@ -210,7 +205,7 @@ static void free_bufs(struct dpaa2_eth_priv *priv, u64 
*buf_array, int count)
int i;
 
for (i = 0; i < count; i++) {
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]);
+   vaddr = dpaa2_iova_to_virt(dev, buf_array[i]);
dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE,
   DMA_BIDIRECTIONAL);
free_pages((unsigned long)vaddr, 0);
@@ -369,7 +364,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
/* Tracing point */
trace_dpaa2_rx_fd(priv->net_dev, fd);
 
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
+   vaddr = dpaa2_iova_to_virt(dev, addr);
dma_sync_single_for_cpu(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
DMA_BIDIRECTIONAL);
 
@@ -682,7 +677,7 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
u32 fd_len = dpaa2_fd_get_len(fd);
 
fd_addr = dpaa2_fd_get_addr(fd);
-   buffer_start = dpaa2_iova_to_virt(priv->iommu_domain, fd_addr);
+   buffer_start = dpaa2_iova_to_virt(dev, fd_addr);
swa = (struct dpaa2_eth_swa *)buffer_start;
 
if (fd_format == dpaa2_fd_single) {
@@ -3448,8 +3443,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv = netdev_priv(net_dev);
priv->net_dev = net_dev;
 
-   priv->iommu_domain = iommu_get_domain_for_dev(dev);
-
/* Obtain a MC portal */
err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
 &priv->mc_io);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
index 8a0e65b3267f..4e5183617ebd 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -374,7 +374,6 @@ struct dpaa2_eth_priv {
 
struct fsl_mc_device *dpbp_dev;
u16 bpid;
-   struct iommu_domain *iommu_domain;
 
bool tx_tstamp; /* Tx timestamping enabled */
bool rx_tstamp; /* Rx timestamping enabled */
-- 
2.17.1

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


[RFC PATCH 0/3] dma-mapping: introduce a new dma api

2019-10-22 Thread Laurentiu Tudor
From: Laurentiu Tudor 

This series introduces a new dma api called dma_addr_to_phys_addr()
that converts a dma address to the corresponding physical address.
It consists in a new dma map op and the wrapper api, both added
in the first patch. The second patch adds an implementation in the
iommu dma glue code and wires it up. The third patch updates a driver
to use the new api.

Note: Originally i wanted to use the simpler api name dma_to_phys()
but it's already used in the dma direct apis. It would be great if
there would be a solution (unifying them?) to use this nicer naming.

Context: https://lkml.org/lkml/2019/5/31/684

Laurentiu Tudor (3):
  dma-mapping: introduce a new dma api dma_addr_to_phys_addr()
  iommu/dma: wire-up new dma op dma_addr_to_phys_addr()
  dpaa2_eth: use dma_addr_to_phys_addr() new dma api

 drivers/iommu/dma-iommu.c | 12 +++
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 21 +++
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 include/linux/dma-mapping.h   | 21 +++
 4 files changed, 40 insertions(+), 15 deletions(-)

-- 
2.17.1

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


[RFC PATCH 2/3] iommu/dma: wire-up new dma op dma_addr_to_phys_addr()

2019-10-22 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Add an implementation of the newly introduced dma map op in the
generic DMA IOMMU generic glue layer and wire it up.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/dma-iommu.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index f321279baf9e..0d2856793ecd 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1091,6 +1091,17 @@ static unsigned long iommu_dma_get_merge_boundary(struct 
device *dev)
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
 }
 
+static phys_addr_t iommu_dma_dma_addr_to_phys_addr(struct device *dev,
+  dma_addr_t dma_handle)
+{
+   struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+   if (domain)
+   return iommu_iova_to_phys(domain, dma_handle);
+
+   return 0;
+}
+
 static const struct dma_map_ops iommu_dma_ops = {
.alloc  = iommu_dma_alloc,
.free   = iommu_dma_free,
@@ -1107,6 +1118,7 @@ static const struct dma_map_ops iommu_dma_ops = {
.map_resource   = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource,
.get_merge_boundary = iommu_dma_get_merge_boundary,
+   .dma_addr_to_phys_addr  = iommu_dma_dma_addr_to_phys_addr,
 };
 
 /*
-- 
2.17.1

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


[RFC PATCH 1/3] dma-mapping: introduce a new dma api dma_addr_to_phys_addr()

2019-10-22 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Introduce a new dma map op called dma_addr_to_phys_addr() that converts
a dma address to the physical address backing it up and add wrapper for
it.

Signed-off-by: Laurentiu Tudor 
---
 include/linux/dma-mapping.h | 21 +
 1 file changed, 21 insertions(+)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..5965d159c9a9 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -132,6 +132,8 @@ struct dma_map_ops {
u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev);
unsigned long (*get_merge_boundary)(struct device *dev);
+   phys_addr_t (*dma_addr_to_phys_addr)(struct device *dev,
+dma_addr_t dma_handle);
 };
 
 #define DMA_MAPPING_ERROR  (~(dma_addr_t)0)
@@ -442,6 +444,19 @@ static inline int dma_mapping_error(struct device *dev, 
dma_addr_t dma_addr)
return 0;
 }
 
+static inline phys_addr_t dma_addr_to_phys_addr(struct device *dev,
+   dma_addr_t dma_handle)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+
+   if (dma_is_direct(ops))
+   return (phys_addr_t)dma_handle;
+   else if (ops->dma_addr_to_phys_addr)
+   return ops->dma_addr_to_phys_addr(dev, dma_handle);
+
+   return 0;
+}
+
 void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t flag, unsigned long attrs);
 void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
@@ -578,6 +593,12 @@ static inline unsigned long dma_get_merge_boundary(struct 
device *dev)
 {
return 0;
 }
+
+static inline phys_addr_t dma_addr_to_phys_addr(struct device *dev,
+   dma_addr_t dma_handle)
+{
+   return 0;
+}
 #endif /* CONFIG_HAS_DMA */
 
 static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
-- 
2.17.1

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


Re: [RFC PATCH 1/3] dma-mapping: introduce a new dma api dma_addr_to_phys_addr()

2019-10-22 Thread Laurentiu Tudor

On 22.10.2019 16:25, Robin Murphy wrote:
> On 22/10/2019 13:55, Laurentiu Tudor wrote:
>> From: Laurentiu Tudor 
>>
>> Introduce a new dma map op called dma_addr_to_phys_addr() that converts
>> a dma address to the physical address backing it up and add wrapper for
>> it.
> 
> I'd really love it if there was a name which could encapsulate that this 
> is *only* for extreme special cases of constrained descriptors/pagetable 
> entries/etc. where there's simply no practical way to keep track of a 
> CPU address alongside the DMA address, and the only option is this 
> potentially-arbitrarily-complex operation (I mean, on some systems it 
> may end up taking locks and poking hardware).
> 
> Either way it's tricky - much as I don't like adding an interface which 
> is ripe for drivers to misuse, I also really don't want hacks like 
> bdf95923086f shoved into other APIs to compensate, so on balance I'd 
> probably consider this proposal ever so slightly the lesser evil.
> 
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>   include/linux/dma-mapping.h | 21 +
>>   1 file changed, 21 insertions(+)
>>
>> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
>> index 4a1c4fca475a..5965d159c9a9 100644
>> --- a/include/linux/dma-mapping.h
>> +++ b/include/linux/dma-mapping.h
>> @@ -132,6 +132,8 @@ struct dma_map_ops {
>>   u64 (*get_required_mask)(struct device *dev);
>>   size_t (*max_mapping_size)(struct device *dev);
>>   unsigned long (*get_merge_boundary)(struct device *dev);
>> +    phys_addr_t (*dma_addr_to_phys_addr)(struct device *dev,
>> + dma_addr_t dma_handle);
> 
> I'd be inclined to name the internal callback something a bit snappier 
> like .get_phys_addr.

Alright. Want me to also rename the wrapper to something like 
dma_get_phys_addr()? Sounds a bit nicer to me.

>>   };
>>   #define DMA_MAPPING_ERROR    (~(dma_addr_t)0)
>> @@ -442,6 +444,19 @@ static inline int dma_mapping_error(struct device 
>> *dev, dma_addr_t dma_addr)
>>   return 0;
>>   }
>> +static inline phys_addr_t dma_addr_to_phys_addr(struct device *dev,
>> +    dma_addr_t dma_handle)
>> +{
>> +    const struct dma_map_ops *ops = get_dma_ops(dev);
>> +
>> +    if (dma_is_direct(ops))
>> +    return (phys_addr_t)dma_handle;
> 
> Well that's not right, is it - remember why you had that namespace 
> collision? ;)
> 

Ugh, correct. Don't know what I was thinking. Will rework the check.

---
Thanks & Best Regards, Laurentiu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [RFC PATCH 1/3] dma-mapping: introduce a new dma api dma_addr_to_phys_addr()

2019-10-23 Thread Laurentiu Tudor
Hi Robin,

On 22.10.2019 16:25, Robin Murphy wrote:
> On 22/10/2019 13:55, Laurentiu Tudor wrote:
>> From: Laurentiu Tudor 
>>
>> Introduce a new dma map op called dma_addr_to_phys_addr() that converts
>> a dma address to the physical address backing it up and add wrapper for
>> it.
> 
> I'd really love it if there was a name which could encapsulate that this 
> is *only* for extreme special cases of constrained descriptors/pagetable 
> entries/etc. where there's simply no practical way to keep track of a 
> CPU address alongside the DMA address, and the only option is this 
> potentially-arbitrarily-complex operation (I mean, on some systems it 
> may end up taking locks and poking hardware).
> 
> Either way it's tricky - much as I don't like adding an interface which 
> is ripe for drivers to misuse, I also really don't want hacks like 
> bdf95923086f shoved into other APIs to compensate, so on balance I'd 
> probably consider this proposal ever so slightly the lesser evil.

We had an internal discussion over these points you are raising and 
Madalin (cc-ed) came up with another idea: instead of adding this prone 
to misuse api how about experimenting with a new dma unmap and dma sync 
variants that would return the physical address by calling the newly 
introduced dma map op. Something along these lines:
  * phys_addr_t dma_unmap_page_ret_phys(...)
  * phys_addr_t dma_unmap_single_ret_phys(...)
  * phys_addr_t dma_sync_single_for_cpu_ret_phys(...)
I'm thinking that this proposal should reduce the risks opened by the 
initial variant.
Please let me know what you think.

---
Thanks & Best Regards, Laurentiu

Re: [RFC PATCH 1/3] dma-mapping: introduce a new dma api dma_addr_to_phys_addr()

2019-10-24 Thread Laurentiu Tudor



On 24.10.2019 05:01, h...@lst.de wrote:
> On Wed, Oct 23, 2019 at 11:53:41AM +0000, Laurentiu Tudor wrote:
>> We had an internal discussion over these points you are raising and
>> Madalin (cc-ed) came up with another idea: instead of adding this prone
>> to misuse api how about experimenting with a new dma unmap and dma sync
>> variants that would return the physical address by calling the newly
>> introduced dma map op. Something along these lines:
>>* phys_addr_t dma_unmap_page_ret_phys(...)
>>* phys_addr_t dma_unmap_single_ret_phys(...)
>>* phys_addr_t dma_sync_single_for_cpu_ret_phys(...)
>> I'm thinking that this proposal should reduce the risks opened by the
>> initial variant.
>> Please let me know what you think.
> 
> I'm not sure what the ret is supposed to mean, but I generally like
> that idea better.  

It was supposed to be short for "return" but given that I'm not good at 
naming stuff I'll just drop it.

> We also need to make sure there is an easy way
> to figure out if these APIs are available, as they generally aren't
> for any non-IOMMU API IOMMU drivers.

I was really hoping to manage making them as generic as possible but 
anyway, I'll start working on a PoC and see how it turns out. This will 
probably happen sometime next next week as the following week I'll be 
traveling to a conference.

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


[PATCH 0/3] dma-mapping: introduce new dma unmap and sync variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

This series introduces a few new dma unmap and sync api variants that,
on top of what the originals do, return the physical address
corresponding to the input dma address. In order to do that a new dma
map op is added, .get_phys_addr that takes the input dma address and
returns the physical address backing it up.
The second patch adds an implementation for this new dma map op in the
generic iommu dma glue code and wires it in.
The third patch updates the dpaa2-eth driver to use the new apis.

Context: https://lkml.org/lkml/2019/5/31/684

Changes since RFC
 * completely changed the approach: added unmap and sync variants that
   return the phys addr instead of adding a new dma to phys conversion
   function

Laurentiu Tudor (3):
  dma-mapping: introduce new dma unmap and sync api variants
  iommu/dma: wire-up new dma map op .get_phys_addr
  dpaa2_eth: use new unmap and sync dma api variants

 drivers/iommu/dma-iommu.c | 12 
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 43 ++-
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 include/linux/dma-mapping.h   | 55 +++
 4 files changed, 85 insertions(+), 26 deletions(-)

-- 
2.17.1

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


[PATCH 3/3] dpaa2_eth: use new unmap and sync dma api variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Convert this driver to usage of the newly introduced dma unmap and
sync DMA APIs. This will get rid of the unsupported direct usage of
iommu_iova_to_phys() API.

Signed-off-by: Laurentiu Tudor 
---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 43 ---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 2 files changed, 18 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 19379bae0144..bd43bfcb3126 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -29,16 +29,6 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
 
-static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
-   dma_addr_t iova_addr)
-{
-   phys_addr_t phys_addr;
-
-   phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
-
-   return phys_to_virt(phys_addr);
-}
-
 static void validate_rx_csum(struct dpaa2_eth_priv *priv,
 u32 fd_status,
 struct sk_buff *skb)
@@ -85,9 +75,10 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
sgt = vaddr + dpaa2_fd_get_offset(fd);
for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
addr = dpaa2_sg_get_addr(&sgt[i]);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = phys_to_virt
+   (dma_unmap_page_phys(dev, addr,
+   DPAA2_ETH_RX_BUF_SIZE,
+   DMA_BIDIRECTIONAL));
 
free_pages((unsigned long)sg_vaddr, 0);
if (dpaa2_sg_is_final(&sgt[i]))
@@ -143,9 +134,10 @@ static struct sk_buff *build_frag_skb(struct 
dpaa2_eth_priv *priv,
 
/* Get the address and length from the S/G entry */
sg_addr = dpaa2_sg_get_addr(sge);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr);
-   dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = phys_to_virt
+   (dma_unmap_page_phys(dev, sg_addr,
+   DPAA2_ETH_RX_BUF_SIZE,
+   DMA_BIDIRECTIONAL));
 
sg_length = dpaa2_sg_get_len(sge);
 
@@ -210,9 +202,9 @@ static void free_bufs(struct dpaa2_eth_priv *priv, u64 
*buf_array, int count)
int i;
 
for (i = 0; i < count; i++) {
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]);
-   dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   vaddr = phys_to_virt(dma_unmap_page_phys(dev, buf_array[i],
+DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL));
free_pages((unsigned long)vaddr, 0);
}
 }
@@ -369,9 +361,9 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
/* Tracing point */
trace_dpaa2_rx_fd(priv->net_dev, fd);
 
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_sync_single_for_cpu(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-   DMA_BIDIRECTIONAL);
+   vaddr = phys_to_virt(dma_sync_single_for_cpu_phys(dev, addr,
+ DPAA2_ETH_RX_BUF_SIZE,
+ DMA_BIDIRECTIONAL));
 
fas = dpaa2_get_fas(vaddr, false);
prefetch(fas);
@@ -682,7 +674,10 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
u32 fd_len = dpaa2_fd_get_len(fd);
 
fd_addr = dpaa2_fd_get_addr(fd);
-   buffer_start = dpaa2_iova_to_virt(priv->iommu_domain, fd_addr);
+   buffer_start = phys_to_virt
+   (dma_sync_single_for_cpu_phys(dev, fd_addr,
+ sizeof(*swa),
+ DMA_BIDIRECTIONAL));
swa = (struct dpaa2_eth_swa *)buffer_start;
 
if (fd_format == dpaa2_fd_single) {
@@ -3448,8 +3443,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv = netdev_priv(net_dev);
priv->net_dev = net_dev;
 
-   priv->iommu_domain = iommu_get_domain_for_dev(dev);
-
/* Obtain a MC portal */
err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORT

[PATCH 1/3] dma-mapping: introduce new dma unmap and sync api variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Introduce a few new dma unmap and sync variants that, on top of the
original variants, return the physical address corresponding to the
input dma address.
In order to implement this a new dma map op is added and used:
phys_addr_t get_phys_addr(dev, dma_handle);
It does the actual conversion of an input dma address to the output
physical address.

Signed-off-by: Laurentiu Tudor 
---
 include/linux/dma-mapping.h | 55 +
 1 file changed, 55 insertions(+)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..d2bccb814eac 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -132,6 +132,7 @@ struct dma_map_ops {
u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev);
unsigned long (*get_merge_boundary)(struct device *dev);
+   phys_addr_t (*get_phys_addr)(struct device *dev, dma_addr_t dma_handle);
 };
 
 #define DMA_MAPPING_ERROR  (~(dma_addr_t)0)
@@ -304,6 +305,21 @@ static inline void dma_unmap_page_attrs(struct device 
*dev, dma_addr_t addr,
debug_dma_unmap_page(dev, addr, size, dir);
 }
 
+static inline phys_addr_t
+dma_unmap_page_phys_attrs(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   phys_addr_t phys = 0;
+
+   if (ops && ops->get_phys_addr)
+   phys = ops->get_phys_addr(dev, addr);
+
+   dma_unmap_page_attrs(dev, addr, size, dir, attrs);
+
+   return phys;
+}
+
 /*
  * dma_maps_sg_attrs returns 0 on error and > 0 on success.
  * It should never return a value < 0.
@@ -390,6 +406,21 @@ static inline void dma_sync_single_for_cpu(struct device 
*dev, dma_addr_t addr,
debug_dma_sync_single_for_cpu(dev, addr, size, dir);
 }
 
+static inline phys_addr_t
+dma_sync_single_for_cpu_phys(struct device *dev, dma_addr_t addr, size_t size,
+enum dma_data_direction dir)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   phys_addr_t phys = 0;
+
+   if (ops && ops->get_phys_addr)
+   phys = ops->get_phys_addr(dev, addr);
+
+   dma_sync_single_for_cpu(dev, addr, size, dir);
+
+   return phys;
+}
+
 static inline void dma_sync_single_for_device(struct device *dev,
  dma_addr_t addr, size_t size,
  enum dma_data_direction dir)
@@ -500,6 +531,12 @@ static inline void dma_sync_single_for_cpu(struct device 
*dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
 {
 }
+
+static inline phys_addr_t
+dma_sync_single_for_cpu_phys(struct device *dev, dma_addr_t addr, size_t size,
+enum dma_data_direction dir)
+{
+}
 static inline void dma_sync_single_for_device(struct device *dev,
dma_addr_t addr, size_t size, enum dma_data_direction dir)
 {
@@ -594,6 +631,21 @@ static inline void dma_unmap_single_attrs(struct device 
*dev, dma_addr_t addr,
return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
 }
 
+static inline phys_addr_t
+dma_unmap_single_phys_attrs(struct device *dev, dma_addr_t addr, size_t size,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   phys_addr_t phys = 0;
+
+   if (ops && ops->get_phys_addr)
+   phys = ops->get_phys_addr(dev, addr);
+
+   dma_unmap_single_attrs(dev, addr, size, dir, attrs);
+
+   return phys;
+}
+
 static inline void dma_sync_single_range_for_cpu(struct device *dev,
dma_addr_t addr, unsigned long offset, size_t size,
enum dma_data_direction dir)
@@ -610,10 +662,13 @@ static inline void 
dma_sync_single_range_for_device(struct device *dev,
 
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
+#define dma_unmap_single_phys(d, a, s, r) \
+   dma_unmap_single_phys_attrs(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
 #define dma_map_page(d, p, o, s, r) dma_map_page_attrs(d, p, o, s, r, 0)
 #define dma_unmap_page(d, a, s, r) dma_unmap_page_attrs(d, a, s, r, 0)
+#define dma_unmap_page_phys(d, a, s, r) dma_unmap_page_phys_attrs(d, a, s, r, 
0)
 #define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
 #define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
 
-- 
2.17.1

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


[PATCH 2/3] iommu/dma: wire-up new dma map op .get_phys_addr

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Add an implementation of the newly introduced dma map op in the
generic DMA IOMMU generic glue layer and wire it up.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/dma-iommu.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index f321279baf9e..e4e2bde586e0 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1091,6 +1091,17 @@ static unsigned long iommu_dma_get_merge_boundary(struct 
device *dev)
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
 }
 
+static phys_addr_t iommu_dma_get_phys_addr(struct device *dev,
+  dma_addr_t dma_handle)
+{
+   struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+   if (domain)
+   return iommu_iova_to_phys(domain, dma_handle);
+
+   return 0;
+}
+
 static const struct dma_map_ops iommu_dma_ops = {
.alloc  = iommu_dma_alloc,
.free   = iommu_dma_free,
@@ -1107,6 +1118,7 @@ static const struct dma_map_ops iommu_dma_ops = {
.map_resource   = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource,
.get_merge_boundary = iommu_dma_get_merge_boundary,
+   .get_phys_addr  = iommu_dma_get_phys_addr,
 };
 
 /*
-- 
2.17.1

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


Re: [RFC PATCH 1/3] dma-mapping: introduce a new dma api dma_addr_to_phys_addr()

2019-10-24 Thread Laurentiu Tudor
On 24.10.2019 14:04, Robin Murphy wrote:
> On 2019-10-24 8:49 am, Laurentiu Tudor wrote:
>>
>>
>> On 24.10.2019 05:01, h...@lst.de wrote:
>>> On Wed, Oct 23, 2019 at 11:53:41AM +, Laurentiu Tudor wrote:
>>>> We had an internal discussion over these points you are raising and
>>>> Madalin (cc-ed) came up with another idea: instead of adding this prone
>>>> to misuse api how about experimenting with a new dma unmap and dma sync
>>>> variants that would return the physical address by calling the newly
>>>> introduced dma map op. Something along these lines:
>>>>     * phys_addr_t dma_unmap_page_ret_phys(...)
>>>>     * phys_addr_t dma_unmap_single_ret_phys(...)
>>>>     * phys_addr_t dma_sync_single_for_cpu_ret_phys(...)
>>>> I'm thinking that this proposal should reduce the risks opened by the
>>>> initial variant.
>>>> Please let me know what you think.
>>>
>>> I'm not sure what the ret is supposed to mean, but I generally like
>>> that idea better.
>>
>> It was supposed to be short for "return" but given that I'm not good at
>> naming stuff I'll just drop it.
> 
> Hmm, how about something like "dma_unmap_*_desc" for the context of the 
> mapped DMA address also being used as a descriptor token?

Alright.

>>> We also need to make sure there is an easy way
>>> to figure out if these APIs are available, as they generally aren't
>>> for any non-IOMMU API IOMMU drivers.
>>
>> I was really hoping to manage making them as generic as possible but
>> anyway, I'll start working on a PoC and see how it turns out. This will
>> probably happen sometime next next week as the following week I'll be
>> traveling to a conference.
> 
> AFAICS, even a full implementation of these APIs would have to be 
> capable of returning an indication that there is no valid physical 
> address - e.g. if unmap is called with a bogus DMA address that was 
> never mapped. At that point there'sseemingly no problem just 
> implementing the trivial case on top of any existing unmap/sync 
> callbacks for everyone. I'd imagine that drivers which want this aren't 
> likely to run on the older architectures where the weird IOMMUs live, so 
> they could probably just always treat failure as unexpected and fatal 
> either way.
> 
> In fact, I'm now wondering whether it's likely to be common that users 
> want the physical address specifically, or whether it would make sense 
> to return the original VA/page, both for symmetry with the corresponding 
> map calls and for the ease of being able to return NULL when necessary.

That's sounds wonderful as it should make the code leaner in the drivers.

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

[PATCH v2 0/3] dma-mapping: introduce new dma unmap and sync variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

This series introduces a few new dma unmap and sync api variants that,
on top of what the originals do, return the virtual address
corresponding to the input dma address. In order to do that a new dma
map op is added, .get_virt_addr that takes the input dma address and
returns the virtual address backing it up.
The second patch adds an implementation for this new dma map op in the
generic iommu dma glue code and wires it in.
The third patch updates the dpaa2-eth driver to use the new apis.

Context: https://lkml.org/lkml/2019/5/31/684

Changes in v2
 * use "dma_unmap_*_desc" names (Robin)
 * return va/page instead of phys addr (Robin)

Changes since RFC
 * completely changed the approach: added unmap and sync variants that
   return the phys addr instead of adding a new dma to phys conversion
   function

Laurentiu Tudor (3):
  dma-mapping: introduce new dma unmap and sync api variants
  iommu/dma: wire-up new dma map op .get_virt_addr
  dpaa2_eth: use new unmap and sync dma api variants

 drivers/iommu/dma-iommu.c | 16 ++
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 40 +-
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 include/linux/dma-mapping.h   | 55 +++
 4 files changed, 86 insertions(+), 26 deletions(-)

-- 
2.17.1

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


[PATCH v2 2/3] iommu/dma: wire-up new dma map op .get_virt_addr

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Add an implementation of the newly introduced dma map op in the
generic DMA IOMMU generic glue layer and wire it up.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/dma-iommu.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index f321279baf9e..15e76232d697 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1091,6 +1091,21 @@ static unsigned long iommu_dma_get_merge_boundary(struct 
device *dev)
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
 }
 
+static void *iommu_dma_get_virt_addr(struct device *dev, dma_addr_t dma_handle)
+{
+   struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+
+   if (domain) {
+   phys_addr_t phys;
+
+   phys = iommu_iova_to_phys(domain, dma_handle);
+   if (phys)
+   return phys_to_virt(phys);
+   }
+
+   return NULL;
+}
+
 static const struct dma_map_ops iommu_dma_ops = {
.alloc  = iommu_dma_alloc,
.free   = iommu_dma_free,
@@ -1107,6 +1122,7 @@ static const struct dma_map_ops iommu_dma_ops = {
.map_resource   = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource,
.get_merge_boundary = iommu_dma_get_merge_boundary,
+   .get_virt_addr  = iommu_dma_get_virt_addr,
 };
 
 /*
-- 
2.17.1

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


[PATCH v2 1/3] dma-mapping: introduce new dma unmap and sync api variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Introduce a few new dma unmap and sync variants that, on top of the
original variants, return the virtual address corresponding to the
input dma address.
In order to implement this a new dma map op is added and used:
void *get_virt_addr(dev, dma_handle);
It does the actual conversion of an input dma address to the output
virtual address.

Signed-off-by: Laurentiu Tudor 
---
 include/linux/dma-mapping.h | 55 +
 1 file changed, 55 insertions(+)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..ae7bb8a84b9d 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -132,6 +132,7 @@ struct dma_map_ops {
u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev);
unsigned long (*get_merge_boundary)(struct device *dev);
+   void *(*get_virt_addr)(struct device *dev, dma_addr_t dma_handle);
 };
 
 #define DMA_MAPPING_ERROR  (~(dma_addr_t)0)
@@ -304,6 +305,21 @@ static inline void dma_unmap_page_attrs(struct device 
*dev, dma_addr_t addr,
debug_dma_unmap_page(dev, addr, size, dir);
 }
 
+static inline struct page *
+dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   void *ptr = NULL;
+
+   if (ops && ops->get_virt_addr)
+   ptr = ops->get_virt_addr(dev, addr);
+
+   dma_unmap_page_attrs(dev, addr, size, dir, attrs);
+
+   return ptr ? virt_to_page(ptr) : NULL;
+}
+
 /*
  * dma_maps_sg_attrs returns 0 on error and > 0 on success.
  * It should never return a value < 0.
@@ -390,6 +406,21 @@ static inline void dma_sync_single_for_cpu(struct device 
*dev, dma_addr_t addr,
debug_dma_sync_single_for_cpu(dev, addr, size, dir);
 }
 
+static inline void *
+dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr, size_t size,
+enum dma_data_direction dir)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   void *ptr = NULL;
+
+   if (ops && ops->get_virt_addr)
+   ptr = ops->get_virt_addr(dev, addr);
+
+   dma_sync_single_for_cpu(dev, addr, size, dir);
+
+   return ptr;
+}
+
 static inline void dma_sync_single_for_device(struct device *dev,
  dma_addr_t addr, size_t size,
  enum dma_data_direction dir)
@@ -500,6 +531,12 @@ static inline void dma_sync_single_for_cpu(struct device 
*dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
 {
 }
+
+static inline void *
+dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr, size_t size,
+enum dma_data_direction dir)
+{
+}
 static inline void dma_sync_single_for_device(struct device *dev,
dma_addr_t addr, size_t size, enum dma_data_direction dir)
 {
@@ -594,6 +631,21 @@ static inline void dma_unmap_single_attrs(struct device 
*dev, dma_addr_t addr,
return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
 }
 
+static inline void *
+dma_unmap_single_attrs_desc(struct device *dev, dma_addr_t addr, size_t size,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+   void *ptr = NULL;
+
+   if (ops && ops->get_virt_addr)
+   ptr = ops->get_virt_addr(dev, addr);
+
+   dma_unmap_single_attrs(dev, addr, size, dir, attrs);
+
+   return ptr;
+}
+
 static inline void dma_sync_single_range_for_cpu(struct device *dev,
dma_addr_t addr, unsigned long offset, size_t size,
enum dma_data_direction dir)
@@ -610,10 +662,13 @@ static inline void 
dma_sync_single_range_for_device(struct device *dev,
 
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
+#define dma_unmap_single_desc(d, a, s, r) \
+   dma_unmap_single_attrs_desc(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
 #define dma_map_page(d, p, o, s, r) dma_map_page_attrs(d, p, o, s, r, 0)
 #define dma_unmap_page(d, a, s, r) dma_unmap_page_attrs(d, a, s, r, 0)
+#define dma_unmap_page_desc(d, a, s, r) dma_unmap_page_attrs_desc(d, a, s, r, 
0)
 #define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
 #define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
 
-- 
2.17.1

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


[PATCH v2 3/3] dpaa2_eth: use new unmap and sync dma api variants

2019-10-24 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Convert this driver to usage of the newly introduced dma unmap and
sync DMA APIs. This will get rid of the unsupported direct usage of
iommu_iova_to_phys() API.

Signed-off-by: Laurentiu Tudor 
---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 40 +++
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 2 files changed, 15 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 19379bae0144..8c3391e6e598 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -29,16 +29,6 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
 
-static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
-   dma_addr_t iova_addr)
-{
-   phys_addr_t phys_addr;
-
-   phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
-
-   return phys_to_virt(phys_addr);
-}
-
 static void validate_rx_csum(struct dpaa2_eth_priv *priv,
 u32 fd_status,
 struct sk_buff *skb)
@@ -85,9 +75,10 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
sgt = vaddr + dpaa2_fd_get_offset(fd);
for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
addr = dpaa2_sg_get_addr(&sgt[i]);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = page_to_virt
+   (dma_unmap_page_desc(dev, addr,
+   DPAA2_ETH_RX_BUF_SIZE,
+   DMA_BIDIRECTIONAL));
 
free_pages((unsigned long)sg_vaddr, 0);
if (dpaa2_sg_is_final(&sgt[i]))
@@ -143,9 +134,10 @@ static struct sk_buff *build_frag_skb(struct 
dpaa2_eth_priv *priv,
 
/* Get the address and length from the S/G entry */
sg_addr = dpaa2_sg_get_addr(sge);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr);
-   dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = page_to_virt
+   (dma_unmap_page_desc(dev, sg_addr,
+   DPAA2_ETH_RX_BUF_SIZE,
+   DMA_BIDIRECTIONAL));
 
sg_length = dpaa2_sg_get_len(sge);
 
@@ -210,9 +202,9 @@ static void free_bufs(struct dpaa2_eth_priv *priv, u64 
*buf_array, int count)
int i;
 
for (i = 0; i < count; i++) {
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]);
-   dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   vaddr = page_to_virt(dma_unmap_page_desc(dev, buf_array[i],
+DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL));
free_pages((unsigned long)vaddr, 0);
}
 }
@@ -369,9 +361,8 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
/* Tracing point */
trace_dpaa2_rx_fd(priv->net_dev, fd);
 
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_sync_single_for_cpu(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-   DMA_BIDIRECTIONAL);
+   vaddr = dma_sync_single_for_cpu_desc(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL);
 
fas = dpaa2_get_fas(vaddr, false);
prefetch(fas);
@@ -682,7 +673,8 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
u32 fd_len = dpaa2_fd_get_len(fd);
 
fd_addr = dpaa2_fd_get_addr(fd);
-   buffer_start = dpaa2_iova_to_virt(priv->iommu_domain, fd_addr);
+   buffer_start = dma_sync_single_for_cpu_desc(dev, fd_addr, sizeof(*swa),
+   DMA_BIDIRECTIONAL);
swa = (struct dpaa2_eth_swa *)buffer_start;
 
if (fd_format == dpaa2_fd_single) {
@@ -3448,8 +3440,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv = netdev_priv(net_dev);
priv->net_dev = net_dev;
 
-   priv->iommu_domain = iommu_get_domain_for_dev(dev);
-
/* Obtain a MC portal */
err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
 &priv->mc_io);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
i

Re: [PATCH v2 3/3] dpaa2_eth: use new unmap and sync dma api variants

2019-10-28 Thread Laurentiu Tudor
Hi Jonathan,

On 25.10.2019 19:12, Jonathan Lemon wrote:
> 
> 
> On 24 Oct 2019, at 5:41, Laurentiu Tudor wrote:
> 
>> From: Laurentiu Tudor 
>>
>> Convert this driver to usage of the newly introduced dma unmap and
>> sync DMA APIs. This will get rid of the unsupported direct usage of
>> iommu_iova_to_phys() API.
>>
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>  .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 40 +++
>>  .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
>>  2 files changed, 15 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c 
>> b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
>> index 19379bae0144..8c3391e6e598 100644
>> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
>> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
>> @@ -29,16 +29,6 @@ MODULE_LICENSE("Dual BSD/GPL");
>>  MODULE_AUTHOR("Freescale Semiconductor, Inc");
>>  MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
>>
>> -static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
>> -    dma_addr_t iova_addr)
>> -{
>> -    phys_addr_t phys_addr;
>> -
>> -    phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : 
>> iova_addr;
>> -
>> -    return phys_to_virt(phys_addr);
>> -}
>> -
>>  static void validate_rx_csum(struct dpaa2_eth_priv *priv,
>>   u32 fd_status,
>>   struct sk_buff *skb)
>> @@ -85,9 +75,10 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
>>  sgt = vaddr + dpaa2_fd_get_offset(fd);
>>  for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
>>  addr = dpaa2_sg_get_addr(&sgt[i]);
>> -    sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
>> -    dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
>> -   DMA_BIDIRECTIONAL);
>> +    sg_vaddr = page_to_virt
>> +    (dma_unmap_page_desc(dev, addr,
>> +    DPAA2_ETH_RX_BUF_SIZE,
>> +    DMA_BIDIRECTIONAL));
> 
> This is doing virt -> page -> virt.  Why not just have the new
> function return the VA corresponding to the addr, which would
> match the other functions?

I'd really like that as it would get rid of the page_to_virt() calls but 
it will break the symmetry with the dma_map_page() API. I'll let the 
maintainers decide.

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

RE: [PATCH v2 1/3] dma-mapping: introduce new dma unmap and sync api variants

2019-10-29 Thread Laurentiu Tudor



> -Original Message-
> From: h...@lst.de 
> Sent: Monday, October 28, 2019 2:38 PM
> 
> On Thu, Oct 24, 2019 at 12:41:41PM +0000, Laurentiu Tudor wrote:
> > From: Laurentiu Tudor 
> >
> > Introduce a few new dma unmap and sync variants that, on top of the
> > original variants, return the virtual address corresponding to the
> > input dma address.
> > In order to implement this a new dma map op is added and used:
> > void *get_virt_addr(dev, dma_handle);
> > It does the actual conversion of an input dma address to the output
> > virtual address.
> 
> We'll definitively need an implementation for dma-direct at least as
> well.  Also as said previously we need a dma_can_unmap_by_dma_addr()
> or similar helper that tells the driver beforehand if this works, so
> that the driver can either use a sub-optimal workaround or fail the
> probe if this functionality isn't implemented.

Alright. On top of that I need to make this work on booke ppc as we have one 
driver that runs both on arm and ppc and will use these APIs.

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


Re: [PATCH v2 3/3] dpaa2_eth: use new unmap and sync dma api variants

2019-11-06 Thread Laurentiu Tudor

On 28.10.2019 13:38, h...@lst.de wrote:
> On Mon, Oct 28, 2019 at 10:55:05AM +0000, Laurentiu Tudor wrote:
>>>> @@ -85,9 +75,10 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
>>>>   sgt = vaddr + dpaa2_fd_get_offset(fd);
>>>>   for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
>>>>   addr = dpaa2_sg_get_addr(&sgt[i]);
>>>> -    sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
>>>> -    dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
>>>> -   DMA_BIDIRECTIONAL);
>>>> +    sg_vaddr = page_to_virt
>>>> +    (dma_unmap_page_desc(dev, addr,
>>>> +    DPAA2_ETH_RX_BUF_SIZE,
>>>> +    DMA_BIDIRECTIONAL));
>>>
>>> This is doing virt -> page -> virt.  Why not just have the new
>>> function return the VA corresponding to the addr, which would
>>> match the other functions?
>>
>> I'd really like that as it would get rid of the page_to_virt() calls but
>> it will break the symmetry with the dma_map_page() API. I'll let the
>> maintainers decide.
> 
> It would be symmetric with dma_map_single, though.  Maybe we need
> both variants?

Patch 1/3 also adds an dma_unmap_single_desc(). Would it be legal to 
just use dma_unmap_single_desc() in the driver even if the driver does 
it's mappings with dma_map_page()?

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

Re: [PATCH v2 1/3] dma-mapping: introduce new dma unmap and sync api variants

2019-11-06 Thread Laurentiu Tudor

On 28.10.2019 15:42, Robin Murphy wrote:
> On 24/10/2019 13:41, Laurentiu Tudor wrote:
>> From: Laurentiu Tudor 
>>
>> Introduce a few new dma unmap and sync variants that, on top of the
>> original variants, return the virtual address corresponding to the
>> input dma address.
>> In order to implement this a new dma map op is added and used:
>>  void *get_virt_addr(dev, dma_handle);
>> It does the actual conversion of an input dma address to the output
>> virtual address.
> 
> At this point, I think it might be better to just change the prototype 
> of the .unmap_page/.sync_single_for_cpu callbacks themselves. 

I could give this a try. At a first sight, looks like it will be quite 
an intrusive change.

> In cases 
> where .get_virt_addr would be non-trivial, it's most likely duplicating 
> work that the relevant callback has to do anyway (i.e. where the virtual 
> and/or physical address is needed internally for a cache maintenance or 
> bounce buffer operation). It would also help avoid any possible 
> ambiguity about whether .get_virt_addr returns the VA corresponding 
> dma_handle (if one exists) rather than the VA of the buffer *mapped to* 
> dma_handle, which for a bounce-buffering implementation would be 
> different, and the one you actually need - a naive 
> phys_to_virt(dma_to_phys(dma_handle)) would lead you to the wrong place 


> (in fact it looks like DPAA2 would currently go wrong with 
> "swiotlb=force" and the SMMU disabled or in passthrough).

Yes, most likely.

> One question there is whether we'd want careful special-casing to avoid 
> introducing overhead where unmap/sync are currently complete no-ops, or 
> whether an extra phys_to_virt() or so in those paths would be tolerable.
> 
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>   include/linux/dma-mapping.h | 55 +
>>   1 file changed, 55 insertions(+)
>>
>> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
>> index 4a1c4fca475a..ae7bb8a84b9d 100644
>> --- a/include/linux/dma-mapping.h
>> +++ b/include/linux/dma-mapping.h
>> @@ -132,6 +132,7 @@ struct dma_map_ops {
>>   u64 (*get_required_mask)(struct device *dev);
>>   size_t (*max_mapping_size)(struct device *dev);
>>   unsigned long (*get_merge_boundary)(struct device *dev);
>> +    void *(*get_virt_addr)(struct device *dev, dma_addr_t dma_handle);
>>   };
>>   #define DMA_MAPPING_ERROR    (~(dma_addr_t)0)
>> @@ -304,6 +305,21 @@ static inline void dma_unmap_page_attrs(struct 
>> device *dev, dma_addr_t addr,
>>   debug_dma_unmap_page(dev, addr, size, dir);
>>   }
>> +static inline struct page *
>> +dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t addr, size_t 
>> size,
>> +  enum dma_data_direction dir, unsigned long attrs)
>> +{
>> +    const struct dma_map_ops *ops = get_dma_ops(dev);
>> +    void *ptr = NULL;
>> +
>> +    if (ops && ops->get_virt_addr)
>> +    ptr = ops->get_virt_addr(dev, addr);
> 
> Note that this doesn't work for dma-direct, but for the sake of arm64 at 
> least it almost certainly wants to.
> 

Will take care of it.

---
Best Regards, Laurentiu

> 
>> +    dma_unmap_page_attrs(dev, addr, size, dir, attrs);
>> +
>> +    return ptr ? virt_to_page(ptr) : NULL;
>> +}
>> +
>>   /*
>>    * dma_maps_sg_attrs returns 0 on error and > 0 on success.
>>    * It should never return a value < 0.
>> @@ -390,6 +406,21 @@ static inline void dma_sync_single_for_cpu(struct 
>> device *dev, dma_addr_t addr,
>>   debug_dma_sync_single_for_cpu(dev, addr, size, dir);
>>   }
>> +static inline void *
>> +dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr, 
>> size_t size,
>> + enum dma_data_direction dir)
>> +{
>> +    const struct dma_map_ops *ops = get_dma_ops(dev);
>> +    void *ptr = NULL;
>> +
>> +    if (ops && ops->get_virt_addr)
>> +    ptr = ops->get_virt_addr(dev, addr);
>> +
>> +    dma_sync_single_for_cpu(dev, addr, size, dir);
>> +
>> +    return ptr;
>> +}
>> +
>>   static inline void dma_sync_single_for_device(struct device *dev,
>>     dma_addr_t addr, size_t size,
>>     enum dma_data_direction dir)
>> @@ -500,6 +531,12 @@ static inline void dma_sync_single_for_cpu(struct 
>> device *dev, dma_addr_t addr,
>>   size_t size, enum dma_data_direction dir)
>>   {
>>   }
>> +
>> +static in

Re: [PATCH v2 1/3] dma-mapping: introduce new dma unmap and sync api variants

2019-11-07 Thread Laurentiu Tudor
Hi Robin,

On 28.10.2019 15:42, Robin Murphy wrote:
> On 24/10/2019 13:41, Laurentiu Tudor wrote:
>> From: Laurentiu Tudor 
>>
>> Introduce a few new dma unmap and sync variants that, on top of the
>> original variants, return the virtual address corresponding to the
>> input dma address.
>> In order to implement this a new dma map op is added and used:
>>  void *get_virt_addr(dev, dma_handle);
>> It does the actual conversion of an input dma address to the output
>> virtual address.
> 
> At this point, I think it might be better to just change the prototype 
> of the .unmap_page/.sync_single_for_cpu callbacks themselves. In cases 
> where .get_virt_addr would be non-trivial, it's most likely duplicating 
> work that the relevant callback has to do anyway (i.e. where the virtual 
> and/or physical address is needed internally for a cache maintenance or 
> bounce buffer operation). 

Looking in the generic dma-iommu, I didn't see any mean of freely 
getting the pa or va bqcking the iova so I can't think of a way of doing 
this without adding a call to iommu_iova_to_phys() somewhere in the 
unmap op implementation. Obviously, this would come with an overhead 
that will probably upset people.
At the moment I can't think at an option other than the initial one, 
that is adding the .get_virt_addr op. Please let me know your opinions 
on this.

---
Thanks & Best Regards, Laurentiu

> It would also help avoid any possible 
> ambiguity about whether .get_virt_addr returns the VA corresponding 
> dma_handle (if one exists) rather than the VA of the buffer *mapped to* 
> dma_handle, which for a bounce-buffering implementation would be 
> different, and the one you actually need - a naive 
> phys_to_virt(dma_to_phys(dma_handle)) would lead you to the wrong place 
> (in fact it looks like DPAA2 would currently go wrong with 
> "swiotlb=force" and the SMMU disabled or in passthrough).
> 
> One question there is whether we'd want careful special-casing to avoid 
> introducing overhead where unmap/sync are currently complete no-ops, or 
> whether an extra phys_to_virt() or so in those paths would be tolerable.
> 
>> Signed-off-by: Laurentiu Tudor 
>> ---
>>   include/linux/dma-mapping.h | 55 +
>>   1 file changed, 55 insertions(+)
>>
>> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
>> index 4a1c4fca475a..ae7bb8a84b9d 100644
>> --- a/include/linux/dma-mapping.h
>> +++ b/include/linux/dma-mapping.h
>> @@ -132,6 +132,7 @@ struct dma_map_ops {
>>   u64 (*get_required_mask)(struct device *dev);
>>   size_t (*max_mapping_size)(struct device *dev);
>>   unsigned long (*get_merge_boundary)(struct device *dev);
>> +    void *(*get_virt_addr)(struct device *dev, dma_addr_t dma_handle);
>>   };
>>   #define DMA_MAPPING_ERROR    (~(dma_addr_t)0)
>> @@ -304,6 +305,21 @@ static inline void dma_unmap_page_attrs(struct 
>> device *dev, dma_addr_t addr,
>>   debug_dma_unmap_page(dev, addr, size, dir);
>>   }
>> +static inline struct page *
>> +dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t addr, size_t 
>> size,
>> +  enum dma_data_direction dir, unsigned long attrs)
>> +{
>> +    const struct dma_map_ops *ops = get_dma_ops(dev);
>> +    void *ptr = NULL;
>> +
>> +    if (ops && ops->get_virt_addr)
>> +    ptr = ops->get_virt_addr(dev, addr);
> 
> Note that this doesn't work for dma-direct, but for the sake of arm64 at 
> least it almost certainly wants to.
> 
> Robin.
> 
>> +    dma_unmap_page_attrs(dev, addr, size, dir, attrs);
>> +
>> +    return ptr ? virt_to_page(ptr) : NULL;
>> +}
>> +
>>   /*
>>    * dma_maps_sg_attrs returns 0 on error and > 0 on success.
>>    * It should never return a value < 0.
>> @@ -390,6 +406,21 @@ static inline void dma_sync_single_for_cpu(struct 
>> device *dev, dma_addr_t addr,
>>   debug_dma_sync_single_for_cpu(dev, addr, size, dir);
>>   }
>> +static inline void *
>> +dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr, 
>> size_t size,
>> + enum dma_data_direction dir)
>> +{
>> +    const struct dma_map_ops *ops = get_dma_ops(dev);
>> +    void *ptr = NULL;
>> +
>> +    if (ops && ops->get_virt_addr)
>> +    ptr = ops->get_virt_addr(dev, addr);
>> +
>> +    dma_sync_single_for_cpu(dev, addr, size, dir);
>> +
>> +    return ptr;
>> +}
>> +
>>   static inline void dma_sync_single_for_device

[PATCH v3 0/4] dma-mapping: introduce new dma unmap and sync variants

2019-11-13 Thread Laurentiu Tudor
From: Laurentiu Tudor 

This series introduces a few new dma unmap and sync api variants that,
on top of what the originals do, return the virtual address
corresponding to the input dma address. In order to do that a new dma
map op is added, .get_virt_addr that takes the input dma address and
returns the virtual address backing it up.
The second patch adds an implementation for this new dma map op in the
generic iommu dma glue code and wires it in.
The third patch updates the dpaa2-eth driver to use the new apis.

Context: https://lkml.org/lkml/2019/5/31/684

Changes in v3
 * drop useless check for null iommu domain (Robin)
 * add dma_can_unmap_by_dma_addr() to check availability of
   these new apis (Christoph)
 * make apis work with direct dma (Christoph)
 * add support for swiotlb (Robin)
 * simplify dpaa2_eth driver code by using dma_unmap_single_desc()
   instead of dma_unmap_page_desc()

Changes in v2
 * use "dma_unmap_*_desc" names (Robin)
 * return va/page instead of phys addr (Robin)

Changes since RFC
 * completely changed the approach: added unmap and sync variants that
   return the phys addr instead of adding a new dma to phys conversion
   function

Laurentiu Tudor (4):
  dma-mapping: introduce new dma unmap and sync api variants
  iommu/dma: wire-up new dma map op .get_virt_addr
  swiotlb: make new {unmap,sync}_desc dma apis work with swiotlb
  dpaa2_eth: use new unmap and sync dma api variants

 drivers/iommu/dma-iommu.c | 13 
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 43 +-
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 include/linux/dma-mapping.h   | 45 +++
 include/linux/swiotlb.h   |  7 ++
 kernel/dma/mapping.c  | 78 +++
 kernel/dma/swiotlb.c  |  8 ++
 7 files changed, 169 insertions(+), 26 deletions(-)

-- 
2.17.1

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


[PATCH v3 3/4] swiotlb: make new {unmap, sync}_desc dma apis work with swiotlb

2019-11-13 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Add a new swiotlb helper to retrieve the original physical
address given a swiotlb physical address and use it in the new
dma_unmap_single_attrs_desc(), dma_sync_single_for_cpu_desc() and
dma_unmap_page_attrs_desc() APIs to make them work with swiotlb.

Signed-off-by: Laurentiu Tudor 
---
 include/linux/swiotlb.h |  7 +++
 kernel/dma/mapping.c| 43 -
 kernel/dma/swiotlb.c|  8 
 3 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index cde3dc18e21a..7a6883a71649 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -73,6 +73,8 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr)
return paddr >= io_tlb_start && paddr < io_tlb_end;
 }
 
+phys_addr_t swiotlb_get_orig_phys(phys_addr_t tlb_addr);
+
 bool swiotlb_map(struct device *dev, phys_addr_t *phys, dma_addr_t *dma_addr,
size_t size, enum dma_data_direction dir, unsigned long attrs);
 void __init swiotlb_exit(void);
@@ -85,6 +87,11 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr)
 {
return false;
 }
+
+static inline phys_addr_t swiotlb_get_orig_phys(phys_addr_t tlb_addr)
+{
+   return PHYS_ADDR_MAX;
+}
 static inline bool swiotlb_map(struct device *dev, phys_addr_t *phys,
dma_addr_t *dma_addr, size_t size, enum dma_data_direction dir,
unsigned long attrs)
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index 2b6f245c9bb1..1a2d02727271 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /*
  * Managed DMA API
@@ -352,10 +353,18 @@ dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t 
addr, size_t size,
const struct dma_map_ops *ops = get_dma_ops(dev);
void *ptr = NULL;
 
-   if (dma_is_direct(ops))
-   ptr = phys_to_virt(dma_to_phys(dev, addr));
-   else if (ops && ops->get_virt_addr)
+   if (dma_is_direct(ops)) {
+   phys_addr_t phys = dma_to_phys(dev, addr);
+
+   if (is_swiotlb_buffer(phys)) {
+   phys = swiotlb_get_orig_phys(phys);
+   ptr = phys == PHYS_ADDR_MAX ? NULL : phys_to_virt(phys);
+   } else {
+   ptr = phys_to_virt(phys);
+   }
+   } else if (ops && ops->get_virt_addr) {
ptr = ops->get_virt_addr(dev, addr);
+   }
 
dma_unmap_page_attrs(dev, addr, size, dir, attrs);
 
@@ -370,10 +379,18 @@ void *dma_unmap_single_attrs_desc(struct device *dev, 
dma_addr_t addr,
const struct dma_map_ops *ops = get_dma_ops(dev);
void *ptr = NULL;
 
-   if (dma_is_direct(ops))
-   ptr = phys_to_virt(dma_to_phys(dev, addr));
-   else if (ops && ops->get_virt_addr)
+   if (dma_is_direct(ops)) {
+   phys_addr_t phys = dma_to_phys(dev, addr);
+
+   if (is_swiotlb_buffer(phys)) {
+   phys = swiotlb_get_orig_phys(phys);
+   ptr = phys == PHYS_ADDR_MAX ? NULL : phys_to_virt(phys);
+   } else {
+   ptr = phys_to_virt(phys);
+   }
+   } else if (ops && ops->get_virt_addr) {
ptr = ops->get_virt_addr(dev, addr);
+   }
 
dma_unmap_single_attrs(dev, addr, size, dir, attrs);
 
@@ -387,10 +404,18 @@ void *dma_sync_single_for_cpu_desc(struct device *dev, 
dma_addr_t addr,
const struct dma_map_ops *ops = get_dma_ops(dev);
void *ptr = NULL;
 
-   if (dma_is_direct(ops))
-   ptr = phys_to_virt(dma_to_phys(dev, addr));
-   else if (ops && ops->get_virt_addr)
+   if (dma_is_direct(ops)) {
+   phys_addr_t phys = dma_to_phys(dev, addr);
+
+   if (is_swiotlb_buffer(phys)) {
+   phys = swiotlb_get_orig_phys(phys);
+   ptr = phys == PHYS_ADDR_MAX ? NULL : phys_to_virt(phys);
+   } else {
+   ptr = phys_to_virt(phys);
+   }
+   } else if (ops && ops->get_virt_addr) {
ptr = ops->get_virt_addr(dev, addr);
+   }
 
dma_sync_single_for_cpu(dev, addr, size, dir);
 
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index 673a2cdb2656..9b241cc0535b 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -701,6 +701,14 @@ bool is_swiotlb_active(void)
return io_tlb_end != 0;
 }
 
+phys_addr_t swiotlb_get_orig_phys(phys_addr_t tlb_addr)
+{
+   int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
+   phys_addr_t phys = io_tlb_orig_addr[index];
+
+   return phys == INVALID_PHYS_ADDR ? PHYS_ADDR_MAX : phys;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static int __init swiotlb_create_debugfs(void)
-- 
2.17.1

__

[PATCH v3 4/4] dpaa2_eth: use new unmap and sync dma api variants

2019-11-13 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Convert this driver to usage of the newly introduced dma unmap and
sync DMA APIs. This will get rid of the unsupported direct usage of
iommu_iova_to_phys() API.

Signed-off-by: Laurentiu Tudor 
---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 43 ---
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  |  1 -
 2 files changed, 18 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c 
b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 19379bae0144..6b941b753106 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -29,16 +29,6 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
 
-static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
-   dma_addr_t iova_addr)
-{
-   phys_addr_t phys_addr;
-
-   phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
-
-   return phys_to_virt(phys_addr);
-}
-
 static void validate_rx_csum(struct dpaa2_eth_priv *priv,
 u32 fd_status,
 struct sk_buff *skb)
@@ -85,9 +75,9 @@ static void free_rx_fd(struct dpaa2_eth_priv *priv,
sgt = vaddr + dpaa2_fd_get_offset(fd);
for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) {
addr = dpaa2_sg_get_addr(&sgt[i]);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = dma_unmap_single_desc(dev, addr,
+DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL);
 
free_pages((unsigned long)sg_vaddr, 0);
if (dpaa2_sg_is_final(&sgt[i]))
@@ -143,9 +133,9 @@ static struct sk_buff *build_frag_skb(struct dpaa2_eth_priv 
*priv,
 
/* Get the address and length from the S/G entry */
sg_addr = dpaa2_sg_get_addr(sge);
-   sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr);
-   dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   sg_vaddr = dma_unmap_single_desc(dev, sg_addr,
+DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL);
 
sg_length = dpaa2_sg_get_len(sge);
 
@@ -210,9 +200,9 @@ static void free_bufs(struct dpaa2_eth_priv *priv, u64 
*buf_array, int count)
int i;
 
for (i = 0; i < count; i++) {
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]);
-   dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE,
-  DMA_BIDIRECTIONAL);
+   vaddr = dma_unmap_single_desc(dev, buf_array[i],
+ DPAA2_ETH_RX_BUF_SIZE,
+ DMA_BIDIRECTIONAL);
free_pages((unsigned long)vaddr, 0);
}
 }
@@ -369,9 +359,8 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
/* Tracing point */
trace_dpaa2_rx_fd(priv->net_dev, fd);
 
-   vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr);
-   dma_sync_single_for_cpu(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
-   DMA_BIDIRECTIONAL);
+   vaddr = dma_sync_single_for_cpu_desc(dev, addr, DPAA2_ETH_RX_BUF_SIZE,
+DMA_BIDIRECTIONAL);
 
fas = dpaa2_get_fas(vaddr, false);
prefetch(fas);
@@ -682,7 +671,8 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
u32 fd_len = dpaa2_fd_get_len(fd);
 
fd_addr = dpaa2_fd_get_addr(fd);
-   buffer_start = dpaa2_iova_to_virt(priv->iommu_domain, fd_addr);
+   buffer_start = dma_sync_single_for_cpu_desc(dev, fd_addr, sizeof(*swa),
+   DMA_BIDIRECTIONAL);
swa = (struct dpaa2_eth_swa *)buffer_start;
 
if (fd_format == dpaa2_fd_single) {
@@ -3435,6 +3425,11 @@ static int dpaa2_eth_probe(struct fsl_mc_device 
*dpni_dev)
 
dev = &dpni_dev->dev;
 
+   if (!dma_can_unmap_by_dma_addr(dev)) {
+   dev_err(dev, "required dma unmap/sync APIs not available\n");
+   return -ENOTSUPP;
+   }
+
/* Net device */
net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA2_ETH_MAX_NETDEV_QUEUES);
if (!net_dev) {
@@ -3448,8 +3443,6 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
priv = netdev_priv(net_dev);
priv->net_dev = net_dev;
 
-   priv->iommu_domain = iommu_get_domain_for_dev(d

[PATCH v3 1/4] dma-mapping: introduce new dma unmap and sync api variants

2019-11-13 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Introduce a few new dma unmap and sync variants that, on top of the
original variants, return the virtual address corresponding to the
input dma address. Additionally, provide an api that can be used to
check at runtime if these variants are actually available.
In order to implement them, a new dma map op is added and used:
void *get_virt_addr(dev, dma_handle);
It does the actual conversion of an input dma address to the output
virtual address.

Signed-off-by: Laurentiu Tudor 
---
 include/linux/dma-mapping.h | 45 +++
 kernel/dma/mapping.c| 53 +
 2 files changed, 98 insertions(+)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..0940bd75df8e 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -132,6 +132,7 @@ struct dma_map_ops {
u64 (*get_required_mask)(struct device *dev);
size_t (*max_mapping_size)(struct device *dev);
unsigned long (*get_merge_boundary)(struct device *dev);
+   void *(*get_virt_addr)(struct device *dev, dma_addr_t dma_handle);
 };
 
 #define DMA_MAPPING_ERROR  (~(dma_addr_t)0)
@@ -442,6 +443,13 @@ static inline int dma_mapping_error(struct device *dev, 
dma_addr_t dma_addr)
return 0;
 }
 
+static inline bool dma_can_unmap_by_dma_addr(struct device *dev)
+{
+   const struct dma_map_ops *ops = get_dma_ops(dev);
+
+   return dma_is_direct(ops) || (ops && ops->get_virt_addr);
+}
+
 void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t flag, unsigned long attrs);
 void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
@@ -458,6 +466,14 @@ int dma_get_sgtable_attrs(struct device *dev, struct 
sg_table *sgt,
 int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs);
+void *dma_unmap_single_attrs_desc(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+struct page *
+dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs);
+void *dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr,
+  size_t size, enum dma_data_direction dir);
 bool dma_can_mmap(struct device *dev);
 int dma_supported(struct device *dev, u64 mask);
 int dma_set_mask(struct device *dev, u64 mask);
@@ -534,6 +550,27 @@ static inline void dmam_free_coherent(struct device *dev, 
size_t size,
void *vaddr, dma_addr_t dma_handle)
 {
 }
+
+static inline void *
+dma_unmap_single_attrs_desc(struct device *dev, dma_addr_t addr, size_t size,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   return NULL;
+}
+
+static inline struct page *
+dma_unmap_page_attrs_desc(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+   return NULL;
+}
+
+static inline void *
+dma_sync_single_for_cpu_desc(struct device *dev, dma_addr_t addr, size_t size,
+enum dma_data_direction dir)
+{
+   return NULL;
+}
 static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction dir)
 {
@@ -578,6 +615,11 @@ static inline unsigned long dma_get_merge_boundary(struct 
device *dev)
 {
return 0;
 }
+
+static inline bool dma_can_unmap_by_dma_addr(struct device *dev)
+{
+   return false;
+}
 #endif /* CONFIG_HAS_DMA */
 
 static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
@@ -610,10 +652,13 @@ static inline void 
dma_sync_single_range_for_device(struct device *dev,
 
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
+#define dma_unmap_single_desc(d, a, s, r) \
+   dma_unmap_single_attrs_desc(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
 #define dma_map_page(d, p, o, s, r) dma_map_page_attrs(d, p, o, s, r, 0)
 #define dma_unmap_page(d, a, s, r) dma_unmap_page_attrs(d, a, s, r, 0)
+#define dma_unmap_page_desc(d, a, s, r) dma_unmap_page_attrs_desc(d, a, s, r, 
0)
 #define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
 #define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
 
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
index d9334f31a5af..2b6f245c9bb1 100644
--- a/kernel/dma/mapping.c
+++ b/kernel/dma/mapping.c
@@ -345,6 +345,59 @@ void dma_free_attrs(struct device *dev, size_t size, void

[PATCH v3 2/4] iommu/dma: wire-up new dma map op .get_virt_addr

2019-11-13 Thread Laurentiu Tudor
From: Laurentiu Tudor 

Add an implementation of the newly introduced dma map op in the
generic DMA IOMMU generic glue layer and wire it up.

Signed-off-by: Laurentiu Tudor 
---
 drivers/iommu/dma-iommu.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index f321279baf9e..98742c1451ce 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1091,6 +1091,18 @@ static unsigned long iommu_dma_get_merge_boundary(struct 
device *dev)
return (1UL << __ffs(domain->pgsize_bitmap)) - 1;
 }
 
+static void *iommu_dma_get_virt_addr(struct device *dev, dma_addr_t dma_handle)
+{
+   struct iommu_domain *domain = iommu_get_dma_domain(dev);
+   phys_addr_t phys;
+
+   phys = iommu_iova_to_phys(domain, dma_handle);
+   if (phys)
+   return phys_to_virt(phys);
+
+   return NULL;
+}
+
 static const struct dma_map_ops iommu_dma_ops = {
.alloc  = iommu_dma_alloc,
.free   = iommu_dma_free,
@@ -1107,6 +1119,7 @@ static const struct dma_map_ops iommu_dma_ops = {
.map_resource   = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource,
.get_merge_boundary = iommu_dma_get_merge_boundary,
+   .get_virt_addr  = iommu_dma_get_virt_addr,
 };
 
 /*
-- 
2.17.1

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


Re: [PATCH v3 0/4] dma-mapping: introduce new dma unmap and sync variants

2019-11-14 Thread Laurentiu Tudor
On 13.11.2019 22:11, David Miller wrote:
> From: Laurentiu Tudor 
> Date: Wed, 13 Nov 2019 12:24:17 +
> 
>> From: Laurentiu Tudor 
>>
>> This series introduces a few new dma unmap and sync api variants that,
>> on top of what the originals do, return the virtual address
>> corresponding to the input dma address. In order to do that a new dma
>> map op is added, .get_virt_addr that takes the input dma address and
>> returns the virtual address backing it up.
>> The second patch adds an implementation for this new dma map op in the
>> generic iommu dma glue code and wires it in.
>> The third patch updates the dpaa2-eth driver to use the new apis.
> 
> The driver should store the mapping in it's private software state if
> it needs this kind of conversion.

On this hardware there's no way of conveying additional frame 
information, such as original va/pa behind the dma address. We have also 
pondered on the idea of keeping this in some kind of data structure but 
could not find a lock-less solution which obviously would bring 
performance to the ground.
I'll let my colleagues maintaining these ethernet drivers to get into 
more details, if required.

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


RE: [PATCH 05/13] soc/fsl/bqman: page align iommu mapping sizes

2019-04-01 Thread Laurentiu Tudor
Hi Leo,

> -Original Message-
> From: Li Yang [mailto:leoyang...@nxp.com]
> Sent: Saturday, March 30, 2019 12:07 AM
> To: Laurentiu Tudor 
> Cc: Netdev ; Madalin-cristian Bucur
> ; Roy Pledge ; Camelia
> Alexandra Groza ; David Miller
> ; Linux IOMMU ;
> moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE  ker...@lists.infradead.org>; linuxppc-dev ;
> lkml 
> Subject: Re: [PATCH 05/13] soc/fsl/bqman: page align iommu mapping sizes
> Importance: High
> 
> On Fri, Mar 29, 2019 at 9:01 AM  wrote:
> >
> > From: Laurentiu Tudor 
> >
> > Prior to calling iommu_map()/iommu_unmap() page align the size or
> > failures such as below could happen:
> >
> > iommu: unaligned: iova 0x... pa 0x... size 0x4000 min_pagesz 0x1
> > qman_portal 5.qman-portal: failed to iommu_map() -22
> >
> > Seen when booted a kernel compiled with 64K page size support.
> 
> This will silently incease the actual space mapped to 64K when the
> driver is actually trying to map 4K.  Will this potentially cause
> security breaches?  If it is really safe to map 64K, probably the
> better way is to increase the region size to 64k in the device tree
> explicitly.

Not sure if such small reserved areas are practical, so I wouldn't worry 
much. As an example, currently on ls1046a we reserve the following memory:
bman 16MB, qman fqd 8MB, qman pdfr 32MB.
But just to be on the safe side, maybe we could add an error check for 
device trees that specify < 64KB reserved memory.

---
Best Regards, Laurentiu

> >
> > Signed-off-by: Laurentiu Tudor 
> > ---
> >  drivers/soc/fsl/qbman/bman_ccsr.c   | 2 +-
> >  drivers/soc/fsl/qbman/qman_ccsr.c   | 4 ++--
> >  drivers/soc/fsl/qbman/qman_portal.c | 2 +-
> >  3 files changed, 4 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c
> b/drivers/soc/fsl/qbman/bman_ccsr.c
> > index b209c79511bb..3a6e01bde32d 100644
> > --- a/drivers/soc/fsl/qbman/bman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/bman_ccsr.c
> > @@ -230,7 +230,7 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> > /* Create an 1-to-1 iommu mapping for FBPR area */
> > domain = iommu_get_domain_for_dev(dev);
> > if (domain) {
> > -   ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
> > +   ret = iommu_map(domain, fbpr_a, fbpr_a,
> PAGE_ALIGN(fbpr_sz),
> > IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > if (ret)
> > dev_warn(dev, "failed to iommu_map() %d\n",
> ret);
> > diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c
> b/drivers/soc/fsl/qbman/qman_ccsr.c
> > index eec7700507e1..8d3c950ce52d 100644
> > --- a/drivers/soc/fsl/qbman/qman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/qman_ccsr.c
> > @@ -783,11 +783,11 @@ static int fsl_qman_probe(struct platform_device
> *pdev)
> > /* Create an 1-to-1 iommu mapping for fqd and pfdr areas */
> > domain = iommu_get_domain_for_dev(dev);
> > if (domain) {
> > -   ret = iommu_map(domain, fqd_a, fqd_a, fqd_sz,
> > +   ret = iommu_map(domain, fqd_a, fqd_a,
> PAGE_ALIGN(fqd_sz),
> > IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > if (ret)
> > dev_warn(dev, "iommu_map(fqd) failed %d\n",
> ret);
> > -   ret = iommu_map(domain, pfdr_a, pfdr_a, pfdr_sz,
> > +   ret = iommu_map(domain, pfdr_a, pfdr_a,
> PAGE_ALIGN(pfdr_sz),
> > IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > if (ret)
> > dev_warn(dev, "iommu_map(pfdr) failed %d\n",
> ret);
> > diff --git a/drivers/soc/fsl/qbman/qman_portal.c
> b/drivers/soc/fsl/qbman/qman_portal.c
> > index dfb62f9815e9..bce56da2b01f 100644
> > --- a/drivers/soc/fsl/qbman/qman_portal.c
> > +++ b/drivers/soc/fsl/qbman/qman_portal.c
> > @@ -297,7 +297,7 @@ static int qman_portal_probe(struct platform_device
> *pdev)
> >  */
> > err = iommu_map(domain,
> > addr_phys[0]->start, addr_phys[0]-
> >start,
> > -   resource_size(addr_phys[0]),
> > +   PAGE_ALIGN(resource_size(addr_phys[0])),
> > IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > if (err)
> > dev_warn(dev, "failed to iommu_map() %d\n",
> err);
> > --
> > 2.17.1
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH 01/13] soc/fsl/qman: fixup liodns only on ppc targets

2019-04-01 Thread Laurentiu Tudor
Hi Leo,

> -Original Message-
> From: Li Yang [mailto:leoyang...@nxp.com]
> Sent: Friday, March 29, 2019 11:50 PM
> To: Laurentiu Tudor 
> Cc: Netdev ; Madalin-cristian Bucur
> ; Roy Pledge ; Camelia
> Alexandra Groza ; David Miller
> ; Linux IOMMU ;
> moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE  ker...@lists.infradead.org>; linuxppc-dev ;
> lkml 
> Subject: Re: [PATCH 01/13] soc/fsl/qman: fixup liodns only on ppc targets
> Importance: High
> 
> On Fri, Mar 29, 2019 at 9:01 AM  wrote:
> >
> > From: Laurentiu Tudor 
> >
> > ARM SoCs use SMMU so the liodn fixup done in the qman driver is no
> > longer making sense and it also breaks the ICID settings inherited
> > from u-boot. Do the fixups only for PPC targets.
> >
> > Signed-off-by: Laurentiu Tudor 
> > ---
> >  drivers/soc/fsl/qbman/qman_ccsr.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c
> b/drivers/soc/fsl/qbman/qman_ccsr.c
> > index 109b38de3176..12e414ca3b03 100644
> > --- a/drivers/soc/fsl/qbman/qman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/qman_ccsr.c
> > @@ -598,6 +598,7 @@ static int qman_init_ccsr(struct device *dev)
> >  #define LIO_CFG_LIODN_MASK 0x0fff
> >  void qman_liodn_fixup(u16 channel)
> >  {
> > +#ifdef CONFIG_PPC
> > static int done;
> > static u32 liodn_offset;
> > u32 before, after;
> > @@ -617,6 +618,7 @@ void qman_liodn_fixup(u16 channel)
> > qm_ccsr_out(REG_REV3_QCSP_LIO_CFG(idx), after);
> > else
> > qm_ccsr_out(REG_QCSP_LIO_CFG(idx), after);
> > +#endif
> 
> According to the Linux coding style recommendation, it would be better
> to put the #ifdef into the header files
> "drivers/soc/fsl/qbman/qman_priv.h".  And I'm not sure if this is
> needed on PPC when IOMMU(PAMU) driver is not compiled, if not,
> probably using CONFIG_PAMU as condition would be even better.

Good point, will so in the next spin.

---
Best Regards, Laurentiu

> >  }
> >
> >  #define IO_CFG_SDEST_MASK 0x00ff
> > --
> > 2.17.1
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH 13/13] dpaa_eth: fix SG frame cleanup

2019-04-01 Thread Laurentiu Tudor
Hi Joakim,

> -Original Message-
> From: Joakim Tjernlund [mailto:joakim.tjernl...@infinera.com]
> Sent: Friday, March 29, 2019 5:25 PM> 
> 
> Should this one go stable 4.14/4.19 too?

Good point. I also think it makes sense to cc: stable.

---
Best Regards, Laurentiu

> On Fri, 2019-03-29 at 16:00 +0200, laurentiu.tu...@nxp.com wrote:
> >
> > From: Laurentiu Tudor 
> >
> > Fix issue with the entry indexing in the sg frame cleanup code being
> > off-by-1. This problem showed up when doing some basic iperf tests and
> > manifested in traffic coming to a halt.
> >
> > Signed-off-by: Laurentiu Tudor 
> > Acked-by: Madalin Bucur 
> > ---
> >  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > index daede7272768..40420edc9ce6 100644
> > --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > @@ -1663,7 +1663,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const
> struct dpaa_priv *priv,
> >  qm_sg_entry_get_len(&sgt[0]), dma_dir);
> >
> > /* remaining pages were mapped with skb_frag_dma_map()
> */
> > -   for (i = 1; i < nr_frags; i++) {
> > +   for (i = 1; i <= nr_frags; i++) {
> > WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
> >
> > dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
> > --
> > 2.17.1
> >

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


RE: [PATCH 02/13] soc/fsl/bman: map FBPR area in the iommu

2019-04-01 Thread Laurentiu Tudor
Hi Robin,

> -Original Message-
> From: Robin Murphy [mailto:robin.mur...@arm.com]
> Sent: Friday, March 29, 2019 4:51 PM
> 
> On 29/03/2019 14:00, laurentiu.tu...@nxp.com wrote:
> > From: Laurentiu Tudor 
> >
> > Add a one-to-one iommu mapping for bman private data memory (FBPR).
> > This is required for BMAN to work without faults behind an iommu.
> >
> > Signed-off-by: Laurentiu Tudor 
> > ---
> >   drivers/soc/fsl/qbman/bman_ccsr.c | 11 +++
> >   1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c
> b/drivers/soc/fsl/qbman/bman_ccsr.c
> > index 7c3cc968053c..b209c79511bb 100644
> > --- a/drivers/soc/fsl/qbman/bman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/bman_ccsr.c
> > @@ -29,6 +29,7 @@
> >*/
> >
> >   #include "bman_priv.h"
> > +#include 
> >
> >   u16 bman_ip_rev;
> >   EXPORT_SYMBOL(bman_ip_rev);
> > @@ -178,6 +179,7 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> > int ret, err_irq;
> > struct device *dev = &pdev->dev;
> > struct device_node *node = dev->of_node;
> > +   struct iommu_domain *domain;
> > struct resource *res;
> > u16 id, bm_pool_cnt;
> > u8 major, minor;
> > @@ -225,6 +227,15 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> >
> > dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
> >
> > +   /* Create an 1-to-1 iommu mapping for FBPR area */
> > +   domain = iommu_get_domain_for_dev(dev);
> 
> If that's expected to be the default domain that you're grabbing, then
> this is *incredibly* fragile. There's nothing to stop the IOVA that you
> forcibly map from being automatically allocated later and causing some
> other DMA mapping to fail noisily and unexpectedly. 

Agree here, we pretty much rely on luck with this implementation. As a side 
note, I've also experimented using dma_map_resource() instead of directly 
calling into iommu api and things worked fine, but see below ...

> Furthermore, have you tried this with "iommu.passthrough=1"?

Yes. The iommu_map() calls fail and the drivers issue warning messages, but 
apart from that I don't see any issues.

> That said, I really don't understand what's going on here anyway :/
>
> As far as I can tell from qbman_init_private_mem(), fbpr_a comes from
> dma_alloc_coherent() and thus would already be a mapped IOVA - isn't
> this the stuff that Roy converted to nicely use shared-dma-pool regions
> a while ago?

I must say that I'm also unclear on this. The thing is that I don't get to see 
a smmu mapping being created for the reserved memory as result of calling 
dma_alloc_coherent(). IIRC, at the time when I looked at this I concluded that 
the call to dma_alloc_coherent() simply returns the phys address of the 
device's reserved memory without creating a smmu mapping to back it up. Maybe 
my understanding was not correct or perhaps there's an issue with this 
shared-dma-pool mechanism where instead of creating a mapping in the smmu and 
return an IOVA it just returns the physical address of the reserved memory area.

---
Thanks & Best Regards, Laurentiu

> 
> > +   if (domain) {
> > +   ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
> > +   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > +   if (ret)
> > +   dev_warn(dev, "failed to iommu_map() %d\n", ret);
> > +   }
> > +
> > bm_set_memory(fbpr_a, fbpr_sz);
> >
> > err_irq = platform_get_irq(pdev, 0);
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH 02/13] soc/fsl/bman: map FBPR area in the iommu

2019-04-01 Thread Laurentiu Tudor
Hi Leo,

> -Original Message-
> From: Li Yang [mailto:leoyang...@nxp.com]
> Sent: Friday, March 29, 2019 11:16 PM
> 
> On Fri, Mar 29, 2019 at 9:03 AM  wrote:
> >
> > From: Laurentiu Tudor 
> >
> > Add a one-to-one iommu mapping for bman private data memory (FBPR).
> > This is required for BMAN to work without faults behind an iommu.
> >
> > Signed-off-by: Laurentiu Tudor 
> > ---
> >  drivers/soc/fsl/qbman/bman_ccsr.c | 11 +++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c
> b/drivers/soc/fsl/qbman/bman_ccsr.c
> > index 7c3cc968053c..b209c79511bb 100644
> > --- a/drivers/soc/fsl/qbman/bman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/bman_ccsr.c
> > @@ -29,6 +29,7 @@
> >   */
> >
> >  #include "bman_priv.h"
> > +#include 
> >
> >  u16 bman_ip_rev;
> >  EXPORT_SYMBOL(bman_ip_rev);
> > @@ -178,6 +179,7 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> > int ret, err_irq;
> > struct device *dev = &pdev->dev;
> > struct device_node *node = dev->of_node;
> > +   struct iommu_domain *domain;
> > struct resource *res;
> > u16 id, bm_pool_cnt;
> > u8 major, minor;
> > @@ -225,6 +227,15 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> >
> > dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
> >
> > +   /* Create an 1-to-1 iommu mapping for FBPR area */
> > +   domain = iommu_get_domain_for_dev(dev);
> > +   if (domain) {
> > +   ret = iommu_map(domain, fbpr_a, fbpr_a, fbpr_sz,
> > +   IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
> > +   if (ret)
> > +   dev_warn(dev, "failed to iommu_map() %d\n",
> ret);
> > +   }
> 
> Like Robin has pointed out, could you explain why the mapping in this
> patch and other similar patches cannot be dealt with the dma APIs
> automatically?  If the current bqman driver doesn't use the dma APIs
> correctly, we need to fix that instead of doing the mapping
> explicitly.

Please see my reply to Robin.
As a side comment, if we want to convert to dma api it will be interesting to 
see how we'll deal with the qman portal devices as they require a smmu mapping 
for an area of their register block (where stashing goes). Problem is they 
treated as distinct devices, the address where they should dma cannot be 
configured independently for each one of them. I think I can came up with a 
proposal but probably will not look very pretty.

---
Best Regards, Laurentiu

> > +
> > bm_set_memory(fbpr_a, fbpr_sz);
> >
> > err_irq = platform_get_irq(pdev, 0);
> > --
> > 2.17.1
> >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH 02/13] soc/fsl/bman: map FBPR area in the iommu

2019-04-19 Thread Laurentiu Tudor
Hi Robin,

> -Original Message-
> From: Robin Murphy 
> Sent: Friday, March 29, 2019 4:51 PM
> 
> On 29/03/2019 14:00, laurentiu.tu...@nxp.com wrote:
> > From: Laurentiu Tudor 
> >
> > Add a one-to-one iommu mapping for bman private data memory (FBPR).
> > This is required for BMAN to work without faults behind an iommu.
> >
> > Signed-off-by: Laurentiu Tudor 
> > ---
> >   drivers/soc/fsl/qbman/bman_ccsr.c | 11 +++
> >   1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c
> b/drivers/soc/fsl/qbman/bman_ccsr.c
> > index 7c3cc968053c..b209c79511bb 100644
> > --- a/drivers/soc/fsl/qbman/bman_ccsr.c
> > +++ b/drivers/soc/fsl/qbman/bman_ccsr.c
> > @@ -29,6 +29,7 @@
> >*/
> >
> >   #include "bman_priv.h"
> > +#include 
> >
> >   u16 bman_ip_rev;
> >   EXPORT_SYMBOL(bman_ip_rev);
> > @@ -178,6 +179,7 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> > int ret, err_irq;
> > struct device *dev = &pdev->dev;
> > struct device_node *node = dev->of_node;
> > +   struct iommu_domain *domain;
> > struct resource *res;
> > u16 id, bm_pool_cnt;
> > u8 major, minor;
> > @@ -225,6 +227,15 @@ static int fsl_bman_probe(struct platform_device
> *pdev)
> >
> > dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
> >
> > +   /* Create an 1-to-1 iommu mapping for FBPR area */
> > +   domain = iommu_get_domain_for_dev(dev);
> 
> If that's expected to be the default domain that you're grabbing, then
> this is *incredibly* fragile. There's nothing to stop the IOVA that you
> forcibly map from being automatically allocated later and causing some
> other DMA mapping to fail noisily and unexpectedly. Furthermore, have
> you tried this with "iommu.passthrough=1"?
> 
> That said, I really don't understand what's going on here anyway :/
> 
> As far as I can tell from qbman_init_private_mem(), fbpr_a comes from
> dma_alloc_coherent() and thus would already be a mapped IOVA - isn't
> this the stuff that Roy converted to nicely use shared-dma-pool regions
> a while ago?
> 

Finally found some time to look into this, sorry for the delay. It seems that 
on the code path taken in our case (dma_alloc_coherent() -> dma_alloc_attrs() 
-> dma_alloc_from_dev_coherent() -> __dma_alloc_from_coherent()) there's no 
call into the iommu layer, thus no mapping in the smmu. I plan to come up with 
a RFC patch early next week so we have something concrete to discuss on.

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


[RFC PATCH] dma-mapping: create iommu mapping for newly allocated dma coherent mem

2019-04-22 Thread laurentiu . tudor
From: Laurentiu Tudor 

If possible / available call into the DMA API to get a proper iommu
mapping and a dma address for the newly allocated coherent dma memory.

Signed-off-by: Laurentiu Tudor 
---
 arch/arm/mm/dma-mapping-nommu.c |  3 ++-
 include/linux/dma-mapping.h | 12 ++---
 kernel/dma/coherent.c   | 45 +++--
 kernel/dma/mapping.c|  3 ++-
 4 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c
index f304b10e23a4..2c42e83a6995 100644
--- a/arch/arm/mm/dma-mapping-nommu.c
+++ b/arch/arm/mm/dma-mapping-nommu.c
@@ -74,7 +74,8 @@ static void arm_nommu_dma_free(struct device *dev, size_t 
size,
dma_direct_free_pages(dev, size, cpu_addr, dma_addr, attrs);
} else {
int ret = dma_release_from_global_coherent(get_order(size),
-  cpu_addr);
+  cpu_addr, size,
+  dma_addr);
 
WARN_ON_ONCE(ret == 0);
}
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 6309a721394b..cb23334608a7 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -161,19 +161,21 @@ static inline int is_device_dma_capable(struct device 
*dev)
  */
 int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size,
   dma_addr_t *dma_handle, void **ret);
-int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr);
+int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr,
+ ssize_t size, dma_addr_t dma_handle);
 
 int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, size_t size, int *ret);
 
 void *dma_alloc_from_global_coherent(ssize_t size, dma_addr_t *dma_handle);
-int dma_release_from_global_coherent(int order, void *vaddr);
+int dma_release_from_global_coherent(int order, void *vaddr, ssize_t size,
+dma_addr_t dma_handle);
 int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *cpu_addr,
  size_t size, int *ret);
 
 #else
 #define dma_alloc_from_dev_coherent(dev, size, handle, ret) (0)
-#define dma_release_from_dev_coherent(dev, order, vaddr) (0)
+#define dma_release_from_dev_coherent(dev, order, vaddr, size, dma_handle) (0)
 #define dma_mmap_from_dev_coherent(dev, vma, vaddr, order, ret) (0)
 
 static inline void *dma_alloc_from_global_coherent(ssize_t size,
@@ -182,7 +184,9 @@ static inline void *dma_alloc_from_global_coherent(ssize_t 
size,
return NULL;
 }
 
-static inline int dma_release_from_global_coherent(int order, void *vaddr)
+static inline int dma_release_from_global_coherent(int order, void *vaddr
+  ssize_t size,
+  dma_addr_t dma_handle)
 {
return 0;
 }
diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
index 29fd6590dc1e..b40439d6feaa 100644
--- a/kernel/dma/coherent.c
+++ b/kernel/dma/coherent.c
@@ -135,13 +135,15 @@ void dma_release_declared_memory(struct device *dev)
 }
 EXPORT_SYMBOL(dma_release_declared_memory);
 
-static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem,
-   ssize_t size, dma_addr_t *dma_handle)
+static void *__dma_alloc_from_coherent(struct device *dev,
+  struct dma_coherent_mem *mem,
+  ssize_t size, dma_addr_t *dma_handle)
 {
int order = get_order(size);
unsigned long flags;
int pageno;
void *ret;
+   const struct dma_map_ops *ops = dev ? get_dma_ops(dev) : NULL;
 
spin_lock_irqsave(&mem->spinlock, flags);
 
@@ -155,10 +157,16 @@ static void *__dma_alloc_from_coherent(struct 
dma_coherent_mem *mem,
/*
 * Memory was found in the coherent area.
 */
-   *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
ret = mem->virt_base + (pageno << PAGE_SHIFT);
spin_unlock_irqrestore(&mem->spinlock, flags);
memset(ret, 0, size);
+   if (ops && ops->map_resource)
+   *dma_handle = ops->map_resource(dev,
+   mem->device_base +
+   (pageno << PAGE_SHIFT),
+   size, DMA_BIDIRECTIONAL, 0);
+   else
+   *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
return ret;
 err:
spin_unlock_irqrestore(&mem->spinlock, flags);
@@ -187,7 +195,7 @@ int dma_alloc_from_dev_coherent(struct device *dev, ss

RE: [RFC PATCH] dma-mapping: create iommu mapping for newly allocated dma coherent mem

2019-04-23 Thread Laurentiu Tudor
Hello,

> -Original Message-
> From: Christoph Hellwig 
> Sent: Monday, April 22, 2019 9:11 PM
> 
> On Mon, Apr 22, 2019 at 07:51:25PM +0300, laurentiu.tu...@nxp.com wrote:
> > From: Laurentiu Tudor 
> >
> > If possible / available call into the DMA API to get a proper iommu
> > mapping and a dma address for the newly allocated coherent dma memory.
> 
> I don't think this is so simple.  The original use case of
> dma_declare_coherent_memory was memory that is local to a device, where
> we copy in data through a MMIO mapping and the device can then access
> it.  This use case still seems to be alive in the ohci-sm501 and
> ohci-tmio drivers.  Going through the iommu in those cases would be
> counter productive.

I had a feeling that I didn't get the whole story and something isn't quite 
right with this patch. 😊 But I'm happy that we have a discussion started on the 
topic and, I must say, I'm very interested in getting to the bottom of it (I 
have some patches enabling SMMU on a couple of NXP chips and depend on 
resolving this).
I'll try to understand what you're planning but in the meantime please let me 
know if you think I can be of any help.

---
Thanks & Best Regards, Laurentiu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [RFC PATCH] dma-mapping: create iommu mapping for newly allocated dma coherent mem

2019-04-25 Thread Laurentiu Tudor
Hi Christoph,

On 24.04.2019 17:57, Christoph Hellwig wrote:
> I'd be happy to offload all of the mentioned tasks to you if you
> volunteer.

Alright, I think I mostly got it and can start with the two usb drivers 
you mentioned. Just need a few clarifications, please see inline.

> I think the first step is to move the two USB controller that can only
> DMA to their own BAR off the existing DMA coherent infrastructure.  The
> controllers are already identified using the HCD_LOCAL_MEM flag, so we
> just need to key off that in the hcd_buffer_* routines and call into a

So if HCD_LOCAL_MEM is set I should call into the gen_pool api instead 
of existing dma_{alloc,free}_coherent().

> genalloc that has been fed using the bar, replacing the current
> dma_declare_coherent usage.  Take a look at drivers/pci/p2pdma.c
> for another example of allocating bits of a BAR using genalloc.

Where should I place the reference to the gen_pool? How does local_pool 
in 'struct hcd_usb' sound?

---
Thanks & Best Regards, Laurentiu
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 1/9] soc/fsl/qman: fixup liodns only on ppc targets

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

ARM SoCs use SMMU so the liodn fixup done in the qman driver is no
longer making sense and it also breaks the ICID settings inherited
from u-boot. Do the fixups only for PPC targets.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/qman_ccsr.c | 2 +-
 drivers/soc/fsl/qbman/qman_priv.h | 9 -
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c 
b/drivers/soc/fsl/qbman/qman_ccsr.c
index 109b38de3176..a6bb43007d03 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -596,7 +596,7 @@ static int qman_init_ccsr(struct device *dev)
 }
 
 #define LIO_CFG_LIODN_MASK 0x0fff
-void qman_liodn_fixup(u16 channel)
+void __qman_liodn_fixup(u16 channel)
 {
static int done;
static u32 liodn_offset;
diff --git a/drivers/soc/fsl/qbman/qman_priv.h 
b/drivers/soc/fsl/qbman/qman_priv.h
index 75a8f905f8f7..04515718cfd9 100644
--- a/drivers/soc/fsl/qbman/qman_priv.h
+++ b/drivers/soc/fsl/qbman/qman_priv.h
@@ -193,7 +193,14 @@ extern struct gen_pool *qm_cgralloc; /* CGR ID allocator */
 u32 qm_get_pools_sdqcr(void);
 
 int qman_wq_alloc(void);
-void qman_liodn_fixup(u16 channel);
+#ifdef CONFIG_FSL_PAMU
+#define qman_liodn_fixup __qman_liodn_fixup
+#else
+static inline void qman_liodn_fixup(u16 channel)
+{
+}
+#endif
+void __qman_liodn_fixup(u16 channel);
 void qman_set_sdest(u16 channel, unsigned int cpu_idx);
 
 struct qman_portal *qman_create_affine_portal(
-- 
2.17.1

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


[PATCH v2 4/9] fsl/fman: add API to get the device behind a fman port

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add an API that retrieves the 'struct device' that the specified fman
port probed against. The new API will be used in a subsequent iommu
enablement related patch.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/fman/fman_port.c | 14 ++
 drivers/net/ethernet/freescale/fman/fman_port.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c 
b/drivers/net/ethernet/freescale/fman/fman_port.c
index ee82ee1384eb..bd76c9730692 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1728,6 +1728,20 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port)
 }
 EXPORT_SYMBOL(fman_port_get_qman_channel_id);
 
+/**
+ * fman_port_get_device
+ * port:   Pointer to the FMan port device
+ *
+ * Get the 'struct device' associated to the specified FMan port device
+ *
+ * Return: pointer to associated 'struct device'
+ */
+struct device *fman_port_get_device(struct fman_port *port)
+{
+   return port->dev;
+}
+EXPORT_SYMBOL(fman_port_get_device);
+
 int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
 {
if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE)
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h 
b/drivers/net/ethernet/freescale/fman/fman_port.h
index 9dbb69f40121..82f12661a46d 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.h
+++ b/drivers/net/ethernet/freescale/fman/fman_port.h
@@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_port *port, const void 
*data, u64 *tstamp);
 
 struct fman_port *fman_port_bind(struct device *dev);
 
+struct device *fman_port_get_device(struct fman_port *port);
+
 #endif /* __FMAN_PORT_H */
-- 
2.17.1

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


[PATCH v2 2/9] soc/fsl/qbman_portals: add APIs to retrieve the probing status

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

Add a couple of new APIs to check the probing status of the required
cpu bound qman and bman portals:
 'int bman_portals_probed()' and 'int qman_portals_probed()'.
They return the following values.
 *  1 if qman/bman portals were all probed correctly
 *  0 if qman/bman portals were not yet probed
 * -1 if probing of qman/bman portals failed
Portals are considered successful probed if no error occurred during
the probing of any of the portals and if enough portals were probed
to have one available for each cpu.
The error handling paths were slightly rearranged in order to fit this
new functionality without being too intrusive.
Drivers that use qman/bman portal driver services are required to use
these APIs before calling any functions exported by these drivers or
otherwise they will crash the kernel.
First user will be the dpaa1 ethernet driver, coming in a subsequent
patch.

Signed-off-by: Laurentiu Tudor 
---
 drivers/soc/fsl/qbman/bman_portal.c | 20 
 drivers/soc/fsl/qbman/qman_portal.c | 21 +
 include/soc/fsl/bman.h  |  8 
 include/soc/fsl/qman.h  |  9 +
 4 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/fsl/qbman/bman_portal.c 
b/drivers/soc/fsl/qbman/bman_portal.c
index 2c95cf59f3e7..cf4f10d6f590 100644
--- a/drivers/soc/fsl/qbman/bman_portal.c
+++ b/drivers/soc/fsl/qbman/bman_portal.c
@@ -32,6 +32,7 @@
 
 static struct bman_portal *affine_bportals[NR_CPUS];
 static struct cpumask portal_cpus;
+static int __bman_portals_probed;
 /* protect bman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(bman_lock);
 
@@ -87,6 +88,12 @@ static int bman_online_cpu(unsigned int cpu)
return 0;
 }
 
+int bman_portals_probed(void)
+{
+   return __bman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(bman_portals_probed);
+
 static int bman_portal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -104,8 +111,10 @@ static int bman_portal_probe(struct platform_device *pdev)
}
 
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-   if (!pcfg)
+   if (!pcfg) {
+   __bman_portals_probed = -1;
return -ENOMEM;
+   }
 
pcfg->dev = dev;
 
@@ -113,14 +122,14 @@ static int bman_portal_probe(struct platform_device *pdev)
 DPAA_PORTAL_CE);
if (!addr_phys[0]) {
dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
 
addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
 DPAA_PORTAL_CI);
if (!addr_phys[1]) {
dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
 
pcfg->cpu = -1;
@@ -128,7 +137,7 @@ static int bman_portal_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "Can't get %pOF IRQ'\n", node);
-   return -ENXIO;
+   goto err_ioremap1;
}
pcfg->irq = irq;
 
@@ -150,6 +159,7 @@ static int bman_portal_probe(struct platform_device *pdev)
spin_lock(&bman_lock);
cpu = cpumask_next_zero(-1, &portal_cpus);
if (cpu >= nr_cpu_ids) {
+   __bman_portals_probed = 1;
/* unassigned portal, skip init */
spin_unlock(&bman_lock);
return 0;
@@ -175,6 +185,8 @@ static int bman_portal_probe(struct platform_device *pdev)
 err_ioremap2:
memunmap(pcfg->addr_virt_ce);
 err_ioremap1:
+__bman_portals_probed = -1;
+
return -ENXIO;
 }
 
diff --git a/drivers/soc/fsl/qbman/qman_portal.c 
b/drivers/soc/fsl/qbman/qman_portal.c
index 661c9b234d32..e2186b681d87 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -38,6 +38,7 @@ EXPORT_SYMBOL(qman_dma_portal);
 #define CONFIG_FSL_DPA_PIRQ_FAST  1
 
 static struct cpumask portal_cpus;
+static int __qman_portals_probed;
 /* protect qman global registers and global data shared among portals */
 static DEFINE_SPINLOCK(qman_lock);
 
@@ -220,6 +221,12 @@ static int qman_online_cpu(unsigned int cpu)
return 0;
 }
 
+int qman_portals_probed(void)
+{
+   return __qman_portals_probed;
+}
+EXPORT_SYMBOL_GPL(qman_portals_probed);
+
 static int qman_portal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -238,8 +245,10 @@ static int qman_portal_probe(struct platform_device *pdev)
}
 
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
-   if (!pcfg)
+   if (!pcfg) {
+

[PATCH v2 5/9] dpaa_eth: defer probing after qbman

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

Enabling SMMU altered the order of device probing causing the dpaa1
ethernet driver to get probed before qbman and causing a boot crash.
Add predictability in the probing order by deferring the ethernet
driver probe after qbman and portals by using the recently introduced
qbman APIs.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index dfebc30c4841..647e90e7434f 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2774,6 +2774,37 @@ static int dpaa_eth_probe(struct platform_device *pdev)
int err = 0, i, channel;
struct device *dev;
 
+   err = bman_is_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev, "failing probe due to bman probe error\n");
+   return -ENODEV;
+   }
+   err = qman_is_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev, "failing probe due to qman probe error\n");
+   return -ENODEV;
+   }
+   err = bman_portals_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev,
+   "failing probe due to bman portals probe error\n");
+   return -ENODEV;
+   }
+   err = qman_portals_probed();
+   if (!err)
+   return -EPROBE_DEFER;
+   if (err < 0) {
+   dev_err(&pdev->dev,
+   "failing probe due to qman portals probe error\n");
+   return -ENODEV;
+   }
+
/* device used for DMA mapping */
dev = pdev->dev.parent;
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
-- 
2.17.1

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


[PATCH v2 0/9] Prerequisites for NXP LS104xA SMMU enablement

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

This patch series contains several fixes in preparation for SMMU
support on NXP LS1043A and LS1046A chips. Once these get picked up,
I'll submit the actual SMMU enablement patches consisting in the
required device tree changes.

This patch series contains only part of the previously submitted one,
(including also the device tree changes) available here:

https://patchwork.kernel.org/cover/10634443/

Changes in v2:
 - dropped patches dealing with mapping reserved memory in iommu
 - changed logic for qman portal probe status (Leo)
 - moved "#ifdef CONFIG_PAMU" in header file (Leo)
 - rebased on v5.1.0-rc5

Laurentiu Tudor (9):
  soc/fsl/qman: fixup liodns only on ppc targets
  soc/fsl/qbman_portals: add APIs to retrieve the probing status
  fsl/fman: backup and restore ICID registers
  fsl/fman: add API to get the device behind a fman port
  dpaa_eth: defer probing after qbman
  dpaa_eth: base dma mappings on the fman rx port
  dpaa_eth: fix iova handling for contiguous frames
  dpaa_eth: fix iova handling for sg frames
  dpaa_eth: fix SG frame cleanup

 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 136 --
 drivers/net/ethernet/freescale/fman/fman.c|  35 -
 drivers/net/ethernet/freescale/fman/fman.h|   4 +
 .../net/ethernet/freescale/fman/fman_port.c   |  14 ++
 .../net/ethernet/freescale/fman/fman_port.h   |   2 +
 drivers/soc/fsl/qbman/bman_portal.c   |  20 ++-
 drivers/soc/fsl/qbman/qman_ccsr.c |   2 +-
 drivers/soc/fsl/qbman/qman_portal.c   |  21 ++-
 drivers/soc/fsl/qbman/qman_priv.h |   9 +-
 include/soc/fsl/bman.h|   8 ++
 include/soc/fsl/qman.h|   9 ++
 11 files changed, 202 insertions(+), 58 deletions(-)

-- 
2.17.1

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


[PATCH v2 7/9] dpaa_eth: fix iova handling for contiguous frames

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this by adding a function that does
proper iova -> phys conversions using the iommu api and update the code
to use it.
Also, a dma_unmap_single() call had to be moved further down the code
because iova -> vaddr conversions were required before the unmap.
For now only the contiguous frame case is handled and the SG case is
split in a following patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 44 ++-
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index cdc7e6d83f77..f17edc80dc37 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -50,6 +50,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1595,6 +1596,17 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv)
return 0;
 }
 
+static phys_addr_t dpaa_iova_to_phys(struct device *dev, dma_addr_t addr)
+{
+   struct iommu_domain *domain;
+
+   domain = iommu_get_domain_for_dev(dev);
+   if (domain)
+   return iommu_iova_to_phys(domain, addr);
+   else
+   return addr;
+}
+
 /* Cleanup function for outgoing frame descriptors that were built on Tx path,
  * either contiguous frames or scatter/gather ones.
  * Skb freeing is not handled here.
@@ -1617,7 +1629,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
int nr_frags, i;
u64 ns;
 
-   skbh = (struct sk_buff **)phys_to_virt(addr);
+   skbh = (struct sk_buff **)phys_to_virt(dpaa_iova_to_phys(dev, addr));
skb = *skbh;
 
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
@@ -1687,25 +1699,21 @@ static u8 rx_csum_offload(const struct dpaa_priv *priv, 
const struct qm_fd *fd)
  * accommodate the shared info area of the skb.
  */
 static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
-   const struct qm_fd *fd)
+   const struct qm_fd *fd,
+   struct dpaa_bp *dpaa_bp,
+   void *vaddr)
 {
ssize_t fd_off = qm_fd_get_offset(fd);
-   dma_addr_t addr = qm_fd_addr(fd);
-   struct dpaa_bp *dpaa_bp;
struct sk_buff *skb;
-   void *vaddr;
 
-   vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
 
-   dpaa_bp = dpaa_bpid2pool(fd->bpid);
-   if (!dpaa_bp)
-   goto free_buffer;
-
skb = build_skb(vaddr, dpaa_bp->size +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
-   if (WARN_ONCE(!skb, "Build skb failure on Rx\n"))
-   goto free_buffer;
+   if (WARN_ONCE(!skb, "Build skb failure on Rx\n")) {
+   skb_free_frag(vaddr);
+   return NULL;
+   }
WARN_ON(fd_off != priv->rx_headroom);
skb_reserve(skb, fd_off);
skb_put(skb, qm_fd_get_length(fd));
@@ -1713,10 +1721,6 @@ static struct sk_buff *contig_fd_to_skb(const struct 
dpaa_priv *priv,
skb->ip_summed = rx_csum_offload(priv, fd);
 
return skb;
-
-free_buffer:
-   skb_free_frag(vaddr);
-   return NULL;
 }
 
 /* Build an skb with the data of the first S/G entry in the linear portion and
@@ -2309,12 +2313,12 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct 
qman_portal *portal,
if (!dpaa_bp)
return qman_cb_dqrr_consume;
 
-   dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
-
/* prefetch the first 64 bytes of the frame or the SGT start */
-   vaddr = phys_to_virt(addr);
+   vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev, addr));
prefetch(vaddr + qm_fd_get_offset(fd));
 
+   dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE);
+
/* The only FD types that we may receive are contig and S/G */
WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
 
@@ -2325,7 +2329,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct 
qman_portal *portal,
(*count_ptr)--;
 
if (likely(fd_format == qm_fd_contig))
-   skb = contig_fd_to_skb(priv, fd);
+   skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
else
skb = sg_fd_to_skb(priv, fd);
if (!skb)
-- 
2.17.1

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


[PATCH v2 6/9] dpaa_eth: base dma mappings on the fman rx port

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

The dma transactions initiator is the rx fman port so that's the device
that the dma mappings should be done. Previously the mappings were done
through the MAC device which makes no sense because it's neither dma-able
nor connected in any way to smmu.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 647e90e7434f..cdc7e6d83f77 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2805,8 +2805,15 @@ static int dpaa_eth_probe(struct platform_device *pdev)
return -ENODEV;
}
 
+   mac_dev = dpaa_mac_dev_get(pdev);
+   if (IS_ERR(mac_dev)) {
+   dev_err(&pdev->dev, "dpaa_mac_dev_get() failed\n");
+   err = PTR_ERR(mac_dev);
+   goto probe_err;
+   }
+
/* device used for DMA mapping */
-   dev = pdev->dev.parent;
+   dev = fman_port_get_device(mac_dev->port[RX]);
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
if (err) {
dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
@@ -2831,13 +2838,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)
 
priv->msg_enable = netif_msg_init(debug, DPAA_MSG_DEFAULT);
 
-   mac_dev = dpaa_mac_dev_get(pdev);
-   if (IS_ERR(mac_dev)) {
-   dev_err(dev, "dpaa_mac_dev_get() failed\n");
-   err = PTR_ERR(mac_dev);
-   goto free_netdev;
-   }
-
/* If fsl_fm_max_frm is set to a higher value than the all-common 1500,
 * we choose conservatively and let the user explicitly set a higher
 * MTU via ifconfig. Otherwise, the user may end up with different MTUs
@@ -2973,9 +2973,9 @@ static int dpaa_eth_probe(struct platform_device *pdev)
qman_release_cgrid(priv->cgr_data.cgr.cgrid);
 free_dpaa_bps:
dpaa_bps_free(priv);
-free_netdev:
dev_set_drvdata(dev, NULL);
free_netdev(net_dev);
+probe_err:
 
return err;
 }
-- 
2.17.1

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


[PATCH v2 3/9] fsl/fman: backup and restore ICID registers

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

During probing, FMAN is reset thus losing all its register
settings. Backup port ICID registers before reset and restore
them after, similarly to how it's done on powerpc / PAMU based
platforms.
This also has the side effect of disabling the old code path
(liodn backup/restore handling) that obviously make no sense
in the context of SMMU on ARMs.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/fman/fman.c | 35 +-
 drivers/net/ethernet/freescale/fman/fman.h |  4 +++
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman.c 
b/drivers/net/ethernet/freescale/fman/fman.c
index e80fedb27cee..ae833e215b74 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -629,6 +629,7 @@ static void set_port_order_restoration(struct fman_fpm_regs 
__iomem *fpm_rg,
iowrite32be(tmp, &fpm_rg->fmfp_prc);
 }
 
+#ifdef CONFIG_PPC
 static void set_port_liodn(struct fman *fman, u8 port_id,
   u32 liodn_base, u32 liodn_ofst)
 {
@@ -646,6 +647,27 @@ static void set_port_liodn(struct fman *fman, u8 port_id,
iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]);
iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
 }
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+static void save_restore_port_icids(struct fman *fman, bool save)
+{
+   int port_idxes[] = {
+   0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc,
+   0xd, 0xe, 0xf, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+   0x10, 0x11, 0x30, 0x31
+   };
+   int idx, i;
+
+   for (i = 0; i < ARRAY_SIZE(port_idxes); i++) {
+   idx = port_idxes[i];
+   if (save)
+   fman->sp_icids[idx] =
+   ioread32be(&fman->bmi_regs->fmbm_spliodn[idx]);
+   else
+   iowrite32be(fman->sp_icids[idx],
+   &fman->bmi_regs->fmbm_spliodn[idx]);
+   }
+}
+#endif
 
 static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
 {
@@ -1914,7 +1936,10 @@ static int fman_reset(struct fman *fman)
 static int fman_init(struct fman *fman)
 {
struct fman_cfg *cfg = NULL;
-   int err = 0, i, count;
+   int err = 0, count;
+#ifdef CONFIG_PPC
+   int i;
+#endif
 
if (is_init_done(fman->cfg))
return -EINVAL;
@@ -1934,6 +1959,7 @@ static int fman_init(struct fman *fman)
memset_io((void __iomem *)(fman->base_addr + CGP_OFFSET), 0,
  fman->state->fm_port_num_of_cg);
 
+#ifdef CONFIG_PPC
/* Save LIODN info before FMan reset
 * Skipping non-existent port 0 (i = 1)
 */
@@ -1953,6 +1979,9 @@ static int fman_init(struct fman *fman)
}
fman->liodn_base[i] = liodn_base;
}
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   save_restore_port_icids(fman, true);
+#endif
 
err = fman_reset(fman);
if (err)
@@ -2181,8 +2210,12 @@ int fman_set_port_params(struct fman *fman,
if (err)
goto return_err;
 
+#ifdef CONFIG_PPC
set_port_liodn(fman, port_id, fman->liodn_base[port_id],
   fman->liodn_offset[port_id]);
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   save_restore_port_icids(fman, false);
+#endif
 
if (fman->state->rev_info.major < 6)
set_port_order_restoration(fman->fpm_regs, port_id);
diff --git a/drivers/net/ethernet/freescale/fman/fman.h 
b/drivers/net/ethernet/freescale/fman/fman.h
index 935c317fa696..19f20fa58053 100644
--- a/drivers/net/ethernet/freescale/fman/fman.h
+++ b/drivers/net/ethernet/freescale/fman/fman.h
@@ -346,8 +346,12 @@ struct fman {
unsigned long fifo_offset;
size_t fifo_size;
 
+#ifdef CONFIG_PPC
u32 liodn_base[64];
u32 liodn_offset[64];
+#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+   u32 sp_icids[64];
+#endif
 
struct fman_dts_params dts_params;
 };
-- 
2.17.1

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


[PATCH v2 9/9] dpaa_eth: fix SG frame cleanup

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

Fix issue with the entry indexing in the sg frame cleanup code being
off-by-1. This problem showed up when doing some basic iperf tests and
manifested in traffic coming to a halt.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index daede7272768..40420edc9ce6 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1663,7 +1663,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
 qm_sg_entry_get_len(&sgt[0]), dma_dir);
 
/* remaining pages were mapped with skb_frag_dma_map() */
-   for (i = 1; i < nr_frags; i++) {
+   for (i = 1; i <= nr_frags; i++) {
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
 
dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
-- 
2.17.1

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


[PATCH v2 8/9] dpaa_eth: fix iova handling for sg frames

2019-04-27 Thread laurentiu . tudor
From: Laurentiu Tudor 

The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this also for scatter-gather frames
using the iova -> phys conversion function added in the previous patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 41 +++
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index f17edc80dc37..daede7272768 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1646,14 +1646,17 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
 
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
-   dma_unmap_single(dev, addr,
-qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
-dma_dir);
 
/* The sgt buffer has been allocated with netdev_alloc_frag(),
 * it's from lowmem.
 */
-   sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
+   sgt = phys_to_virt(dpaa_iova_to_phys(dev,
+addr +
+qm_fd_get_offset(fd)));
+
+   dma_unmap_single(dev, addr,
+qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+dma_dir);
 
/* sgt[0] is from lowmem, was dma_map_single()-ed */
dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
@@ -1668,7 +1671,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
}
 
/* Free the page frag that we allocated on Tx */
-   skb_free_frag(phys_to_virt(addr));
+   skb_free_frag(skbh);
} else {
dma_unmap_single(dev, addr,
 skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
@@ -1729,14 +1732,14 @@ static struct sk_buff *contig_fd_to_skb(const struct 
dpaa_priv *priv,
  * The page fragment holding the S/G Table is recycled here.
  */
 static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
-   const struct qm_fd *fd)
+   const struct qm_fd *fd,
+   struct dpaa_bp *dpaa_bp,
+   void *vaddr)
 {
ssize_t fd_off = qm_fd_get_offset(fd);
-   dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct page *page, *head_page;
-   struct dpaa_bp *dpaa_bp;
-   void *vaddr, *sg_vaddr;
+   void *sg_vaddr;
int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
@@ -1745,7 +1748,6 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
int *count_ptr;
int i;
 
-   vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
 
/* Iterate through the SGT entries and add data buffers to the skb */
@@ -1756,14 +1758,18 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
 
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
-   SMP_CACHE_BYTES));
 
/* We may use multiple Rx pools */
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
-   if (!dpaa_bp)
+   if (!dpaa_bp) {
+   pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
+   __func__, sgt[i].bpid);
goto free_buffers;
+   }
+   sg_vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev,
+ sg_addr));
+   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+   SMP_CACHE_BYTES));
 
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
@@ -1835,10 +1841,11 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
/* free all the SG entries */
for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   skb_free_frag(sg_vaddr);
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
if (dpaa_bp

RE: [PATCH v2 9/9] dpaa_eth: fix SG frame cleanup

2019-05-02 Thread Laurentiu Tudor
Hi Joakim,

> -Original Message-
> From: Joakim Tjernlund 
> Sent: Saturday, April 27, 2019 8:11 PM
> 
> On Sat, 2019-04-27 at 10:10 +0300, laurentiu.tu...@nxp.com wrote:
> > From: Laurentiu Tudor 
> >
> > Fix issue with the entry indexing in the sg frame cleanup code being
> > off-by-1. This problem showed up when doing some basic iperf tests and
> > manifested in traffic coming to a halt.
> >
> > Signed-off-by: Laurentiu Tudor 
> > Acked-by: Madalin Bucur 
> 
> Wasn't this a stable candidate too?

Yes, it is. I forgot to add the cc:stable tag, sorry about that.

---
Best Regards, Laurentiu
 
> > ---
> >  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > index daede7272768..40420edc9ce6 100644
> > --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > @@ -1663,7 +1663,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const
> struct dpaa_priv *priv,
> >  qm_sg_entry_get_len(&sgt[0]), dma_dir);
> >
> > /* remaining pages were mapped with skb_frag_dma_map()
> */
> > -   for (i = 1; i < nr_frags; i++) {
> > +   for (i = 1; i <= nr_frags; i++) {
> > WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
> >
> > dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
> > --
> > 2.17.1
> >

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


RE: [PATCH v2 7/9] dpaa_eth: fix iova handling for contiguous frames

2019-05-02 Thread Laurentiu Tudor



> -Original Message-
> From: Christoph Hellwig 
> Sent: Saturday, April 27, 2019 7:46 PM
> 
> On Sat, Apr 27, 2019 at 10:10:29AM +0300, laurentiu.tu...@nxp.com wrote:
> > From: Laurentiu Tudor 
> >
> > The driver relies on the no longer valid assumption that dma addresses
> > (iovas) are identical to physical addressees and uses phys_to_virt() to
> > make iova -> vaddr conversions. Fix this by adding a function that does
> > proper iova -> phys conversions using the iommu api and update the code
> > to use it.
> > Also, a dma_unmap_single() call had to be moved further down the code
> > because iova -> vaddr conversions were required before the unmap.
> > For now only the contiguous frame case is handled and the SG case is
> > split in a following patch.
> > While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
> > as parameter.
> 
> Err, this is broken.  A driver using the DMA API has no business
> call IOMMU APIs.  Just save the _virtual_ address used for the mapping
> away and use that again.  We should not go through crazy gymnastics
> like this.

I think that due to the particularity of this hardware we don't have a way of 
saving the VA, but I'd let my colleagues maintaining this driver to comment 
more on why we need to do this.

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


RE: [PATCH v2 9/9] dpaa_eth: fix SG frame cleanup

2019-05-02 Thread Laurentiu Tudor



> -Original Message-
> From: Joakim Tjernlund 
> Sent: Thursday, May 2, 2019 1:37 PM
> 
> On Thu, 2019-05-02 at 09:05 +0000, Laurentiu Tudor wrote:
> > Hi Joakim,
> >
> > > -Original Message-
> > > From: Joakim Tjernlund 
> > > Sent: Saturday, April 27, 2019 8:11 PM
> > >
> > > On Sat, 2019-04-27 at 10:10 +0300, laurentiu.tu...@nxp.com wrote:
> > > > From: Laurentiu Tudor 
> > > >
> > > > Fix issue with the entry indexing in the sg frame cleanup code being
> > > > off-by-1. This problem showed up when doing some basic iperf tests
> and
> > > > manifested in traffic coming to a halt.
> > > >
> > > > Signed-off-by: Laurentiu Tudor 
> > > > Acked-by: Madalin Bucur 
> > >
> > > Wasn't this a stable candidate too?
> >
> > Yes, it is. I forgot to add the cc:stable tag, sorry about that.
> 
> Then this is a bug fix that should go directly to linus/stable.
> 
> I note that
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/log/drivers/net/ethernet/freescale/dpaa?h=linux-4.19.y

Not sure I understand ... I don't see the patch in the link.

> is in 4.19 but not in 4.14 , is it not appropriate for 4.14?

I think it makes sense to go in both stable trees.

---
Best Regards, Laurentiu

> >
> > > > ---
> > > >  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +-
> > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > > b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > > > index daede7272768..40420edc9ce6 100644
> > > > --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > > > +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > > > @@ -1663,7 +1663,7 @@ static struct sk_buff
> *dpaa_cleanup_tx_fd(const
> > > struct dpaa_priv *priv,
> > > >  qm_sg_entry_get_len(&sgt[0]),
> dma_dir);
> > > >
> > > > /* remaining pages were mapped with
> skb_frag_dma_map()
> > > */
> > > > -   for (i = 1; i < nr_frags; i++) {
> > > > +   for (i = 1; i <= nr_frags; i++) {
> > > > WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
> > > >
> > > > dma_unmap_page(dev, qm_sg_addr(&sgt[i]),
> > > > --
> > > > 2.17.1
> > > >
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [ARM SMMU] Dynamic StreamID allocation

2019-05-13 Thread Laurentiu Tudor
Hi Pankaj,

> -Original Message-
> From: linux-arm-kernel  On
> Behalf Of Pankaj Bansal
> Sent: Friday, May 10, 2019 3:34 PM
> 
> Hi Will/Robin/Joerg,
> 
> I am s/w engineer from NXP India Pvt. Ltd.
> We are using SMMU-V3 in one of NXP SOC.
> I have a question about the SMMU Stream ID allocation in linux.
> 
> Right now the Stream IDs allocated to a device are mapped via device tree
> to the device.

[snip]

> 
> As the device tree is passed from bootloader to linux, we detect all the
> stream IDs needed by a device in bootloader and add their IDs in
> respective device nodes.
> For each PCIE Endpoint (a unique BDF (Bus Device Function)) on PCIE bus,
> we are assigning a unique Stream ID in bootloader.
> 
> However, this poses an issue with PCIE hot plug.
> If we plug in a pcie device while linux is running, a unique BDF is
> assigned to the device, for which there is no stream ID in device tree.
> 
> How can this problem be solved in linux?
> 
> Is there a way to assign (and revoke) stream IDs at run time?

I think that our main problem is that we enumerate the PCI EPs in the 
bootloader (u-boot) and allocate StreamIDs just for them, completely 
disregarding hotplug scenarios. One simple fix would be to not do this and 
simply allocate a decently sized, fixed range of StreamIDs per PCI controller.

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


[PATCH v3 1/6] fsl/fman: don't touch liodn base regs reserved on non-PAMU SoCs

2019-05-30 Thread laurentiu . tudor
From: Laurentiu Tudor 

liodn base registers are specific to PAMU based NXP systems and on SMMU
based ones are reserved. Don't access them if PAMU is compiled in.

Signed-off-by: Laurentiu Tudor 
---
 drivers/net/ethernet/freescale/fman/fman.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman.c 
b/drivers/net/ethernet/freescale/fman/fman.c
index e80fedb27cee..cce6636b1763 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -634,6 +634,9 @@ static void set_port_liodn(struct fman *fman, u8 port_id,
 {
u32 tmp;
 
+   iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
+   if (!IS_ENABLED(CONFIG_FSL_PAMU))
+   return;
/* set LIODN base for this port */
tmp = ioread32be(&fman->dma_regs->fmdmplr[port_id / 2]);
if (port_id % 2) {
@@ -644,7 +647,6 @@ static void set_port_liodn(struct fman *fman, u8 port_id,
tmp |= liodn_base << DMA_LIODN_SHIFT;
}
iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]);
-   iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]);
 }
 
 static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg)
@@ -1942,6 +1944,8 @@ static int fman_init(struct fman *fman)
 
fman->liodn_offset[i] =
ioread32be(&fman->bmi_regs->fmbm_spliodn[i - 1]);
+   if (!IS_ENABLED(CONFIG_FSL_PAMU))
+   continue;
liodn_base = ioread32be(&fman->dma_regs->fmdmplr[i / 2]);
if (i % 2) {
/* FMDM_PLR LSB holds LIODN base for odd ports */
-- 
2.17.1



[PATCH v3 6/6] dpaa_eth: fix iova handling for sg frames

2019-05-30 Thread laurentiu . tudor
From: Laurentiu Tudor 

The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this also for scatter-gather frames
using the iova -> phys conversion function added in the previous patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.

Signed-off-by: Laurentiu Tudor 
Acked-by: Madalin Bucur 
---
 .../net/ethernet/freescale/dpaa/dpaa_eth.c| 40 +++
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 46194a04617a..7d978a93dffd 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1641,14 +1641,17 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
 
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
-   dma_unmap_single(dev, addr,
-qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
-dma_dir);
 
/* The sgt buffer has been allocated with netdev_alloc_frag(),
 * it's from lowmem.
 */
-   sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
+   sgt = phys_to_virt(dpaa_iova_to_phys(priv,
+addr +
+qm_fd_get_offset(fd)));
+
+   dma_unmap_single(dev, addr,
+qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+dma_dir);
 
/* sgt[0] is from lowmem, was dma_map_single()-ed */
dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
@@ -1663,7 +1666,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct 
dpaa_priv *priv,
}
 
/* Free the page frag that we allocated on Tx */
-   skb_free_frag(phys_to_virt(addr));
+   skb_free_frag(skbh);
} else {
dma_unmap_single(dev, addr,
 skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
@@ -1724,14 +1727,14 @@ static struct sk_buff *contig_fd_to_skb(const struct 
dpaa_priv *priv,
  * The page fragment holding the S/G Table is recycled here.
  */
 static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
-   const struct qm_fd *fd)
+   const struct qm_fd *fd,
+   struct dpaa_bp *dpaa_bp,
+   void *vaddr)
 {
ssize_t fd_off = qm_fd_get_offset(fd);
-   dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct page *page, *head_page;
-   struct dpaa_bp *dpaa_bp;
-   void *vaddr, *sg_vaddr;
+   void *sg_vaddr;
int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
@@ -1740,7 +1743,6 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
int *count_ptr;
int i;
 
-   vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
 
/* Iterate through the SGT entries and add data buffers to the skb */
@@ -1751,14 +1753,17 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
 
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
-   SMP_CACHE_BYTES));
 
/* We may use multiple Rx pools */
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
-   if (!dpaa_bp)
+   if (!dpaa_bp) {
+   pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
+   __func__, sgt[i].bpid);
goto free_buffers;
+   }
+   sg_vaddr = phys_to_virt(dpaa_iova_to_phys(priv, sg_addr));
+   WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+   SMP_CACHE_BYTES));
 
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
@@ -1830,10 +1835,11 @@ static struct sk_buff *sg_fd_to_skb(const struct 
dpaa_priv *priv,
/* free all the SG entries */
for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
sg_addr = qm_sg_addr(&sgt[i]);
-   sg_vaddr = phys_to_virt(sg_addr);
-   skb_free_frag(sg_vaddr);
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
if (dpaa_bp) {
+   sg_addr = dpaa_iova_to_phys(priv, sg_ad

  1   2   >