lkml.org 
[lkml]   [2018]   [Jan]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [RESEND PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM
On Thu 14 Dec 09:33 PST 2017, srinivas.kandagatla@linaro.org wrote:

> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>
> This patch adds basic support to Q6 ASM (Audio Stream Manager) module on
> Q6DSP. ASM supports up to 8 concurrent streams. each stream can be setup
> as playback/capture.

"...streams, each one setup as either playback or capture".

or "each" need to be capitalized.

> ASM provides top control functions like
> Pause/flush/resume for playback and record. ASM can Create/destroy encoder,

lower case p and c

> decoder and also provides POPP dynamic services.

Please describe what POPP is.

[..]
> +struct audio_client {
> + int session;
> + app_cb cb;
> + int cmd_state;
> + void *priv;
> + uint32_t io_mode;
> + uint64_t time_stamp;

Unused.

> + struct apr_device *adev;
> + struct mutex cmd_lock;
> + wait_queue_head_t cmd_wait;
> + int perf_mode;
> + int stream_id;
> + struct device *dev;
> +};
> +
> +struct q6asm {
> + struct apr_device *adev;
> + int mem_state;
> + struct device *dev;
> + wait_queue_head_t mem_wait;
> + struct mutex session_lock;
> + struct platform_device *pcmdev;
> + struct audio_client *session[MAX_SESSIONS + 1];
> +};
> +
> +static int q6asm_session_alloc(struct audio_client *ac, struct q6asm *a)

Move the allocation of ac into this function, and return the newly
allocated ac - that way the name of this function makes more sense.

> +{
> + int n = -EINVAL;

You're returning MAX_SESSIONS if no free sessions are found, but are
checking for <= 0 in the caller.

> +
> + mutex_lock(&a->session_lock);
> + for (n = 1; n <= MAX_SESSIONS; n++) {

Is there an external reason for session 0 not being considered?

> + if (!a->session[n]) {
> + a->session[n] = ac;
> + break;
> + }
> + }

If you make session an idr this function would become idr_alloc(1,
MAX_SESSIONS + 1).

> + mutex_unlock(&a->session_lock);
> +
> + return n;
> +}
> +
> +static bool q6asm_is_valid_audio_client(struct audio_client *ac)
> +{
> + struct q6asm *a = dev_get_drvdata(ac->dev->parent);
> + int n;
> +
> + for (n = 1; n <= MAX_SESSIONS; n++) {
> + if (a->session[n] == ac)
> + return 1;

"true"

> + }
> +
> + return 0;

"false"

> +}
> +
> +static void q6asm_session_free(struct audio_client *ac)
> +{
> + struct q6asm *a = dev_get_drvdata(ac->dev->parent);
> +
> + if (!a)
> + return;
> +
> + mutex_lock(&a->session_lock);
> + a->session[ac->session] = 0;
> + ac->session = 0;
> + ac->perf_mode = LEGACY_PCM_MODE;

No need to update ac->*, as you kfree ac as soon as you return from
here.

> + mutex_unlock(&a->session_lock);
> +}
> +
> +/**
> + * q6asm_audio_client_free() - Freee allocated audio client
> + *
> + * @ac: audio client to free
> + */
> +void q6asm_audio_client_free(struct audio_client *ac)
> +{
> + q6asm_session_free(ac);

Inline q6asm_session_free() here.

> + kfree(ac);
> +}
> +EXPORT_SYMBOL_GPL(q6asm_audio_client_free);
> +
> +static struct audio_client *q6asm_get_audio_client(struct q6asm *a,
> + int session_id)
> +{
> + if ((session_id <= 0) || (session_id > MAX_SESSIONS)) {
> + dev_err(a->dev, "invalid session: %d\n", session_id);
> + goto err;

Just return NULL here instead.

> + }
> +
> + if (!a->session[session_id]) {
> + dev_err(a->dev, "session not active: %d\n", session_id);
> + goto err;

Dito

> + }

But this is another place where an idr would be preferable, as both
these cases would be covered with a call to idr_find()

> + return a->session[session_id];
> +err:
> + return NULL;
> +}
> +
> +static int q6asm_srvc_callback(struct apr_device *adev, struct apr_client_data *data)
> +{
> + struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
> + struct audio_client *ac = NULL;
> + uint32_t sid = 0;

This is 4 bits, so just use int.

> + uint32_t *payload;

payload is unused.

> +
> + if (!data) {
> + dev_err(&adev->dev, "%s: Invalid CB\n", __func__);
> + return 0;
> + }

Again, define the apr to never invoke the callback with data = NULL

> +
> + payload = data->payload;
> + sid = (data->token >> 8) & 0x0F;
> + ac = q6asm_get_audio_client(q6asm, sid);
> + if (!ac) {
> + dev_err(&adev->dev, "Audio Client not active\n");
> + return 0;
> + }
> +
> + if (ac->cb)
> + ac->cb(data->opcode, data->token, data->payload, ac->priv);
> + return 0;
> +}
> +
> +/**
> + * q6asm_get_session_id() - get session id for audio client
> + *
> + * @ac: audio client pointer
> + *
> + * Return: Will be an session id of the audio client.
> + */
> +int q6asm_get_session_id(struct audio_client *c)
> +{
> + return c->session;
> +}
> +EXPORT_SYMBOL_GPL(q6asm_get_session_id);
> +
> +/**
> + * q6asm_audio_client_alloc() - Allocate a new audio client
> + *
> + * @dev: Pointer to asm child device.
> + * @cb: event callback.
> + * @priv: private data associated with this client.
> + *
> + * Return: Will be an error pointer on error or a valid audio client
> + * on success.
> + */
> +struct audio_client *q6asm_audio_client_alloc(struct device *dev,
> + app_cb cb, void *priv)
> +{
> + struct q6asm *a = dev_get_drvdata(dev->parent);
> + struct audio_client *ac;
> + int n;
> +
> + ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);

sizeof(*ac)

> + if (!ac)
> + return NULL;
> +
> + n = q6asm_session_alloc(ac, a);

As stated above, moving the kzalloc into q6asm_session_alloc() would
clean the code up here, as you only need to deal with one possible
error case here.

> + if (n <= 0) {
> + dev_err(dev, "ASM Session alloc fail n=%d\n", n);
> + kfree(ac);
> + return NULL;

Per the kerneldoc I expect an ERR_PTR(n) here.

> + }
> +
> + ac->session = n;
> + ac->cb = cb;
> + ac->dev = dev;
> + ac->priv = priv;
> + ac->io_mode = SYNC_IO_MODE;
> + ac->perf_mode = LEGACY_PCM_MODE;
> + /* DSP expects stream id from 1 */
> + ac->stream_id = 1;
> + ac->adev = a->adev;
> +
> + init_waitqueue_head(&ac->cmd_wait);
> + mutex_init(&ac->cmd_lock);
> + ac->cmd_state = 0;
> +
> + return ac;
> +}
> +EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc);
> +
> +

