-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sdw rework #3
Sdw rework #3
Changes from 1 commit
343e424
835b6a8
7c0809b
847e2a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -593,6 +593,17 @@ static int intel_config_stream(struct sdw_intel *sdw, | |
return -EIO; | ||
} | ||
|
||
static int intel_free_stream(struct sdw_intel *sdw, | ||
struct snd_pcm_substream *substream, | ||
struct snd_soc_dai *dai) | ||
{ | ||
if (sdw->res->ops && sdw->res->ops->free_stream && sdw->res->arg) | ||
return sdw->res->ops->free_stream(sdw->res->arg, | ||
substream, dai); | ||
|
||
return 0; | ||
} | ||
|
||
/* | ||
* bank switch routines | ||
*/ | ||
|
@@ -738,6 +749,62 @@ static int intel_startup(struct snd_pcm_substream *substream, | |
return ret; | ||
} | ||
|
||
static int sdw_stream_setup(struct snd_pcm_substream *substream, | ||
struct snd_soc_dai *dai) | ||
{ | ||
struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
struct sdw_stream_runtime *sdw_stream = NULL; | ||
char *name; | ||
int i, ret = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. superfluous initialisation? |
||
|
||
name = kzalloc(32, GFP_KERNEL); | ||
if (!name) | ||
return -ENOMEM; | ||
|
||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
snprintf(name, 32, "%s-Playback", dai->name); | ||
else | ||
snprintf(name, 32, "%s-Capture", dai->name); | ||
|
||
sdw_stream = sdw_alloc_stream(name); | ||
if (!sdw_stream) { | ||
dev_err(dai->dev, | ||
"alloc stream failed for DAI %s: %d", | ||
dai->name, ret); | ||
ret = -ENOMEM; | ||
goto error; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you only kfree(name) here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually this is wrong. The concept of 'stream' means we can use multiple DAIs (cpu and codec), so doing a sdw_alloc_stream here is just not quite right. see comments /**
* sdw_alloc_stream() - Allocate and return stream runtime
*
* @stream_name: SoundWire stream name
*
* Allocates a SoundWire stream runtime instance.
* sdw_alloc_stream should be called only once per stream. Typically
* invoked from ALSA/ASoC machine/platform driver.
*/ |
||
} | ||
|
||
/* Set stream pointer on CPU DAI */ | ||
ret = snd_soc_dai_set_sdw_stream(dai, | ||
sdw_stream, | ||
substream->stream); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @RanderWang please use one line if possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks!I get it. |
||
if (ret < 0) { | ||
dev_err(dai->dev, "failed to set stream pointer on cpu dai %s", | ||
dai->name); | ||
return ret; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memory leak, use goto error |
||
} | ||
|
||
/* Set stream pointer on all CODEC DAIs */ | ||
for (i = 0; i < rtd->num_codecs; i++) { | ||
ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], | ||
sdw_stream, | ||
substream->stream); | ||
if (ret < 0) { | ||
dev_err(dai->dev, "failed to set stream pointer on codec dai %s", | ||
rtd->codec_dais[i]->name); | ||
return ret; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memory leak here too? |
||
} | ||
} | ||
|
||
return 0; | ||
|
||
error: | ||
kfree(name); | ||
sdw_release_stream(sdw_stream); | ||
return ret; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not done in the right order, you need to revert the kfree and sdw_release_stream |
||
} | ||
|
||
static int intel_hw_params(struct snd_pcm_substream *substream, | ||
struct snd_pcm_hw_params *params, | ||
struct snd_soc_dai *dai) | ||
|
@@ -750,6 +817,12 @@ static int intel_hw_params(struct snd_pcm_substream *substream, | |
int ret, i, ch, dir; | ||
bool pcm = true; | ||
|
||
ret = sdw_stream_setup(substream, dai); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we do sdw_stream_step() in hw_params().I think it should be done in startup() to keep it in line with what is there already There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it should be done in a dai operation, the notion of stream is larger than a dai. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am still struggling here, in the initial proposal there was no notion of DAI, Initially we did all the soundwire stream handling in pcm_ops callbacks. Here everything is done as part of dai_ops callbacks. That's very very different! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @plbossart but all the dai_ops are called from the pcm ops context anyway isnt it? like for example: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry @ranj063, I don't get your point. I never fully understood how DPCM works so not sure if the two models are was referring to are equivalent. Does anyone have a sequence diagram showing how those rtd, pcm_ops and cpu_dai and codec_dai ops are called? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will check the ASOC and give a process flow picture There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree with @plbossart the operation can be done in dailink. Actually I think intel_hw_params() will be invoked twice if there are two sdw components in the same dailink. @RanderWang Can we allocate and release stream in machine driver? Maybe we can use startup and shutdown ops? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are component pcm driver and dai driver in ASoC. they all have prepare, hw_params, and trigger functions. In the following picture, dai hw_params is for dai driver , and the only hw_params is for component pcm driver. Now there is only component pcm driver in SOF for SDW, and there is only dai driver in SDW component and codec comopnent. All the components pcm driver are invoked in both FE and BE dai, so you will find some functions are invoke twice. Although there is no component pcm driver in SDW and codec component, I still marked some functions in in picture to reflect the process flow in ASoC |
||
if (ret) { | ||
dev_err(cdns->dev, "stream setup failed:%d\n", ret); | ||
return -EIO; | ||
} | ||
|
||
dma = snd_soc_dai_get_dma_data(dai, substream); | ||
if (!dma) | ||
return -EIO; | ||
|
@@ -835,24 +908,96 @@ static int intel_hw_params(struct snd_pcm_substream *substream, | |
return ret; | ||
} | ||
|
||
static int intel_prepare(struct snd_pcm_substream *substream, | ||
struct snd_soc_dai *dai) | ||
{ | ||
struct sdw_cdns_dma_data *dma; | ||
int ret; | ||
|
||
dma = snd_soc_dai_get_dma_data(dai, substream); | ||
if (!dma) { | ||
dev_err(dai->dev, "failed to get dma data in %s", | ||
__func__); | ||
return -EIO; | ||
} | ||
|
||
ret = sdw_prepare_stream(dma->stream); | ||
return ret; | ||
} | ||
|
||
static int intel_trigger(struct snd_pcm_substream *substream, int cmd, | ||
struct snd_soc_dai *dai) | ||
{ | ||
struct sdw_cdns_dma_data *dma; | ||
int ret; | ||
|
||
dma = snd_soc_dai_get_dma_data(dai, substream); | ||
if (!dma) { | ||
dev_err(dai->dev, "failed to get dma data in %s", __func__); | ||
return -EIO; | ||
} | ||
|
||
switch (cmd) { | ||
case SNDRV_PCM_TRIGGER_START: | ||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
case SNDRV_PCM_TRIGGER_RESUME: | ||
ret = sdw_enable_stream(dma->stream); | ||
if (ret) { | ||
dev_err(dai->dev, | ||
"%s trigger %d failed: %d", | ||
__func__, cmd, ret); | ||
return ret; | ||
} | ||
break; | ||
|
||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
case SNDRV_PCM_TRIGGER_SUSPEND: | ||
case SNDRV_PCM_TRIGGER_STOP: | ||
ret = sdw_disable_stream(dma->stream); | ||
if (ret) { | ||
dev_err(dai->dev, | ||
"%s trigger %d failed: %d", | ||
__func__, cmd, ret); | ||
return ret; | ||
} | ||
break; | ||
|
||
default: | ||
return -EINVAL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int | ||
intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) | ||
{ | ||
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); | ||
struct sdw_intel *sdw = cdns_to_intel(cdns); | ||
struct sdw_cdns_dma_data *dma; | ||
int ret; | ||
|
||
dma = snd_soc_dai_get_dma_data(dai, substream); | ||
if (!dma) | ||
return -EIO; | ||
|
||
ret = sdw_deprepare_stream(dma->stream); | ||
if (ret) { | ||
dev_err(dai->dev, "sdw_deprepare_stream: failed %d", ret); | ||
return ret; | ||
} | ||
|
||
ret = sdw_stream_remove_master(&cdns->bus, dma->stream); | ||
if (ret < 0) | ||
dev_err(dai->dev, "remove master from stream %s failed: %d\n", | ||
dma->stream->name, ret); | ||
|
||
intel_port_cleanup(dma); | ||
kfree(dma->port); | ||
|
||
ret = intel_free_stream(sdw, substream, dai); | ||
sdw_release_stream(dma->stream); | ||
|
||
return ret; | ||
} | ||
|
||
|
@@ -898,13 +1043,17 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { | |
.hw_free = intel_hw_free, | ||
.shutdown = intel_shutdown, | ||
.set_sdw_stream = intel_pcm_set_sdw_stream, | ||
.prepare = intel_prepare, | ||
.trigger = intel_trigger, | ||
}; | ||
|
||
static const struct snd_soc_dai_ops intel_pdm_dai_ops = { | ||
.hw_params = intel_hw_params, | ||
.hw_free = intel_hw_free, | ||
.shutdown = intel_shutdown, | ||
.set_sdw_stream = intel_pdm_set_sdw_stream, | ||
.prepare = intel_prepare, | ||
.trigger = intel_trigger, | ||
}; | ||
|
||
static const struct snd_soc_component_driver dai_component = { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be separate patch