Linux-mmc Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v4] mmc: mmci: Support odd block sizes for ux500v2 and qcom variant
@ 2019-12-02 22:28 Linus Walleij
  2019-12-11  8:47 ` Ulf Hansson
  0 siblings, 1 reply; 3+ messages in thread
From: Linus Walleij @ 2019-12-02 22:28 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson
  Cc: Linus Walleij, Ludovic Barre, Brian Masney, Stephan Gerhold,
	Niklas Cassel, Russell King, Srinivas Kandagatla

For the ux500v2 variant of the PL18x block, odd block sizes
are supported. This is necessary to support some SDIO
transfers. This also affects the QCOM MMCI variant and the
ST micro variant.

For Ux500 an additional quirk only allowing DMA on blocks
that are a power of two is needed. This might be a bug in
the DMA engine (DMA40) or the MMCI or in the interconnect,
but the most likely is the MMCI, as transfers of these
sizes work fine for other devices using the same DMA
engine. DMA works fine also with SDIO as long as the
blocksize is a power of 2.

This patch has proven necessary for enabling SDIO for WLAN on
PostmarketOS-based Ux500 platforms.

What we managed to test in practice is Broadcom WiFi over
SDIO on the Ux500 based Samsung GT-I8190 and GT-S7710.
This WiFi chip, BCM4334 works fine after the patch.

Before this patch:

brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4334-sdio
	  for chip BCM4334/3
mmci-pl18x 80118000.sdi1_per2: unsupported block size (60 bytes)
brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
brcmfmac: brcmf_sdio_download_code_file: error -22 on writing
	  434236 membytes at 0x00000000
brcmfmac: brcmf_sdio_download_firmware: dongle image file download
	  failed

After this patch:

brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4334/3 wl0:
	  Nov 21 2012 00:21:28 version 6.10.58.813 (B2) FWID 01-0

Bringing up networks, discovering networks with "iw dev wlan0 scan"
and connecting works fine from this point.

This patch is inspired by Ulf Hansson's patch
http://www.spinics.net/lists/linux-mmc/msg12160.html

As the DMA engines on these platforms may now get block sizes
they were not used to before, make sure to also respect if
the DMA engine says "no" to a transfer.

Make a drive-by fix for datactrl_blocksz, misspelled.

Cc: Ludovic Barre <ludovic.barre@st.com>
Cc: Brian Masney <masneyb@onstation.org>
Cc: Stephan Gerhold <stephan@gerhold.net>
Cc: Niklas Cassel <niklas.cassel@linaro.org>
Cc: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v3->v4:
- Rewrite the patch to accept odd packages but only
  let power of two packages pass on to the DMA.
- Drop the patches disallowing DMA not divisible by 4:
  this doesn't work. Instead just push the whole
  power of two criteria down to the DMA submission
  phase.
- Drop the patch handling odd sglist offsets and
  passing of page boundaries in SG buffers when
  using PIO: it just doesn't happen in practice, we
  don't know why, but likely because all packets are
  small.
ChangeLog v2->v3:
- Repost with the inclusion of other patches.
ChangeLog v1->v2:
- Specify odd blocksize field to 1 bit (:1)
- Specify that STMMC supports odd block sizes
- Collect Stephan's test tag
---
 drivers/mmc/host/mmci.c | 34 ++++++++++++++++++++++++++++++----
 drivers/mmc/host/mmci.h |  8 +++++++-
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index c37e70dbe250..5afe9145f957 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -168,6 +168,8 @@ static struct variant_data variant_ux500 = {
 	.cmdreg_srsp		= MCI_CPSM_RESPONSE,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_odd_blocksz	= true,
+	.only_pow_2_dma		= true,
 	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
@@ -201,6 +203,8 @@ static struct variant_data variant_ux500v2 = {
 	.datactrl_mask_ddrmode	= MCI_DPSM_ST_DDRMODE,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_odd_blocksz	= true,
+	.only_pow_2_dma		= true,
 	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
@@ -260,6 +264,7 @@ static struct variant_data variant_stm32_sdmmc = {
 	.datacnt_useless	= true,
 	.datalength_bits	= 25,
 	.datactrl_blocksz	= 14,
+	.datactrl_odd_blocksz	= true,
 	.stm32_idmabsize_mask	= GENMASK(12, 5),
 	.init			= sdmmc_variant_init,
 };
@@ -279,6 +284,7 @@ static struct variant_data variant_qcom = {
 	.data_cmd_enable	= MCI_CPSM_QCOM_DATCMD,
 	.datalength_bits	= 24,
 	.datactrl_blocksz	= 11,
+	.datactrl_odd_blocksz	= true,
 	.pwrreg_powerup		= MCI_PWR_UP,
 	.f_max			= 208000000,
 	.explicit_mclk_control	= true,
@@ -447,10 +453,11 @@ void mmci_dma_setup(struct mmci_host *host)
 static int mmci_validate_data(struct mmci_host *host,
 			      struct mmc_data *data)
 {
+	struct variant_data *variant = host->variant;
+
 	if (!data)
 		return 0;
-
-	if (!is_power_of_2(data->blksz)) {
+	if (!is_power_of_2(data->blksz) && !variant->datactrl_odd_blocksz) {
 		dev_err(mmc_dev(host->mmc),
 			"unsupported block size (%d bytes)\n", data->blksz);
 		return -EINVAL;
@@ -515,7 +522,9 @@ int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)
 		 "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
 		 data->sg_len, data->blksz, data->blocks, data->flags);
 
-	host->ops->dma_start(host, &datactrl);
+	ret = host->ops->dma_start(host, &datactrl);
+	if (ret)
+		return ret;
 
 	/* Trigger the DMA transfer */
 	mmci_write_datactrlreg(host, datactrl);
@@ -822,6 +831,18 @@ static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,
 	if (data->blksz * data->blocks <= variant->fifosize)
 		return -EINVAL;
 
+	/*
+	 * This is necessary to get SDIO working on the Ux500. We do not yet
+	 * know if this is a bug in:
+	 * - The Ux500 DMA controller (DMA40)
+	 * - The MMCI DMA interface on the Ux500
+	 * some power of two blocks (such as 64 bytes) are sent regularly
+	 * during SDIO traffic and those work fine so for these we enable DMA
+	 * transfers.
+	 */
+	if (host->variant->only_pow_2_dma && !is_power_of_2(data->blksz))
+		return -EINVAL;
+
 	device = chan->device;
 	nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
 			   mmc_get_dma_dir(data));
@@ -872,9 +893,14 @@ int mmci_dmae_prep_data(struct mmci_host *host,
 int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl)
 {
 	struct mmci_dmae_priv *dmae = host->dma_priv;
+	int ret;
 
 	host->dma_in_progress = true;
-	dmaengine_submit(dmae->desc_current);
+	ret = dma_submit_error(dmaengine_submit(dmae->desc_current));
+	if (ret < 0) {
+		host->dma_in_progress = false;
+		return ret;
+	}
 	dma_async_issue_pending(dmae->cur);
 
 	*datactrl |= MCI_DPSM_DMAENABLE;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 833236ecb31e..37d02f147b4f 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -278,7 +278,11 @@ struct mmci_host;
  * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
  * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
  * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @datactrl_blksz: block size in power of two
+ * @datactrl_blocksz: block size in power of two
+ * @datactrl_odd_blocksz: true if block any block sizes are accepted by
+ *		  hardware, such as with some SDIO traffic that send
+ *		  odd packets.
+ * @only_pow_2_dma: DMA only works with blocks that are a power of 2.
  * @datactrl_first: true if data must be setup before send command
  * @datacnt_useless: true if you could not use datacnt register to read
  *		     remaining data
@@ -323,6 +327,8 @@ struct variant_data {
 	unsigned int		datactrl_mask_ddrmode;
 	unsigned int		datactrl_mask_sdio;
 	unsigned int		datactrl_blocksz;
+	u8			datactrl_odd_blocksz:1;
+	u8			only_pow_2_dma:1;
 	u8			datactrl_first:1;
 	u8			datacnt_useless:1;
 	u8			st_sdio:1;
-- 
2.21.0


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

* Re: [PATCH v4] mmc: mmci: Support odd block sizes for ux500v2 and qcom variant
  2019-12-02 22:28 [PATCH v4] mmc: mmci: Support odd block sizes for ux500v2 and qcom variant Linus Walleij
@ 2019-12-11  8:47 ` Ulf Hansson
  2019-12-11  8:48   ` Ulf Hansson
  0 siblings, 1 reply; 3+ messages in thread
From: Ulf Hansson @ 2019-12-11  8:47 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-mmc, Ludovic Barre, Brian Masney, Stephan Gerhold,
	Niklas Cassel, Russell King, Srinivas Kandagatla

On Mon, 2 Dec 2019 at 23:28, Linus Walleij <linus.walleij@linaro.org> wrote:
>
> For the ux500v2 variant of the PL18x block, odd block sizes
> are supported. This is necessary to support some SDIO
> transfers. This also affects the QCOM MMCI variant and the
> ST micro variant.
>
> For Ux500 an additional quirk only allowing DMA on blocks
> that are a power of two is needed. This might be a bug in
> the DMA engine (DMA40) or the MMCI or in the interconnect,
> but the most likely is the MMCI, as transfers of these
> sizes work fine for other devices using the same DMA
> engine. DMA works fine also with SDIO as long as the
> blocksize is a power of 2.
>
> This patch has proven necessary for enabling SDIO for WLAN on
> PostmarketOS-based Ux500 platforms.
>
> What we managed to test in practice is Broadcom WiFi over
> SDIO on the Ux500 based Samsung GT-I8190 and GT-S7710.
> This WiFi chip, BCM4334 works fine after the patch.
>
> Before this patch:
>
> brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4334-sdio
>           for chip BCM4334/3
> mmci-pl18x 80118000.sdi1_per2: unsupported block size (60 bytes)
> brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
> brcmfmac: brcmf_sdio_download_code_file: error -22 on writing
>           434236 membytes at 0x00000000
> brcmfmac: brcmf_sdio_download_firmware: dongle image file download
>           failed
>
> After this patch:
>
> brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4334/3 wl0:
>           Nov 21 2012 00:21:28 version 6.10.58.813 (B2) FWID 01-0
>
> Bringing up networks, discovering networks with "iw dev wlan0 scan"
> and connecting works fine from this point.
>
> This patch is inspired by Ulf Hansson's patch
> http://www.spinics.net/lists/linux-mmc/msg12160.html
>
> As the DMA engines on these platforms may now get block sizes
> they were not used to before, make sure to also respect if
> the DMA engine says "no" to a transfer.
>
> Make a drive-by fix for datactrl_blocksz, misspelled.

Alright, I think this approach makes sense.

Especially, trying to make some changes in mmci_pio_read|write() that
we can trigger/test doesn't make sense.

A few nitpicks below.

>
> Cc: Ludovic Barre <ludovic.barre@st.com>
> Cc: Brian Masney <masneyb@onstation.org>
> Cc: Stephan Gerhold <stephan@gerhold.net>
> Cc: Niklas Cassel <niklas.cassel@linaro.org>
> Cc: Russell King <rmk+kernel@armlinux.org.uk>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ChangeLog v3->v4:
> - Rewrite the patch to accept odd packages but only
>   let power of two packages pass on to the DMA.
> - Drop the patches disallowing DMA not divisible by 4:
>   this doesn't work. Instead just push the whole
>   power of two criteria down to the DMA submission
>   phase.
> - Drop the patch handling odd sglist offsets and
>   passing of page boundaries in SG buffers when
>   using PIO: it just doesn't happen in practice, we
>   don't know why, but likely because all packets are
>   small.
> ChangeLog v2->v3:
> - Repost with the inclusion of other patches.
> ChangeLog v1->v2:
> - Specify odd blocksize field to 1 bit (:1)
> - Specify that STMMC supports odd block sizes
> - Collect Stephan's test tag
> ---

[...]

> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
> index 833236ecb31e..37d02f147b4f 100644
> --- a/drivers/mmc/host/mmci.h
> +++ b/drivers/mmc/host/mmci.h
> @@ -278,7 +278,11 @@ struct mmci_host;
>   * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
>   * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
>   * @datactrl_mask_sdio: SDIO enable mask in datactrl register
> - * @datactrl_blksz: block size in power of two
> + * @datactrl_blocksz: block size in power of two
> + * @datactrl_odd_blocksz: true if block any block sizes are accepted by
> + *               hardware, such as with some SDIO traffic that send
> + *               odd packets.
> + * @only_pow_2_dma: DMA only works with blocks that are a power of 2.
>   * @datactrl_first: true if data must be setup before send command
>   * @datacnt_useless: true if you could not use datacnt register to read
>   *                  remaining data
> @@ -323,6 +327,8 @@ struct variant_data {
>         unsigned int            datactrl_mask_ddrmode;
>         unsigned int            datactrl_mask_sdio;
>         unsigned int            datactrl_blocksz;
> +       u8                      datactrl_odd_blocksz:1;

How about renaming this to datactrl_any_blocksz? As I think that
better explains its purpose.

> +       u8                      only_pow_2_dma:1;

and rename this to dma_power_of_2

>         u8                      datactrl_first:1;
>         u8                      datacnt_useless:1;
>         u8                      st_sdio:1;
> --
> 2.21.0
>

Kind regards
Uffe

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

* Re: [PATCH v4] mmc: mmci: Support odd block sizes for ux500v2 and qcom variant
  2019-12-11  8:47 ` Ulf Hansson
