diff mbox series

[1/2] firmware: cs_dsp: Remove async regmap writes

Message ID 20250225131843.113752-2-rf@opensource.cirrus.com (mailing list archive)
State Accepted
Commit fe08b7d5085a9774abc30c26d5aebc5b9cdd6091
Headers show
Series ALSA: cs35l56: Fix for races when soft-resetting on SPI | expand

Commit Message

Richard Fitzgerald Feb. 25, 2025, 1:18 p.m. UTC
Change calls to async regmap write functions to use the normal
blocking writes so that the cs35l56 driver can use spi_bus_lock() to
gain exclusive access to the SPI bus.

As this is part of a fix, it makes only the minimal change to swap the
functions to the blocking equivalents. There's no need to risk
reworking the buffer allocation logic that is now partially redundant.

The async writes are a 12-year-old workaround for inefficiency of
synchronous writes in the SPI subsystem. The SPI subsystem has since
been changed to avoid the overheads, so this workaround should not be
necessary.

The cs35l56 driver needs to use spi_bus_lock() prevent bus activity
while it is soft-resetting the cs35l56. But spi_bus_lock() is
incompatible with spi_async() calls, which will fail with -EBUSY.

Fixes: 8a731fd37f8b ("ASoC: cs35l56: Move utility functions to shared file")
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
 drivers/firmware/cirrus/cs_dsp.c | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

Comments

Mark Brown Feb. 25, 2025, 3:15 p.m. UTC | #1
On Tue, Feb 25, 2025 at 01:18:42PM +0000, Richard Fitzgerald wrote:

> The async writes are a 12-year-old workaround for inefficiency of
> synchronous writes in the SPI subsystem. The SPI subsystem has since
> been changed to avoid the overheads, so this workaround should not be
> necessary.

That wasn't really the issue, it was that on systems with low numbers of
slower cores (especially single core but there were some dual core
systems too) there was a surprisingly low threashold where it was useful
to overlap the marshalling of data to send to the device with
transmitting already marshalled data.  SMP adds locking requirements
which loose a lot of the gains, and it's controller dependent where the
cuttoff points for interrupts and/or DMA are.
Richard Fitzgerald Feb. 25, 2025, 4:22 p.m. UTC | #2
On 25/02/2025 3:15 pm, Mark Brown wrote:
> On Tue, Feb 25, 2025 at 01:18:42PM +0000, Richard Fitzgerald wrote:
> 
>> The async writes are a 12-year-old workaround for inefficiency of
>> synchronous writes in the SPI subsystem. The SPI subsystem has since
>> been changed to avoid the overheads, so this workaround should not be
>> necessary.
> 
> That wasn't really the issue, it was that on systems with low numbers of
> slower cores (especially single core but there were some dual core
> systems too) there was a surprisingly low threashold where it was useful
> to overlap the marshalling of data to send to the device with
> transmitting already marshalled data.  SMP adds locking requirements
> which loose a lot of the gains, and it's controller dependent where the
> cuttoff points for interrupts and/or DMA are.

Ok. It was a very long time ago.
Do you want a V2 with a commit message that doesn't libel the SPI
framework?

FWIW switching to sync write reduced the download of small amp firmware
by 200ms on a 1.67MHz SPI bus.
Mark Brown Feb. 25, 2025, 4:37 p.m. UTC | #3
On Tue, Feb 25, 2025 at 04:22:49PM +0000, Richard Fitzgerald wrote:

> Ok. It was a very long time ago.
> Do you want a V2 with a commit message that doesn't libel the SPI
> framework?

No, it's fine - it's in CI already.

> FWIW switching to sync write reduced the download of small amp firmware
> by 200ms on a 1.67MHz SPI bus.

Yeah, with modern multi-core systems that's unsurprising especially
with a controller that does small writes synchronously - the cost of
locking on modern CPUs tends to blow out the overlapping of the
formatting with the I/O.  It's part of why maple tree caches don't do
async writes during sync.
diff mbox series

Patch

diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index 5365e9a43000..42433c19eb30 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -1609,8 +1609,8 @@  static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 				goto out_fw;
 			}
 
-			ret = regmap_raw_write_async(regmap, reg, buf->buf,
-						     le32_to_cpu(region->len));
+			ret = regmap_raw_write(regmap, reg, buf->buf,
+					       le32_to_cpu(region->len));
 			if (ret != 0) {
 				cs_dsp_err(dsp,
 					   "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
@@ -1625,12 +1625,6 @@  static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 		regions++;
 	}
 
-	ret = regmap_async_complete(regmap);
-	if (ret != 0) {
-		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
-		goto out_fw;
-	}
-
 	if (pos > firmware->size)
 		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
 			    file, regions, pos - firmware->size);
@@ -1638,7 +1632,6 @@  static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
 	cs_dsp_debugfs_save_wmfwname(dsp, file);
 
 out_fw:
-	regmap_async_complete(regmap);
 	cs_dsp_buf_free(&buf_list);
 
 	if (ret == -EOVERFLOW)
@@ -2326,8 +2319,8 @@  static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 			cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
 				   file, blocks, le32_to_cpu(blk->len),
 				   reg);
-			ret = regmap_raw_write_async(regmap, reg, buf->buf,
-						     le32_to_cpu(blk->len));
+			ret = regmap_raw_write(regmap, reg, buf->buf,
+					       le32_to_cpu(blk->len));
 			if (ret != 0) {
 				cs_dsp_err(dsp,
 					   "%s.%d: Failed to write to %x in %s: %d\n",
@@ -2339,10 +2332,6 @@  static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 		blocks++;
 	}
 
-	ret = regmap_async_complete(regmap);
-	if (ret != 0)
-		cs_dsp_err(dsp, "Failed to complete async write: %d\n", ret);
-
 	if (pos > firmware->size)
 		cs_dsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
 			    file, blocks, pos - firmware->size);
@@ -2350,7 +2339,6 @@  static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
 	cs_dsp_debugfs_save_binname(dsp, file);
 
 out_fw:
-	regmap_async_complete(regmap);
 	cs_dsp_buf_free(&buf_list);
 
 	if (ret == -EOVERFLOW)
@@ -2561,8 +2549,8 @@  static int cs_dsp_adsp2_enable_core(struct cs_dsp *dsp)
 {
 	int ret;
 
-	ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
-				       ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+	ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+				 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
 	if (ret != 0)
 		return ret;