All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bjorn Andersson <bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
To: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org
Cc: Andy Gross <andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org,
	Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Banajit Goswami
	<bgoswami-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Patrick Lai <plai-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>,
	Takashi Iwai <tiwai-IBi9RG/b67k@public.gmane.org>,
	sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
	Liam Girdwood <lgirdwood-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	Jaroslav Kysela <perex-/Fr2/VpizcU@public.gmane.org>,
	David Brown <david.brown-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	linux-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: Re: [RESEND PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM
Date: Mon, 1 Jan 2018 20:43:50 -0800	[thread overview]
Message-ID: <20180102044350.GO478@tuxbook> (raw)
In-Reply-To: <20171214173402.19074-7-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Thu 14 Dec 09:33 PST 2017, srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org wrote:

> From: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.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
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: Bjorn Andersson <bjorn.andersson@linaro.org>
To: srinivas.kandagatla@linaro.org
Cc: Andy Gross <andy.gross@linaro.org>,
	Mark Brown <broonie@kernel.org>,
	linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org,
	Mark Rutland <mark.rutland@arm.com>,
	devicetree@vger.kernel.org,
	Banajit Goswami <bgoswami@codeaurora.org>,
	linux-kernel@vger.kernel.org, Patrick Lai <plai@codeaurora.org>,
	Takashi Iwai <tiwai@suse.com>,
	sboyd@codeaurora.org, Liam Girdwood <lgirdwood@gmail.com>,
	Jaroslav Kysela <perex@perex.cz>,
	David Brown <david.brown@linaro.org>,
	Rob Herring <robh+dt@kernel.org>,
	linux-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Subject: Re: [RESEND PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM
Date: Mon, 1 Jan 2018 20:43:50 -0800	[thread overview]
Message-ID: <20180102044350.GO478@tuxbook> (raw)
In-Reply-To: <20171214173402.19074-7-srinivas.kandagatla@linaro.org>

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

WARNING: multiple messages have this Message-ID (diff)
From: bjorn.andersson@linaro.org (Bjorn Andersson)
To: linux-arm-kernel@lists.infradead.org
Subject: [RESEND PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM
Date: Mon, 1 Jan 2018 20:43:50 -0800	[thread overview]
Message-ID: <20180102044350.GO478@tuxbook> (raw)
In-Reply-To: <20171214173402.19074-7-srinivas.kandagatla@linaro.org>

On Thu 14 Dec 09:33 PST 2017, srinivas.kandagatla at 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

  parent reply	other threads:[~2018-01-02  4:43 UTC|newest]

Thread overview: 166+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-14 17:33 [RESEND PATCH v2 00/15] ASoC: qcom: Add support to QDSP6 based audio srinivas.kandagatla
2017-12-14 17:33 ` srinivas.kandagatla at linaro.org
2017-12-14 17:33 ` [RESEND PATCH v2 01/15] dt-bindings: soc: qcom: Add bindings for APR bus srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
     [not found]   ` <20171214173402.19074-2-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-12-16 17:27     ` Rob Herring
2017-12-16 17:27       ` Rob Herring
2017-12-16 17:27       ` Rob Herring
2017-12-18  9:50       ` Srinivas Kandagatla
2017-12-18  9:50         ` Srinivas Kandagatla
2018-01-03  0:35   ` Bjorn Andersson
2018-01-03  0:35     ` Bjorn Andersson
2018-01-03 16:26     ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 02/15] soc: qcom: add support to APR bus driver srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
     [not found]   ` <20171214173402.19074-3-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-01 23:29     ` Bjorn Andersson
2018-01-01 23:29       ` Bjorn Andersson
2018-01-01 23:29       ` Bjorn Andersson
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26         ` Srinivas Kandagatla
2018-01-03 16:26         ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 03/15] ASoC: qcom: qdsp6: Add common qdsp6 helper functions srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
2018-01-02  0:19   ` Bjorn Andersson
2018-01-02  0:19     ` Bjorn Andersson
2018-01-02  0:19     ` Bjorn Andersson
2018-01-03 16:26     ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 04/15] ASoC: qcom: qdsp6: Add support to Q6AFE srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
2018-01-02  0:45   ` Bjorn Andersson
2018-01-02  0:45     ` Bjorn Andersson
2018-01-02  0:45     ` Bjorn Andersson
2018-01-03 16:26     ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 05/15] ASoC: qcom: qdsp6: Add support to Q6ADM srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
     [not found]   ` <20171214173402.19074-6-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-02  1:50     ` Bjorn Andersson
2018-01-02  1:50       ` Bjorn Andersson
2018-01-02  1:50       ` Bjorn Andersson
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26         ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
     [not found]   ` <20171214173402.19074-7-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-02  4:43     ` Bjorn Andersson [this message]
2018-01-02  4:43       ` Bjorn Andersson
2018-01-02  4:43       ` Bjorn Andersson
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26         ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 08/15] ASoC: qcom: q6asm: add support to audio stream apis srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
2018-01-02 20:08   ` Bjorn Andersson
2018-01-02 20:08     ` Bjorn Andersson
2018-01-03 16:26     ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-13  8:42   ` Rohit Kumar
2018-01-13  8:42     ` [alsa-devel] " Rohit Kumar
2018-01-13  8:42     ` Rohit Kumar
2017-12-14 17:33 ` [RESEND PATCH v2 09/15] ASoC: qcom: qdsp6: Add support to Q6CORE srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2017-12-14 17:33   ` srinivas.kandagatla
2018-01-02 22:15   ` Bjorn Andersson
2018-01-02 22:15     ` Bjorn Andersson
2018-01-03 16:27     ` Srinivas Kandagatla
2018-01-03 16:27       ` Srinivas Kandagatla
2018-02-07 12:15   ` [alsa-devel] " Rohit Kumar
2018-02-07 12:15     ` Rohit Kumar
2017-12-14 17:33 ` [RESEND PATCH v2 10/15] ASoC: qcom: qdsp6: Add support to q6routing driver srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2018-01-02 23:00   ` Bjorn Andersson
2018-01-02 23:00     ` Bjorn Andersson
2018-01-02 23:00     ` Bjorn Andersson
2018-01-03 16:27     ` Srinivas Kandagatla
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-03 16:27       ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 11/15] ASoC: qcom: qdsp6: Add support to q6afe dai driver srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
     [not found]   ` <20171214173402.19074-12-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-02 23:28     ` Bjorn Andersson
2018-01-02 23:28       ` Bjorn Andersson
2018-01-02 23:28       ` Bjorn Andersson
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-03 16:27         ` Srinivas Kandagatla
2018-01-03 16:27         ` Srinivas Kandagatla
2018-02-07 11:34   ` Rohit Kumar
2018-02-07 11:34     ` [alsa-devel] " Rohit Kumar
2018-02-07 11:34     ` Rohit Kumar
2018-02-07 11:40     ` Srinivas Kandagatla
2018-02-07 11:40       ` Srinivas Kandagatla
2017-12-14 17:33 ` [RESEND PATCH v2 12/15] ASoC: qcom: qdsp6: Add support to q6asm " srinivas.kandagatla
2017-12-14 17:33   ` srinivas.kandagatla at linaro.org
2018-01-03  0:03   ` Bjorn Andersson
2018-01-03  0:03     ` Bjorn Andersson
2018-01-03 16:27     ` Srinivas Kandagatla
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-13  8:45   ` [alsa-devel] " Rohit Kumar
2018-01-13  8:45     ` Rohit Kumar
     [not found] ` <20171214173402.19074-1-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-12-14 17:33   ` [RESEND PATCH v2 07/15] ASoC: qcom: q6asm: Add support to memory map and unmap srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
2017-12-14 17:33     ` srinivas.kandagatla at linaro.org
2017-12-14 17:33     ` srinivas.kandagatla
2018-01-02  5:48     ` Bjorn Andersson
2018-01-02  5:48       ` Bjorn Andersson
2018-01-03 16:26       ` Srinivas Kandagatla
2018-01-03 16:26         ` Srinivas Kandagatla
     [not found]         ` <4d1d17df-71a4-2896-29c1-9d033a2f3711-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-03 19:39           ` Bjorn Andersson
2018-01-03 19:39             ` Bjorn Andersson
2018-01-03 19:39             ` Bjorn Andersson
2017-12-14 17:34   ` [RESEND PATCH v2 13/15] dt-bindings: sound: qcom: Add devicetree bindings for apq8096 srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
2017-12-14 17:34     ` srinivas.kandagatla at linaro.org
2017-12-14 17:34     ` srinivas.kandagatla
2017-12-16 17:44     ` Rob Herring
2017-12-16 17:44       ` Rob Herring
2017-12-18  9:49       ` Srinivas Kandagatla
2017-12-18  9:49         ` Srinivas Kandagatla
2017-12-18  9:49         ` Srinivas Kandagatla
2018-01-03  0:28     ` Bjorn Andersson
2018-01-03  0:28       ` Bjorn Andersson
2018-01-03  0:28       ` Bjorn Andersson
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-03 16:27         ` Srinivas Kandagatla
     [not found]         ` <787ecdc5-66d8-23ee-7136-2a8759c86536-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-03 19:49           ` Bjorn Andersson
2018-01-03 19:49             ` Bjorn Andersson
2018-01-03 19:49             ` Bjorn Andersson
2017-12-14 17:34   ` [RESEND PATCH v2 14/15] ASoC: qcom: apq8096: Add db820c machine driver srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
2017-12-14 17:34     ` srinivas.kandagatla at linaro.org
2017-12-14 17:34     ` srinivas.kandagatla
2018-01-03  0:16     ` Bjorn Andersson
2018-01-03  0:16       ` Bjorn Andersson
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-03 16:27         ` Srinivas Kandagatla
2018-01-03 20:04         ` Bjorn Andersson
2018-01-03 20:04           ` Bjorn Andersson
2018-01-03 20:04           ` Bjorn Andersson
2018-01-03 17:20     ` Stephen Boyd
2018-01-03 17:20       ` Stephen Boyd
2018-01-03 18:36       ` Srinivas Kandagatla
2018-01-03 18:36         ` Srinivas Kandagatla
2018-01-03 19:41         ` Stephen Boyd
2018-01-03 19:41           ` Stephen Boyd
2018-01-03 19:41           ` Stephen Boyd
2018-01-04  9:25           ` Srinivas Kandagatla
2018-01-04  9:25             ` Srinivas Kandagatla
2018-01-04 12:02       ` Mark Brown
2018-01-04 12:02         ` Mark Brown
2018-01-04 12:02         ` Mark Brown
2018-01-04 13:44         ` Srinivas Kandagatla
2018-01-04 13:44           ` Srinivas Kandagatla
2018-01-04 14:03           ` Mark Brown
2018-01-04 14:03             ` Mark Brown
2018-01-04 14:03             ` Mark Brown
2017-12-14 17:34 ` [RESEND PATCH v2 15/15] arm64: dts: msm8996: db820c: Add sound card support srinivas.kandagatla
2017-12-14 17:34   ` srinivas.kandagatla at linaro.org
     [not found]   ` <20171214173402.19074-16-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2018-01-03  0:22     ` Bjorn Andersson
2018-01-03  0:22       ` Bjorn Andersson
2018-01-03  0:22       ` Bjorn Andersson
2018-01-03 16:27       ` Srinivas Kandagatla
2018-01-03 16:27         ` Srinivas Kandagatla
2018-01-03 20:01         ` Bjorn Andersson
2018-01-03 20:01           ` Bjorn Andersson
2018-01-03 20:01           ` Bjorn Andersson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180102044350.GO478@tuxbook \
    --to=bjorn.andersson-qsej5fyqhm4dnm+yrofe0a@public.gmane.org \
    --cc=alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org \
    --cc=andy.gross-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=bgoswami-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
    --cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=david.brown-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=lgirdwood-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
    --cc=perex-/Fr2/VpizcU@public.gmane.org \
    --cc=plai-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
    --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
    --cc=srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=tiwai-IBi9RG/b67k@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.