@ 2019-12-11  8:48   ` Ulf Hansson
  0 siblings, 0 replies; 3+ messages in thread
From: Ulf Hansson @ 2019-12-11  8:48 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-mmc, Ludovic Barre, Brian Masney, Stephan Gerhold,
	Niklas Cassel, Russell King, Srinivas Kandagatla

On Wed, 11 Dec 2019 at 09:47, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> On Mon, 2 Dec 2019 at 23:28, Linus Walleij <linus.walleij@linaro.org> wrote:
> >
> > For the ux500v2 variant of the PL18x block, odd block sizes
> > are supported. This is necessary to support some SDIO
> > transfers. This also affects the QCOM MMCI variant and the
> > ST micro variant.
> >
> > For Ux500 an additional quirk only allowing DMA on blocks
> > that are a power of two is needed. This might be a bug in
> > the DMA engine (DMA40) or the MMCI or in the interconnect,
> > but the most likely is the MMCI, as transfers of these
> > sizes work fine for other devices using the same DMA
> > engine. DMA works fine also with SDIO as long as the
> > blocksize is a power of 2.
> >
> > This patch has proven necessary for enabling SDIO for WLAN on
> > PostmarketOS-based Ux500 platforms.
> >
> > What we managed to test in practice is Broadcom WiFi over
> > SDIO on the Ux500 based Samsung GT-I8190 and GT-S7710.
> > This WiFi chip, BCM4334 works fine after the patch.
> >
> > Before this patch:
> >
> > brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4334-sdio
> >           for chip BCM4334/3
> > mmci-pl18x 80118000.sdi1_per2: unsupported block size (60 bytes)
> > brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
> > brcmfmac: brcmf_sdio_download_code_file: error -22 on writing
> >           434236 membytes at 0x00000000
> > brcmfmac: brcmf_sdio_download_firmware: dongle image file download
> >           failed
> >
> > After this patch:
> >
> > brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4334/3 wl0:
> >           Nov 21 2012 00:21:28 version 6.10.58.813 (B2) FWID 01-0
> >
> > Bringing up networks, discovering networks with "iw dev wlan0 scan"
> > and connecting works fine from this point.
> >
> > This patch is inspired by Ulf Hansson's patch
> > http://www.spinics.net/lists/linux-mmc/msg12160.html
> >
> > As the DMA engines on these platforms may now get block sizes
> > they were not used to before, make sure to also respect if
> > the DMA engine says "no" to a transfer.
> >
> > Make a drive-by fix for datactrl_blocksz, misspelled.
>
> Alright, I think this approach makes sense.
>
> Especially, trying to make some changes in mmci_pio_read|write() that
> we can trigger/test doesn't make sense.

/s/can/can't

[...]

Kind regards
Uffe

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

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-02 22:28 [PATCH v4] mmc: mmci: Support odd block sizes for ux500v2 and qcom variant Linus Walleij
2019-12-11  8:47 ` Ulf Hansson
2019-12-11  8:48   ` Ulf Hansson

Linux-mmc Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-mmc/0 linux-mmc/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-mmc linux-mmc/ https://lore.kernel.org/linux-mmc \
		linux-mmc@vger.kernel.org
	public-inbox-index linux-mmc

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-mmc


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git