diff options
Diffstat (limited to 'sound/soc/intel/skylake/skl-topology.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-topology.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 4624556f486d..5a4837dcfce3 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c | |||
@@ -54,12 +54,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) | |||
54 | 54 | ||
55 | /* | 55 | /* |
56 | * Each pipelines needs memory to be allocated. Check if we have free memory | 56 | * Each pipelines needs memory to be allocated. Check if we have free memory |
57 | * from available pool. Then only add this to pool | 57 | * from available pool. |
58 | * This is freed when pipe is deleted | ||
59 | * Note: DSP does actual memory management we only keep track for complete | ||
60 | * pool | ||
61 | */ | 58 | */ |
62 | static bool skl_tplg_alloc_pipe_mem(struct skl *skl, | 59 | static bool skl_is_pipe_mem_avail(struct skl *skl, |
63 | struct skl_module_cfg *mconfig) | 60 | struct skl_module_cfg *mconfig) |
64 | { | 61 | { |
65 | struct skl_sst *ctx = skl->skl_sst; | 62 | struct skl_sst *ctx = skl->skl_sst; |
@@ -74,10 +71,20 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, | |||
74 | "exceeds ppl memory available %d mem %d\n", | 71 | "exceeds ppl memory available %d mem %d\n", |
75 | skl->resource.max_mem, skl->resource.mem); | 72 | skl->resource.max_mem, skl->resource.mem); |
76 | return false; | 73 | return false; |
74 | } else { | ||
75 | return true; | ||
77 | } | 76 | } |
77 | } | ||
78 | 78 | ||
79 | /* | ||
80 | * Add the mem to the mem pool. This is freed when pipe is deleted. | ||
81 | * Note: DSP does actual memory management we only keep track for complete | ||
82 | * pool | ||
83 | */ | ||
84 | static void skl_tplg_alloc_pipe_mem(struct skl *skl, | ||
85 | struct skl_module_cfg *mconfig) | ||
86 | { | ||
79 | skl->resource.mem += mconfig->pipe->memory_pages; | 87 | skl->resource.mem += mconfig->pipe->memory_pages; |
80 | return true; | ||
81 | } | 88 | } |
82 | 89 | ||
83 | /* | 90 | /* |
@@ -85,10 +92,10 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl, | |||
85 | * quantified in MCPS (Million Clocks Per Second) required for module/pipe | 92 | * quantified in MCPS (Million Clocks Per Second) required for module/pipe |
86 | * | 93 | * |
87 | * Each pipelines needs mcps to be allocated. Check if we have mcps for this | 94 | * Each pipelines needs mcps to be allocated. Check if we have mcps for this |
88 | * pipe. This adds the mcps to driver counter | 95 | * pipe. |
89 | * This is removed on pipeline delete | ||
90 | */ | 96 | */ |
91 | static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, | 97 | |
98 | static bool skl_is_pipe_mcps_avail(struct skl *skl, | ||
92 | struct skl_module_cfg *mconfig) | 99 | struct skl_module_cfg *mconfig) |
93 | { | 100 | { |
94 | struct skl_sst *ctx = skl->skl_sst; | 101 | struct skl_sst *ctx = skl->skl_sst; |
@@ -98,13 +105,18 @@ static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, | |||
98 | "%s: module_id %d instance %d\n", __func__, | 105 | "%s: module_id %d instance %d\n", __func__, |
99 | mconfig->id.module_id, mconfig->id.instance_id); | 106 | mconfig->id.module_id, mconfig->id.instance_id); |
100 | dev_err(ctx->dev, | 107 | dev_err(ctx->dev, |
101 | "exceeds ppl memory available %d > mem %d\n", | 108 | "exceeds ppl mcps available %d > mem %d\n", |
102 | skl->resource.max_mcps, skl->resource.mcps); | 109 | skl->resource.max_mcps, skl->resource.mcps); |
103 | return false; | 110 | return false; |
111 | } else { | ||
112 | return true; | ||
104 | } | 113 | } |
114 | } | ||
105 | 115 | ||
116 | static void skl_tplg_alloc_pipe_mcps(struct skl *skl, | ||
117 | struct skl_module_cfg *mconfig) | ||
118 | { | ||
106 | skl->resource.mcps += mconfig->mcps; | 119 | skl->resource.mcps += mconfig->mcps; |
107 | return true; | ||
108 | } | 120 | } |
109 | 121 | ||
110 | /* | 122 | /* |
@@ -411,7 +423,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
411 | mconfig = w->priv; | 423 | mconfig = w->priv; |
412 | 424 | ||
413 | /* check resource available */ | 425 | /* check resource available */ |
414 | if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) | 426 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) |
415 | return -ENOMEM; | 427 | return -ENOMEM; |
416 | 428 | ||
417 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { | 429 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { |
@@ -435,6 +447,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
435 | ret = skl_tplg_set_module_params(w, ctx); | 447 | ret = skl_tplg_set_module_params(w, ctx); |
436 | if (ret < 0) | 448 | if (ret < 0) |
437 | return ret; | 449 | return ret; |
450 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
438 | } | 451 | } |
439 | 452 | ||
440 | return 0; | 453 | return 0; |
@@ -477,10 +490,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
477 | struct skl_sst *ctx = skl->skl_sst; | 490 | struct skl_sst *ctx = skl->skl_sst; |
478 | 491 | ||
479 | /* check resource available */ | 492 | /* check resource available */ |
480 | if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) | 493 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) |
481 | return -EBUSY; | 494 | return -EBUSY; |
482 | 495 | ||
483 | if (!skl_tplg_alloc_pipe_mem(skl, mconfig)) | 496 | if (!skl_is_pipe_mem_avail(skl, mconfig)) |
484 | return -ENOMEM; | 497 | return -ENOMEM; |
485 | 498 | ||
486 | /* | 499 | /* |
@@ -526,11 +539,15 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
526 | src_module = dst_module; | 539 | src_module = dst_module; |
527 | } | 540 | } |
528 | 541 | ||
542 | skl_tplg_alloc_pipe_mem(skl, mconfig); | ||
543 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
544 | |||
529 | return 0; | 545 | return 0; |
530 | } | 546 | } |
531 | 547 | ||
532 | static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, | 548 | static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, |
533 | struct skl *skl, | 549 | struct skl *skl, |
550 | struct snd_soc_dapm_widget *src_w, | ||
534 | struct skl_module_cfg *src_mconfig) | 551 | struct skl_module_cfg *src_mconfig) |
535 | { | 552 | { |
536 | struct snd_soc_dapm_path *p; | 553 | struct snd_soc_dapm_path *p; |
@@ -547,6 +564,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, | |||
547 | dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); | 564 | dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); |
548 | 565 | ||
549 | next_sink = p->sink; | 566 | next_sink = p->sink; |
567 | |||
568 | if (!is_skl_dsp_widget_type(p->sink)) | ||
569 | return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); | ||
570 | |||
550 | /* | 571 | /* |
551 | * here we will check widgets in sink pipelines, so that | 572 | * here we will check widgets in sink pipelines, so that |
552 | * can be any widgets type and we are only interested if | 573 | * can be any widgets type and we are only interested if |
@@ -576,7 +597,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, | |||
576 | } | 597 | } |
577 | 598 | ||
578 | if (!sink) | 599 | if (!sink) |
579 | return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); | 600 | return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); |
580 | 601 | ||
581 | return 0; | 602 | return 0; |
582 | } | 603 | } |
@@ -605,7 +626,7 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
605 | * if sink is not started, start sink pipe first, then start | 626 | * if sink is not started, start sink pipe first, then start |
606 | * this pipe | 627 | * this pipe |
607 | */ | 628 | */ |
608 | ret = skl_tplg_bind_sinks(w, skl, src_mconfig); | 629 | ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); |
609 | if (ret) | 630 | if (ret) |
610 | return ret; | 631 | return ret; |
611 | 632 | ||
@@ -773,10 +794,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, | |||
773 | continue; | 794 | continue; |
774 | } | 795 | } |
775 | 796 | ||
776 | ret = skl_unbind_modules(ctx, src_module, dst_module); | 797 | skl_unbind_modules(ctx, src_module, dst_module); |
777 | if (ret < 0) | ||
778 | return ret; | ||
779 | |||
780 | src_module = dst_module; | 798 | src_module = dst_module; |
781 | } | 799 | } |
782 | 800 | ||
@@ -814,9 +832,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, | |||
814 | * This is a connecter and if path is found that means | 832 | * This is a connecter and if path is found that means |
815 | * unbind between source and sink has not happened yet | 833 | * unbind between source and sink has not happened yet |
816 | */ | 834 | */ |
817 | ret = skl_stop_pipe(ctx, sink_mconfig->pipe); | ||
818 | if (ret < 0) | ||
819 | return ret; | ||
820 | ret = skl_unbind_modules(ctx, src_mconfig, | 835 | ret = skl_unbind_modules(ctx, src_mconfig, |
821 | sink_mconfig); | 836 | sink_mconfig); |
822 | } | 837 | } |
@@ -842,6 +857,12 @@ static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, | |||
842 | case SND_SOC_DAPM_PRE_PMU: | 857 | case SND_SOC_DAPM_PRE_PMU: |
843 | return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); | 858 | return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); |
844 | 859 | ||
860 | case SND_SOC_DAPM_POST_PMU: | ||
861 | return skl_tplg_mixer_dapm_post_pmu_event(w, skl); | ||
862 | |||
863 | case SND_SOC_DAPM_PRE_PMD: | ||
864 | return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); | ||
865 | |||
845 | case SND_SOC_DAPM_POST_PMD: | 866 | case SND_SOC_DAPM_POST_PMD: |
846 | return skl_tplg_mixer_dapm_post_pmd_event(w, skl); | 867 | return skl_tplg_mixer_dapm_post_pmd_event(w, skl); |
847 | } | 868 | } |
@@ -916,6 +937,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, | |||
916 | skl_get_module_params(skl->skl_sst, (u32 *)bc->params, | 937 | skl_get_module_params(skl->skl_sst, (u32 *)bc->params, |
917 | bc->max, bc->param_id, mconfig); | 938 | bc->max, bc->param_id, mconfig); |
918 | 939 | ||
940 | /* decrement size for TLV header */ | ||
941 | size -= 2 * sizeof(u32); | ||
942 | |||
943 | /* check size as we don't want to send kernel data */ | ||
944 | if (size > bc->max) | ||
945 | size = bc->max; | ||
946 | |||
919 | if (bc->params) { | 947 | if (bc->params) { |
920 | if (copy_to_user(data, &bc->param_id, sizeof(u32))) | 948 | if (copy_to_user(data, &bc->param_id, sizeof(u32))) |
921 | return -EFAULT; | 949 | return -EFAULT; |
@@ -950,7 +978,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, | |||
950 | return -EFAULT; | 978 | return -EFAULT; |
951 | } else { | 979 | } else { |
952 | if (copy_from_user(ac->params, | 980 | if (copy_from_user(ac->params, |
953 | data + 2 * sizeof(u32), size)) | 981 | data + 2, size)) |
954 | return -EFAULT; | 982 | return -EFAULT; |
955 | } | 983 | } |
956 | 984 | ||
@@ -1510,6 +1538,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) | |||
1510 | &skl_tplg_ops, fw, 0); | 1538 | &skl_tplg_ops, fw, 0); |
1511 | if (ret < 0) { | 1539 | if (ret < 0) { |
1512 | dev_err(bus->dev, "tplg component load failed%d\n", ret); | 1540 | dev_err(bus->dev, "tplg component load failed%d\n", ret); |
1541 | release_firmware(fw); | ||
1513 | return -EINVAL; | 1542 | return -EINVAL; |
1514 | } | 1543 | } |
1515 | 1544 | ||