2626#include "../sof-priv.h"
2727#include "hda.h"
2828
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+
2934static void hda_ssp_set_cbp_cfp (struct snd_sof_dev * sdev )
3035{
3136 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)
4348 }
4449}
4550
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 )
4955{
5056 struct snd_sof_dev * sdev = dev_get_drvdata (dev );
5157 struct hdac_ext_stream * hext_stream ;
@@ -61,11 +67,19 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
6167 hstream = & hext_stream -> hstream ;
6268 hstream -> substream = NULL ;
6369
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+ }
6983 }
7084
7185 hstream -> period_bytes = 0 ;/* initialize period_bytes */
@@ -91,6 +105,10 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
91105
92106out_free :
93107 snd_dma_free_pages (dmab );
108+ dmab -> area = NULL ;
109+ dmab -> bytes = 0 ;
110+ hstream -> bufsize = 0 ;
111+ hstream -> format_val = 0 ;
94112out_put :
95113 hda_dsp_stream_put (sdev , direction , hstream -> stream_tag );
96114 return ERR_PTR (ret );
@@ -255,7 +273,7 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
255273EXPORT_SYMBOL_NS (hda_cl_trigger , SND_SOC_SOF_INTEL_HDA_COMMON );
256274
257275int 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 )
259277{
260278 struct snd_sof_dev * sdev = dev_get_drvdata (dev );
261279 struct hdac_stream * hstream = & hext_stream -> hstream ;
@@ -279,10 +297,14 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
279297 sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU , 0 );
280298
281299 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+ }
286308
287309 return ret ;
288310}
@@ -340,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
340362
341363int hda_dsp_cl_boot_firmware_iccmax (struct snd_sof_dev * sdev )
342364{
365+ struct sof_intel_hda_dev * hda = sdev -> pdata -> hw_pdata ;
343366 struct hdac_ext_stream * iccmax_stream ;
344- struct snd_dma_buffer dmab_bdl ;
345367 int ret , ret1 ;
346368 u8 original_gb ;
347369
@@ -354,7 +376,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
354376 * the data, so use a buffer of PAGE_SIZE for receiving.
355377 */
356378 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);
358381 if (IS_ERR (iccmax_stream )) {
359382 dev_err (sdev -> dev , "error: dma prepare for ICCMAX stream failed\n" );
360383 return PTR_ERR (iccmax_stream );
@@ -366,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
366389 * Perform iccmax stream cleanup. This should be done even if firmware loading fails.
367390 * If the cleanup also fails, we return the initial error
368391 */
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 );
370394 if (ret1 < 0 ) {
371395 dev_err (sdev -> dev , "error: ICCMAX stream cleanup failed\n" );
372396
@@ -408,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
408432 const struct sof_intel_dsp_desc * chip_info ;
409433 struct hdac_ext_stream * hext_stream ;
410434 struct firmware stripped_firmware ;
411- struct snd_dma_buffer dmab ;
412435 int ret , ret1 , i ;
413436
414437 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)
432455 return - EINVAL ;
433456 }
434457
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-
438458 /* init for booting wait */
439459 init_waitqueue_head (& sdev -> boot_wait );
440460
441461 /* prepare DMA for code loader stream */
462+ stripped_firmware .size = sdev -> basefw .fw -> size - sdev -> basefw .payload_offset ;
442463 hext_stream = hda_cl_prepare (sdev -> dev , HDA_CL_STREAM_FORMAT ,
443464 stripped_firmware .size ,
444- & dmab , SNDRV_PCM_STREAM_PLAYBACK , false);
465+ & hda -> cl_dmab , persistent_cl_buffer ,
466+ SNDRV_PCM_STREAM_PLAYBACK , false);
445467 if (IS_ERR (hext_stream )) {
446468 dev_err (sdev -> dev , "error: dma prepare for fw loading failed\n" );
447469 return PTR_ERR (hext_stream );
448470 }
449471
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+ }
452483
453484 /* try ROM init a few times before giving up */
454485 for (i = 0 ; i < HDA_FW_BOOT_ATTEMPTS ; i ++ ) {
@@ -514,7 +545,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
514545 * This should be done even if firmware loading fails.
515546 * If the cleanup also fails, we return the initial error
516547 */
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 );
518550 if (ret1 < 0 ) {
519551 dev_err (sdev -> dev , "error: Code loader DSP cleanup failed\n" );
520552
@@ -545,7 +577,6 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
545577 struct hdac_ext_stream * hext_stream ;
546578 struct firmware stripped_firmware ;
547579 struct sof_ipc4_msg msg = {};
548- struct snd_dma_buffer dmab ;
549580 int ret , ret1 ;
550581
551582 /* 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,
556587 stripped_firmware .data = fw_lib -> sof_fw .fw -> data + fw_lib -> sof_fw .payload_offset ;
557588 stripped_firmware .size = fw_lib -> sof_fw .fw -> size - fw_lib -> sof_fw .payload_offset ;
558589
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+
559600 /* prepare DMA for code loader stream */
560601 hext_stream = hda_cl_prepare (sdev -> dev , HDA_CL_STREAM_FORMAT ,
561602 stripped_firmware .size ,
562- & dmab , SNDRV_PCM_STREAM_PLAYBACK , false);
603+ & hda -> cl_dmab , persistent_cl_buffer ,
604+ SNDRV_PCM_STREAM_PLAYBACK , false);
563605 if (IS_ERR (hext_stream )) {
564606 dev_err (sdev -> dev , "%s: DMA prepare failed\n" , __func__ );
565607 return PTR_ERR (hext_stream );
566608 }
567609
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;
569612
570613 /*
571614 * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE
@@ -628,7 +671,8 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
628671
629672cleanup :
630673 /* 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 );
632676 if (ret1 < 0 ) {
633677 dev_err (sdev -> dev , "%s: Code loader DSP cleanup failed\n" , __func__ );
634678
0 commit comments