[alsa-devel] [PATCH 0/6] ASoC: rsnd: cleanup for IOMMU
Hi Mark
I will post IOMMU support patches for rsnd driver. These are prepare/cleanup for it.
Kuninori Morimoto (6): ASoC: rsnd: remove duplicate define of rsnd_dvc_of_node() ASoC: rsnd: amend .probe/.remove call for DPCM ASoC: rsnd: add rsnd_mod_next() for for_each_rsnd_mod_xxx() ASoC: rsnd: use for_each_rsnd_mod_xxx() on rsnd_dai_call() ASoC: rsnd: use for_each_rsnd_mod_xxx() on rsnd_rdai_continuance_probe() ASoC: rsnd: add rsnd_parse_of_node() and integrate rsnd_xxx_of_node
sound/soc/sh/rcar/core.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------ sound/soc/sh/rcar/dma.c | 11 +++++++++++ sound/soc/sh/rcar/dvc.c | 2 -- sound/soc/sh/rcar/rsnd.h | 56 +++++++++++++++++++++++++++++++++++++------------------- sound/soc/sh/rcar/ssi.c | 5 ++++- 5 files changed, 125 insertions(+), 64 deletions(-)
Best regards --- Kuninori Morimoto
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dvc.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 02d971f..cf8f59c 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -48,8 +48,6 @@ struct rsnd_dvc {
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
#define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
commit 1a5658c2131 ("ASoC: rsnd: count .probe/.remove for rsnd_mod_call()") solved multi-resource-free issue, by putting .probe/.remove under count control. But,it breaks sound mixing case (if it was used under DPCM). In such case, it uses MIXn/DVCn/SSIn, and these should be always probed. This patch reverted above patch, and solved the same issue by modifing _rsnd_kctrl_remove() function.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 6 +++++- sound/soc/sh/rcar/dma.c | 11 +++++++++++ sound/soc/sh/rcar/rsnd.h | 14 +++++++------- sound/soc/sh/rcar/ssi.c | 5 ++++- 4 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f181410..209e736 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -993,7 +993,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { - snd_ctl_remove(cfg->card, cfg->kctrl); + if (cfg->card && cfg->kctrl) + snd_ctl_remove(cfg->card, cfg->kctrl); + + cfg->card = NULL; + cfg->kctrl = NULL; }
int rsnd_kctrl_new_m(struct rsnd_mod *mod, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6bc93cb..b3bdd36 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -707,6 +707,17 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, return 0; }
+void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod) +{ + if (*dma_mod) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + devm_kfree(dev, *dma_mod); + *dma_mod = NULL; + } +} + int rsnd_dma_probe(struct rsnd_priv *priv) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a8f61d7..901095c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -200,6 +200,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); */ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); +void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -276,9 +277,8 @@ struct rsnd_mod { /* * status * - * 0xH0000CBA + * 0xH0000CB0 * - * A 0: probe 1: remove * B 0: init 1: quit * C 0: start 1: stop * @@ -288,19 +288,19 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ -#define __rsnd_mod_shift_probe 0 -#define __rsnd_mod_shift_remove 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_probe 28 /* always called */ +#define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */
-#define __rsnd_mod_add_probe 1 -#define __rsnd_mod_add_remove -1 +#define __rsnd_mod_add_probe 0 +#define __rsnd_mod_add_remove 0 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -311,7 +311,7 @@ struct rsnd_mod { #define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 1 +#define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6cb6db0..94a19f9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -698,7 +698,10 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, int irq = ssi->irq;
/* PIO will request IRQ again */ - devm_free_irq(dev, irq, mod); + if (ssi->dma) + devm_free_irq(dev, irq, mod); + + rsnd_dma_detach(mod, &ssi->dma);
return 0; }
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rsnd driver is using too complex macro for for-loop of each mod. In order to simplify this issue, this patch adds new rsnd_mod_next() which is non-macro.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 23 +++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 12 ++++++++++++ 2 files changed, 35 insertions(+)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 209e736..c0196f8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -348,6 +348,29 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size) +{ + struct rsnd_mod *mod; + enum rsnd_mod_type type; + int max = array ? array_size : RSND_MOD_MAX; + + for (; *iterator < max; (*iterator)++) { + type = (array) ? array[*iterator] : *iterator; + mod = io->mod[type]; + if (!mod) + continue; + + (*iterator)++; + + return mod; + } + + return NULL; +} + #define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 901095c..d8f81a4 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -346,6 +346,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, struct rsnd_mod *mod, enum rsnd_mod_type type); +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size); +#define for_each_rsnd_mod(iterator, pos, io) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, NULL, 0));) +#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, array, size));) +#define for_each_rsnd_mod_array(iterator, pos, io, array) \ + for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rsnd driver is using too complex macro for for-loop of each mod. rsnd_dai_call() is especially defined as very complex macro. It is easier to read just a little bit by using for_each_rsnd_mod_xxx() and new rsnd_status_update()
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 83 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 40 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index c0196f8..aba49b2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -371,33 +371,6 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, return NULL; }
-#define rsnd_mod_call(idx, io, func, param...) \ -({ \ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ - struct rsnd_mod *mod = (io)->mod[idx]; \ - struct device *dev = rsnd_priv_to_dev(priv); \ - u32 *status = mod->get_status(io, mod, idx); \ - u32 mask = 0xF << __rsnd_mod_shift_##func; \ - u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ - u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ - int ret = 0; \ - int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - if (add == 0xF) \ - call = 0; \ - else \ - *status = (*status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ - dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), \ - *status, call ? #func : ""); \ - if (call) \ - ret = (mod)->ops->func(mod, io, param); \ - if (ret) \ - dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ - ret; \ -}) - static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { /* CAPTURE */ @@ -432,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, };
-#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct rsnd_mod *mod; \ - int type, is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - for (i = 0; i < RSND_MOD_MAX; i++) { \ - type = rsnd_mod_sequence[is_play][i]; \ - mod = (io)->mod[type]; \ - if (!mod) \ - continue; \ - ret |= rsnd_mod_call(type, io, fn, param); \ - } \ - ret; \ +static int rsnd_status_update(u32 *status, + int shift, int add, int timing) +{ + u32 mask = 0xF << shift; + u8 val = (*status >> shift) & 0xF; + u8 next_val = (val + add) & 0xF; + int func_call = (val == timing); + + if (next_val == 0xF) /* underflow case */ + func_call = 0; + else + *status = (*status & ~mask) + (next_val << shift); + + return func_call; +} + +#define rsnd_dai_call(fn, io, param...) \ +({ \ + struct rsnd_priv *priv = rsnd_io_to_priv(io); \ + struct device *dev = rsnd_priv_to_dev(priv); \ + struct rsnd_mod *mod; \ + int is_play = rsnd_io_is_play(io); \ + int ret = 0, i; \ + enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ + for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ + int tmp = 0; \ + u32 *status = mod->get_status(io, mod, types[i]); \ + int func_call = rsnd_status_update(status, \ + __rsnd_mod_shift_##fn, \ + __rsnd_mod_add_##fn, \ + __rsnd_mod_call_##fn); \ + dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ + (func_call && (mod)->ops->fn) ? #fn : ""); \ + if (func_call && (mod)->ops->fn) \ + tmp = (mod)->ops->fn(mod, io, param); \ + if (tmp) \ + dev_err(dev, "%s[%d] : %s error %d\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), \ + #fn, tmp); \ + ret |= tmp; \ + } \ + ret; \ })
int rsnd_dai_connect(struct rsnd_mod *mod,
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Now, we have for_each_rsnd_mod(), let's use it
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index aba49b2..ea14a14 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1122,6 +1122,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *mod; int i;
/* @@ -1141,8 +1142,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ - for (i = 0; i < RSND_MOD_MAX; i++) - rsnd_dai_disconnect((io)->mod[i], io, i); + for_each_rsnd_mod(i, mod, io) + rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
/*
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/rsnd.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d8f81a4..b3b4d89 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -377,6 +377,18 @@ int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
/* + * DT + */ +#define rsnd_parse_of_node(priv, node) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) +#define RSND_NODE_DAI "rcar_sound,dai" +#define RSND_NODE_SSI "rcar_sound,ssi" +#define RSND_NODE_SRC "rcar_sound,src" +#define RSND_NODE_CTU "rcar_sound,ctu" +#define RSND_NODE_MIX "rcar_sound,mix" +#define RSND_NODE_DVC "rcar_sound,dvc" + +/* * R-Car sound DAI */ #define RSND_DAI_NAME_SIZE 16 @@ -440,8 +452,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); -#define rsnd_dai_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") +#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
/* * R-Car Gen1/Gen2 @@ -618,8 +629,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
-#define rsnd_ssi_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); @@ -645,8 +655,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, int is_in);
-#define rsnd_src_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) #define rsnd_parse_connect_src(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -659,8 +668,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv); int rsnd_ctu_converted_channel(struct rsnd_mod *mod); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_parse_connect_ctu(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -672,8 +680,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); int rsnd_mix_probe(struct rsnd_priv *priv); void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) #define rsnd_parse_connect_mix(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -685,8 +692,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); int rsnd_dvc_probe(struct rsnd_priv *priv); void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) #define rsnd_parse_connect_dvc(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
participants (1)
-
Kuninori Morimoto