diff mbox series

[03/14] mmc: sdhci: correct the DMA setting for IOMMU

Message ID 1573816075-26390-3-git-send-email-haibo.chen@nxp.com (mailing list archive)
State New, archived
Headers show
Series [01/14] mmc: sdhci: do not enable card detect interrupt for gpio cd type | expand

Commit Message

Bough Chen Nov. 15, 2019, 11:07 a.m. UTC
From: Haibo Chen <haibo.chen@nxp.com>

The default max segment size of IOMMU is 64KB, which exceed the ADMA
limitation if ADMA only support max to 65535, 64KB - 1Byte. IOMMU will
optimize the segments it received, merge the little segment into one
big segment. If we use the default IOMMU config, then ADMA will get
some segments which it's size is 64KB. Then ADMA error will shows up.

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
---
 drivers/mmc/host/sdhci.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

Comments

Adrian Hunter Nov. 26, 2019, 11:45 a.m. UTC | #1
On 15/11/19 1:07 PM, haibo.chen@nxp.com wrote:
> From: Haibo Chen <haibo.chen@nxp.com>
> 
> The default max segment size of IOMMU is 64KB, which exceed the ADMA
> limitation if ADMA only support max to 65535, 64KB - 1Byte. IOMMU will
> optimize the segments it received, merge the little segment into one
> big segment. If we use the default IOMMU config, then ADMA will get
> some segments which it's size is 64KB. Then ADMA error will shows up.
> 
> Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
> ---
>  drivers/mmc/host/sdhci.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 1436cc9c5f82..3a8093de26c7 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -3743,6 +3743,7 @@ static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
>  int sdhci_setup_host(struct sdhci_host *host)
>  {
>  	struct mmc_host *mmc;
> +	struct device *dev;
>  	u32 max_current_caps;
>  	unsigned int ocr_avail;
>  	unsigned int override_timeout_clk;
> @@ -3754,6 +3755,7 @@ int sdhci_setup_host(struct sdhci_host *host)
>  		return -EINVAL;
>  
>  	mmc = host->mmc;
> +	dev = mmc_dev(mmc);
>  
>  	/*
>  	 * If there are external regulators, get them. Note this must be done
> @@ -4224,10 +4226,20 @@ int sdhci_setup_host(struct sdhci_host *host)
>  	 * be larger than 64 KiB though.
>  	 */
>  	if (host->flags & SDHCI_USE_ADMA) {
> -		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
> +		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
>  			mmc->max_seg_size = 65535;
> -		else
> +
> +			/*
> +			 * send the ADMA limitation to IOMMU. In default,
> +			 * the max segment size of IOMMU is 64KB, this exceed
> +			 * the ADMA max segment limitation, which is 65535.
> +			 */
> +			dev->dma_parms = devm_kzalloc(dev,
> +					sizeof(*dev->dma_parms), GFP_KERNEL);
> +			dma_set_max_seg_size(dev, SZ_64K - 1);

Doesn't mmc_setup_queue() already do this?

> +		} else {
>  			mmc->max_seg_size = 65536;
> +		}
>  	} else {
>  		mmc->max_seg_size = mmc->max_req_size;
>  	}
>
Bough Chen Nov. 27, 2019, 8:25 a.m. UTC | #2
> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org <linux-mmc-owner@vger.kernel.org>
> On Behalf Of Adrian Hunter
> Sent: 2019年11月26日 19:46
> To: BOUGH CHEN <haibo.chen@nxp.com>; ulf.hansson@linaro.org
> Cc: linux-mmc@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: Re: [PATCH 03/14] mmc: sdhci: correct the DMA setting for IOMMU
> 
> On 15/11/19 1:07 PM, haibo.chen@nxp.com wrote:
> > From: Haibo Chen <haibo.chen@nxp.com>
> >
> > The default max segment size of IOMMU is 64KB, which exceed the ADMA
> > limitation if ADMA only support max to 65535, 64KB - 1Byte. IOMMU will
> > optimize the segments it received, merge the little segment into one
> > big segment. If we use the default IOMMU config, then ADMA will get
> > some segments which it's size is 64KB. Then ADMA error will shows up.
> >
> > Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
> > ---
> >  drivers/mmc/host/sdhci.c | 16 ++++++++++++++--
> >  1 file changed, 14 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index
> > 1436cc9c5f82..3a8093de26c7 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -3743,6 +3743,7 @@ static inline bool sdhci_can_64bit_dma(struct
> > sdhci_host *host)  int sdhci_setup_host(struct sdhci_host *host)  {
> >  	struct mmc_host *mmc;
> > +	struct device *dev;
> >  	u32 max_current_caps;
> >  	unsigned int ocr_avail;
> >  	unsigned int override_timeout_clk;
> > @@ -3754,6 +3755,7 @@ int sdhci_setup_host(struct sdhci_host *host)
> >  		return -EINVAL;
> >
> >  	mmc = host->mmc;
> > +	dev = mmc_dev(mmc);
> >
> >  	/*
> >  	 * If there are external regulators, get them. Note this must be
> > done @@ -4224,10 +4226,20 @@ int sdhci_setup_host(struct sdhci_host
> *host)
> >  	 * be larger than 64 KiB though.
> >  	 */
> >  	if (host->flags & SDHCI_USE_ADMA) {
> > -		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
> > +		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
> >  			mmc->max_seg_size = 65535;
> > -		else
> > +
> > +			/*
> > +			 * send the ADMA limitation to IOMMU. In default,
> > +			 * the max segment size of IOMMU is 64KB, this exceed
> > +			 * the ADMA max segment limitation, which is 65535.
> > +			 */
> > +			dev->dma_parms = devm_kzalloc(dev,
> > +					sizeof(*dev->dma_parms), GFP_KERNEL);
> > +			dma_set_max_seg_size(dev, SZ_64K - 1);
> 
> Doesn't mmc_setup_queue() already do this?

mmc_setup_queue do call the function dma_set_max_seg_size(), but it do not give value to dev->dma_parms.
So in dma_set_max_seg_size(), it do nothing, just return -EIO. 
Should I fix this in mmc_setup_queue()? 

725 static inline int dma_set_max_seg_size(struct device *dev, unsigned int size)
726 {
727         if (dev->dma_parms) {
728                 dev->dma_parms->max_segment_size = size;
729                 return 0;
730         }
731         return -EIO;
732 } 

> 
> > +		} else {
> >  			mmc->max_seg_size = 65536;
> > +		}
> >  	} else {
> >  		mmc->max_seg_size = mmc->max_req_size;
> >  	}
> >
Adrian Hunter Nov. 27, 2019, 10:10 a.m. UTC | #3
On 27/11/19 10:25 AM, BOUGH CHEN wrote:
> 
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org <linux-mmc-owner@vger.kernel.org>
>> On Behalf Of Adrian Hunter
>> Sent: 2019年11月26日 19:46
>> To: BOUGH CHEN <haibo.chen@nxp.com>; ulf.hansson@linaro.org
>> Cc: linux-mmc@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>
>> Subject: Re: [PATCH 03/14] mmc: sdhci: correct the DMA setting for IOMMU
>>
>> On 15/11/19 1:07 PM, haibo.chen@nxp.com wrote:
>>> From: Haibo Chen <haibo.chen@nxp.com>
>>>
>>> The default max segment size of IOMMU is 64KB, which exceed the ADMA
>>> limitation if ADMA only support max to 65535, 64KB - 1Byte. IOMMU will
>>> optimize the segments it received, merge the little segment into one
>>> big segment. If we use the default IOMMU config, then ADMA will get
>>> some segments which it's size is 64KB. Then ADMA error will shows up.
>>>
>>> Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
>>> ---
>>>  drivers/mmc/host/sdhci.c | 16 ++++++++++++++--
>>>  1 file changed, 14 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index
>>> 1436cc9c5f82..3a8093de26c7 100644
>>> --- a/drivers/mmc/host/sdhci.c
>>> +++ b/drivers/mmc/host/sdhci.c
>>> @@ -3743,6 +3743,7 @@ static inline bool sdhci_can_64bit_dma(struct
>>> sdhci_host *host)  int sdhci_setup_host(struct sdhci_host *host)  {
>>>  	struct mmc_host *mmc;
>>> +	struct device *dev;
>>>  	u32 max_current_caps;
>>>  	unsigned int ocr_avail;
>>>  	unsigned int override_timeout_clk;
>>> @@ -3754,6 +3755,7 @@ int sdhci_setup_host(struct sdhci_host *host)
>>>  		return -EINVAL;
>>>
>>>  	mmc = host->mmc;
>>> +	dev = mmc_dev(mmc);
>>>
>>>  	/*
>>>  	 * If there are external regulators, get them. Note this must be
>>> done @@ -4224,10 +4226,20 @@ int sdhci_setup_host(struct sdhci_host
>> *host)
>>>  	 * be larger than 64 KiB though.
>>>  	 */
>>>  	if (host->flags & SDHCI_USE_ADMA) {
>>> -		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
>>> +		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
>>>  			mmc->max_seg_size = 65535;
>>> -		else
>>> +
>>> +			/*
>>> +			 * send the ADMA limitation to IOMMU. In default,
>>> +			 * the max segment size of IOMMU is 64KB, this exceed
>>> +			 * the ADMA max segment limitation, which is 65535.
>>> +			 */
>>> +			dev->dma_parms = devm_kzalloc(dev,
>>> +					sizeof(*dev->dma_parms), GFP_KERNEL);
>>> +			dma_set_max_seg_size(dev, SZ_64K - 1);
>>
>> Doesn't mmc_setup_queue() already do this?
> 
> mmc_setup_queue do call the function dma_set_max_seg_size(), but it do not give value to dev->dma_parms.
> So in dma_set_max_seg_size(), it do nothing, just return -EIO. 
> Should I fix this in mmc_setup_queue()? 
> 
> 725 static inline int dma_set_max_seg_size(struct device *dev, unsigned int size)
> 726 {
> 727         if (dev->dma_parms) {
> 728                 dev->dma_parms->max_segment_size = size;
> 729                 return 0;
> 730         }
> 731         return -EIO;
> 732 } 

I don't know where is the best place to create dev->dma_parms.  Ask some DMA
people.

> 
>>
>>> +		} else {
>>>  			mmc->max_seg_size = 65536;
>>> +		}
>>>  	} else {
>>>  		mmc->max_seg_size = mmc->max_req_size;
>>>  	}
>>>
>
diff mbox series

