Skip to content

Commit 900baa6

Browse files
rfvirgilbroonie
authored andcommitted
firmware: cs_dsp: Remove redundant download buffer allocator
Now that cs_dsp uses regmap_raw_write() instead of regmap_raw_write_async() it doesn't need to keep multiple DMA-safe buffers of every chunk of data it wrote. See commit fe08b7d ("firmware: cs_dsp: Remove async regmap writes") Only one write can be in progress at a time, so one DMA-safe buffer can be re-used. The single DMA-safe buffer is reallocated if the next write chunk is larger. Reallocation size is rounded up to reduce the amount of churn. PAGE_SIZE is used as a convenient size multiple. Typically for .wmfw files the first chunk is the largest. A DMA-safe intermediate buffer is used because we can't assume that the bus underlying regmap can accept non-DMA-safe buffers. Note that a chunk from the firmware file cannot simply be split into arbitrarily-sized chunks to avoid buffer reallocation. The data in the firmware file is preformatted to be written directly to the device as one block. It already takes account of alignment, write-bursts and write length requirements of the target hardware, so that the cs_dsp driver can treat it as an opaque blob. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Link: https://patch.msgid.link/20251126131501.884188-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent bcf016a commit 900baa6

1 file changed

Lines changed: 34 additions & 69 deletions

File tree

drivers/firmware/cirrus/cs_dsp.c

Lines changed: 34 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/ctype.h>
1414
#include <linux/debugfs.h>
1515
#include <linux/delay.h>
16+
#include <linux/math.h>
1617
#include <linux/minmax.h>
1718
#include <linux/module.h>
1819
#include <linux/moduleparam.h>
@@ -317,44 +318,6 @@ struct cs_dsp_alg_region_list_item {
317318
struct cs_dsp_alg_region alg_region;
318319
};
319320

320-
struct cs_dsp_buf {
321-
struct list_head list;
322-
void *buf;
323-
};
324-
325-
static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
326-
struct list_head *list)
327-
{
328-
struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
329-
330-
if (buf == NULL)
331-
return NULL;
332-
333-
buf->buf = vmalloc(len);
334-
if (!buf->buf) {
335-
kfree(buf);
336-
return NULL;
337-
}
338-
memcpy(buf->buf, src, len);
339-
340-
if (list)
341-
list_add_tail(&buf->list, list);
342-
343-
return buf;
344-
}
345-
346-
static void cs_dsp_buf_free(struct list_head *list)
347-
{
348-
while (!list_empty(list)) {
349-
struct cs_dsp_buf *buf = list_first_entry(list,
350-
struct cs_dsp_buf,
351-
list);
352-
list_del(&buf->list);
353-
vfree(buf->buf);
354-
kfree(buf);
355-
}
356-
}
357-
358321
/**
359322
* cs_dsp_mem_region_name() - Return a name string for a memory type
360323
* @type: the memory type to match
@@ -1481,7 +1444,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
14811444
const struct wmfw_region *region;
14821445
const struct cs_dsp_region *mem;
14831446
const char *region_name;
1484-
struct cs_dsp_buf *buf;
1447+
u8 *buf __free(kfree) = NULL;
1448+
size_t buf_len = 0;
1449+
size_t region_len;
14851450
unsigned int reg;
14861451
int regions = 0;
14871452
int ret, offset, type;
@@ -1601,23 +1566,23 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
16011566
region_name);
16021567

16031568
if (reg) {
1604-
buf = cs_dsp_buf_alloc(region->data,
1605-
le32_to_cpu(region->len),
1606-
&buf_list);
1607-
if (!buf) {
1608-
cs_dsp_err(dsp, "Out of memory\n");
1609-
ret = -ENOMEM;
1610-
goto out_fw;
1569+
region_len = le32_to_cpu(region->len);
1570+
if (region_len > buf_len) {
1571+
buf_len = round_up(region_len, PAGE_SIZE);
1572+
kfree(buf);
1573+
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
1574+
if (!buf) {
1575+
ret = -ENOMEM;
1576+
goto out_fw;
1577+
}
16111578
}
16121579

1613-
ret = regmap_raw_write(regmap, reg, buf->buf,
1614-
le32_to_cpu(region->len));
1580+
memcpy(buf, region->data, region_len);
1581+
ret = regmap_raw_write(regmap, reg, buf, region_len);
16151582
if (ret != 0) {
16161583
cs_dsp_err(dsp,
1617-
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1618-
file, regions,
1619-
le32_to_cpu(region->len), offset,
1620-
region_name, ret);
1584+
"%s.%d: Failed to write %zu bytes at %d in %s: %d\n",
1585+
file, regions, region_len, offset, region_name, ret);
16211586
goto out_fw;
16221587
}
16231588
}
@@ -1634,8 +1599,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
16341599

16351600
ret = 0;
16361601
out_fw:
1637-
cs_dsp_buf_free(&buf_list);
1638-
16391602
if (ret == -EOVERFLOW)
16401603
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
16411604

@@ -2167,7 +2130,9 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
21672130
struct cs_dsp_alg_region *alg_region;
21682131
const char *region_name;
21692132
int ret, pos, blocks, type, offset, reg, version;
2170-
struct cs_dsp_buf *buf;
2133+
u8 *buf __free(kfree) = NULL;
2134+
size_t buf_len = 0;
2135+
size_t region_len;
21712136

21722137
if (!firmware)
21732138
return 0;
@@ -2309,20 +2274,22 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
23092274
}
23102275

23112276
if (reg) {
2312-
buf = cs_dsp_buf_alloc(blk->data,
2313-
le32_to_cpu(blk->len),
2314-
&buf_list);
2315-
if (!buf) {
2316-
cs_dsp_err(dsp, "Out of memory\n");
2317-
ret = -ENOMEM;
2318-
goto out_fw;
2277+
region_len = le32_to_cpu(blk->len);
2278+
if (region_len > buf_len) {
2279+
buf_len = round_up(region_len, PAGE_SIZE);
2280+
kfree(buf);
2281+
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
2282+
if (!buf) {
2283+
ret = -ENOMEM;
2284+
goto out_fw;
2285+
}
23192286
}
23202287

2321-
cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
2322-
file, blocks, le32_to_cpu(blk->len),
2323-
reg);
2324-
ret = regmap_raw_write(regmap, reg, buf->buf,
2325-
le32_to_cpu(blk->len));
2288+
memcpy(buf, blk->data, region_len);
2289+
2290+
cs_dsp_dbg(dsp, "%s.%d: Writing %zu bytes at %x\n",
2291+
file, blocks, region_len, reg);
2292+
ret = regmap_raw_write(regmap, reg, buf, region_len);
23262293
if (ret != 0) {
23272294
cs_dsp_err(dsp,
23282295
"%s.%d: Failed to write to %x in %s: %d\n",
@@ -2342,8 +2309,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
23422309

23432310
ret = 0;
23442311
out_fw:
2345-
cs_dsp_buf_free(&buf_list);
2346-
23472312
if (ret == -EOVERFLOW)
23482313
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
23492314

0 commit comments

Comments
 (0)