Extra newline.

> +static int q6asm_probe(struct apr_device *adev)
> +{
> + struct q6asm *q6asm;
> +
> + q6asm = devm_kzalloc(&adev->dev, sizeof(*q6asm), GFP_KERNEL);
> + if (!q6asm)
> + return -ENOMEM;
> +
> + q6asm->dev = &adev->dev;
> + q6asm->adev = adev;
> + q6asm->mem_state = 0;
> + init_waitqueue_head(&q6asm->mem_wait);
> + mutex_init(&q6asm->session_lock);
> + dev_set_drvdata(&adev->dev, q6asm);
> +
> + q6asm->pcmdev = platform_device_register_data(&adev->dev,
> + "q6asm_dai", -1, NULL, 0);
> +
> + return 0;
> +}
> +
> +static int q6asm_remove(struct apr_device *adev)
> +{
> + struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
> +
> + platform_device_unregister(q6asm->pcmdev);
> +
> + return 0;
> +}
> +
> +static const struct apr_device_id q6asm_id[] = {
> + {"Q6ASM", APR_DOMAIN_ADSP, APR_SVC_ASM, APR_CLIENT_AUDIO},
> + {}
> +};
> +
> +static struct apr_driver qcom_q6asm_driver = {
> + .probe = q6asm_probe,
> + .remove = q6asm_remove,
> + .callback = q6asm_srvc_callback,
> + .id_table = q6asm_id,
> + .driver = {
> + .name = "qcom-q6asm",
> + },

Indentation

> +};
> +
> +module_apr_driver(qcom_q6asm_driver);
> +MODULE_DESCRIPTION("Q6 Audio Stream Manager driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
> new file mode 100644
> index 000000000000..7a8a9039fd89
> --- /dev/null
> +++ b/sound/soc/qcom/qdsp6/q6asm.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __Q6_ASM_H__
> +#define __Q6_ASM_H__
> +
> +#define MAX_SESSIONS 16
> +
> +typedef void (*app_cb) (uint32_t opcode, uint32_t token,
> + uint32_t *payload, void *priv);

This name of a type is too generic.

And make payload void *, unless the payload really really is an
unstructured uint32_t array.

Regards,
Bjorn

\
 
 \ /
  Last update: 2018-01-02 05:45    [W:0.279 / U:17.960 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site