Patch

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1436cc9c5f82..3a8093de26c7 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3743,6 +3743,7 @@  static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
 int sdhci_setup_host(struct sdhci_host *host)
 {
 	struct mmc_host *mmc;
+	struct device *dev;
 	u32 max_current_caps;
 	unsigned int ocr_avail;
 	unsigned int override_timeout_clk;
@@ -3754,6 +3755,7 @@  int sdhci_setup_host(struct sdhci_host *host)
 		return -EINVAL;
 
 	mmc = host->mmc;
+	dev = mmc_dev(mmc);
 
 	/*
 	 * If there are external regulators, get them. Note this must be done
@@ -4224,10 +4226,20 @@  int sdhci_setup_host(struct sdhci_host *host)
 	 * be larger than 64 KiB though.
 	 */
 	if (host->flags & SDHCI_USE_ADMA) {
-		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
+		if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
 			mmc->max_seg_size = 65535;
-		else
+
+			/*
+			 * send the ADMA limitation to IOMMU. In default,
+			 * the max segment size of IOMMU is 64KB, this exceed
+			 * the ADMA max segment limitation, which is 65535.
+			 */
+			dev->dma_parms = devm_kzalloc(dev,
+					sizeof(*dev->dma_parms), GFP_KERNEL);
+			dma_set_max_seg_size(dev, SZ_64K - 1);
+		} else {
 			mmc->max_seg_size = 65536;
+		}
 	} else {
 		mmc->max_seg_size = mmc->max_req_size;
 	}