26
26
#include "../sof-priv.h"
27
27
#include "hda.h"
28
28
29
+ static bool persistent_cl_buffer = true;
30
+ module_param (persistent_cl_buffer , bool , 0444 );
31
+ MODULE_PARM_DESC (persistent_cl_buffer , "Persistent Code Loader DMA buffer "
32
+ "(default = Y, use N to force buffer re-allocation)" );
33
+
29
34
static void hda_ssp_set_cbp_cfp (struct snd_sof_dev * sdev )
30
35
{
31
36
struct sof_intel_hda_dev * hda = sdev -> pdata -> hw_pdata ;
@@ -43,9 +48,10 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
43
48
}
44
49
}
45
50
46
- struct hdac_ext_stream * hda_cl_prepare (struct device * dev , unsigned int format ,
47
- unsigned int size , struct snd_dma_buffer * dmab ,
48
- int direction , bool is_iccmax )
51
+ struct hdac_ext_stream *
52
+ hda_cl_prepare (struct device * dev , unsigned int format , unsigned int size ,
53
+ struct snd_dma_buffer * dmab , bool persistent_buffer , int direction ,
54
+ bool is_iccmax )
49
55
{
50
56
struct snd_sof_dev * sdev = dev_get_drvdata (dev );
51
57
struct hdac_ext_stream * hext_stream ;
@@ -61,11 +67,19 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
61
67
hstream = & hext_stream -> hstream ;
62
68
hstream -> substream = NULL ;
63
69
64
- /* allocate DMA buffer */
65
- ret = snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV_SG , dev , size , dmab );
66
- if (ret < 0 ) {
67
- dev_err (sdev -> dev , "error: memory alloc failed: %d\n" , ret );
68
- goto out_put ;
70
+ /*
71
+ * Allocate DMA buffer if it is temporary or if the buffer is intended
72
+ * to be persistent but not yet allocated.
73
+ * We cannot rely solely on !dmab->area as caller might use a struct on
74
+ * stack (when it is temporary) without clearing it to 0.
75
+ */
76
+ if (!persistent_buffer || !dmab -> area ) {
77
+ ret = snd_dma_alloc_pages (SNDRV_DMA_TYPE_DEV_SG , dev , size , dmab );
78
+ if (ret < 0 ) {
79
+ dev_err (sdev -> dev , "%s: memory alloc failed: %d\n" ,
80
+ __func__ , ret );
81
+ goto out_put ;
82
+ }
69
83
}
70
84
71
85
hstream -> period_bytes = 0 ;/* initialize period_bytes */
@@ -91,6 +105,10 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
91
105
92
106
out_free :
93
107
snd_dma_free_pages (dmab );
108
+ dmab -> area = NULL ;
109
+ dmab -> bytes = 0 ;
110
+ hstream -> bufsize = 0 ;
111
+ hstream -> format_val = 0 ;
94
112
out_put :
95
113
hda_dsp_stream_put (sdev , direction , hstream -> stream_tag );
96
114
return ERR_PTR (ret );
@@ -255,7 +273,7 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
255
273
EXPORT_SYMBOL_NS (hda_cl_trigger , SND_SOC_SOF_INTEL_HDA_COMMON );
256
274
257
275
int hda_cl_cleanup (struct device * dev , struct snd_dma_buffer * dmab ,
258
- struct hdac_ext_stream * hext_stream )
276
+ bool persistent_buffer , struct hdac_ext_stream * hext_stream )
259
277
{
260
278
struct snd_sof_dev * sdev = dev_get_drvdata (dev );
261
279
struct hdac_stream * hstream = & hext_stream -> hstream ;
@@ -279,10 +297,14 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
279
297
sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU , 0 );
280
298
281
299
snd_sof_dsp_write (sdev , HDA_DSP_HDA_BAR , sd_offset , 0 );
282
- snd_dma_free_pages (dmab );
283
- dmab -> area = NULL ;
284
- hstream -> bufsize = 0 ;
285
- hstream -> format_val = 0 ;
300
+
301
+ if (!persistent_buffer ) {
302
+ snd_dma_free_pages (dmab );
303
+ dmab -> area = NULL ;
304
+ dmab -> bytes = 0 ;
305
+ hstream -> bufsize = 0 ;
306
+ hstream -> format_val = 0 ;
307
+ }
286
308
287
309
return ret ;
288
310
}
@@ -340,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
340
362
341
363
int hda_dsp_cl_boot_firmware_iccmax (struct snd_sof_dev * sdev )
342
364
{
365
+ struct sof_intel_hda_dev * hda = sdev -> pdata -> hw_pdata ;
343
366
struct hdac_ext_stream * iccmax_stream ;
344
- struct snd_dma_buffer dmab_bdl ;
345
367
int ret , ret1 ;
346
368
u8 original_gb ;
347
369
@@ -354,7 +376,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
354
376
* the data, so use a buffer of PAGE_SIZE for receiving.
355
377
*/
356
378
iccmax_stream = hda_cl_prepare (sdev -> dev , HDA_CL_STREAM_FORMAT , PAGE_SIZE ,
357
- & dmab_bdl , SNDRV_PCM_STREAM_CAPTURE , true);
379
+ & hda -> iccmax_dmab , persistent_cl_buffer ,
380
+ SNDRV_PCM_STREAM_CAPTURE , true);
358
381
if (IS_ERR (iccmax_stream )) {
359
382
dev_err (sdev -> dev , "error: dma prepare for ICCMAX stream failed\n" );
360
383
return PTR_ERR (iccmax_stream );
@@ -366,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
366
389
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
367
390
* If the cleanup also fails, we return the initial error
368
391
*/
369
- ret1 = hda_cl_cleanup (sdev -> dev , & dmab_bdl , iccmax_stream );
392
+ ret1 = hda_cl_cleanup (sdev -> dev , & hda -> iccmax_dmab ,
393
+ persistent_cl_buffer , iccmax_stream );
370
394
if (ret1 < 0 ) {
371
395
dev_err (sdev -> dev , "error: ICCMAX stream cleanup failed\n" );
372
396
@@ -408,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
408
432
const struct sof_intel_dsp_desc * chip_info ;
409
433
struct hdac_ext_stream * hext_stream ;
410
434
struct firmware stripped_firmware ;
411
- struct snd_dma_buffer dmab ;
412
435
int ret , ret1 , i ;
413
436
414
437
if (hda -> imrboot_supported && !sdev -> first_boot && !hda -> skip_imr_boot ) {
@@ -432,23 +455,31 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
432
455
return - EINVAL ;
433
456
}
434
457
435
- stripped_firmware .data = sdev -> basefw .fw -> data + sdev -> basefw .payload_offset ;
436
- stripped_firmware .size = sdev -> basefw .fw -> size - sdev -> basefw .payload_offset ;
437
-
438
458
/* init for booting wait */
439
459
init_waitqueue_head (& sdev -> boot_wait );
440
460
441
461
/* prepare DMA for code loader stream */
462
+ stripped_firmware .size = sdev -> basefw .fw -> size - sdev -> basefw .payload_offset ;
442
463
hext_stream = hda_cl_prepare (sdev -> dev , HDA_CL_STREAM_FORMAT ,
443
464
stripped_firmware .size ,
444
- & dmab , SNDRV_PCM_STREAM_PLAYBACK , false);
465
+ & hda -> cl_dmab , persistent_cl_buffer ,
466
+ SNDRV_PCM_STREAM_PLAYBACK , false);
445
467
if (IS_ERR (hext_stream )) {
446
468
dev_err (sdev -> dev , "error: dma prepare for fw loading failed\n" );
447
469
return PTR_ERR (hext_stream );
448
470
}
449
471
450
- memcpy (dmab .area , stripped_firmware .data ,
451
- stripped_firmware .size );
472
+ /*
473
+ * Copy the payload to the DMA buffer if it is temporary or if the
474
+ * buffer is persistent but it does not have the basefw payload either
475
+ * because this is the first boot and the buffer needs to be initialized,
476
+ * or a library got loaded and it replaced the basefw.
477
+ */
478
+ if (!persistent_cl_buffer || !hda -> cl_dmab_contains_basefw ) {
479
+ stripped_firmware .data = sdev -> basefw .fw -> data + sdev -> basefw .payload_offset ;
480
+ memcpy (hda -> cl_dmab .area , stripped_firmware .data , stripped_firmware .size );
481
+ hda -> cl_dmab_contains_basefw = true;
482
+ }
452
483
453
484
/* try ROM init a few times before giving up */
454
485
for (i = 0 ; i < HDA_FW_BOOT_ATTEMPTS ; i ++ ) {
@@ -514,7 +545,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
514
545
* This should be done even if firmware loading fails.
515
546
* If the cleanup also fails, we return the initial error
516
547
*/
517
- ret1 = hda_cl_cleanup (sdev -> dev , & dmab , hext_stream );
548
+ ret1 = hda_cl_cleanup (sdev -> dev , & hda -> cl_dmab ,
549
+ persistent_cl_buffer , hext_stream );
518
550
if (ret1 < 0 ) {
519
551
dev_err (sdev -> dev , "error: Code loader DSP cleanup failed\n" );
520
552
@@ -545,7 +577,6 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
545
577
struct hdac_ext_stream * hext_stream ;
546
578
struct firmware stripped_firmware ;
547
579
struct sof_ipc4_msg msg = {};
548
- struct snd_dma_buffer dmab ;
549
580
int ret , ret1 ;
550
581
551
582
/* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */
@@ -556,16 +587,28 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
556
587
stripped_firmware .data = fw_lib -> sof_fw .fw -> data + fw_lib -> sof_fw .payload_offset ;
557
588
stripped_firmware .size = fw_lib -> sof_fw .fw -> size - fw_lib -> sof_fw .payload_offset ;
558
589
590
+ /*
591
+ * force re-allocation of the cl_dmab if the preserved DMA buffer is
592
+ * smaller than what is needed for the library
593
+ */
594
+ if (persistent_cl_buffer && stripped_firmware .size > hda -> cl_dmab .bytes ) {
595
+ snd_dma_free_pages (& hda -> cl_dmab );
596
+ hda -> cl_dmab .area = NULL ;
597
+ hda -> cl_dmab .bytes = 0 ;
598
+ }
599
+
559
600
/* prepare DMA for code loader stream */
560
601
hext_stream = hda_cl_prepare (sdev -> dev , HDA_CL_STREAM_FORMAT ,
561
602
stripped_firmware .size ,
562
- & dmab , SNDRV_PCM_STREAM_PLAYBACK , false);
603
+ & hda -> cl_dmab , persistent_cl_buffer ,
604
+ SNDRV_PCM_STREAM_PLAYBACK , false);
563
605
if (IS_ERR (hext_stream )) {
564
606
dev_err (sdev -> dev , "%s: DMA prepare failed\n" , __func__ );
565
607
return PTR_ERR (hext_stream );
566
608
}
567
609
568
- memcpy (dmab .area , stripped_firmware .data , stripped_firmware .size );
610
+ memcpy (hda -> cl_dmab .area , stripped_firmware .data , stripped_firmware .size );
611
+ hda -> cl_dmab_contains_basefw = false;
569
612
570
613
/*
571
614
* 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE
@@ -628,7 +671,8 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
628
671
629
672
cleanup :
630
673
/* clean up even in case of error and return the first error */
631
- ret1 = hda_cl_cleanup (sdev -> dev , & dmab , hext_stream );
674
+ ret1 = hda_cl_cleanup (sdev -> dev , & hda -> cl_dmab , persistent_cl_buffer ,
675
+ hext_stream );
632
676
if (ret1 < 0 ) {
633
677
dev_err (sdev -> dev , "%s: Code loader DSP cleanup failed\n" , __func__ );
634
678
0 commit comments