Re: [PATCH 1/2] slimbus: qcom-ngd-ctrl: add Sub System Restart support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In-Reply-To: <20201118170246.16588-2-srinivas.kandagatla@xxxxxxxxxx>

On Wed, 18 Nov 2020 17:02:45 +0000, Srinivas Kandagatla wrote:
> This patch adds SSR(SubSystem Restart) support which includes, synchronisation
> between SSR and QMI server notifications. Also with this patch now NGD is taken
> down by SSR instead of QMI server down notification.
>
> NGD up path now relies on both SSR and QMI notifications and particularly
> sequence of SSR up followed by QMI server up notification.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
> ---
>  drivers/slimbus/Kconfig         |  1 +
>  drivers/slimbus/qcom-ngd-ctrl.c | 97 +++++++++++++++++++++++++++++++--
>  2 files changed, 94 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig
> index 8cd595148d17..7c950948a9ec 100644
> --- a/drivers/slimbus/Kconfig
> +++ b/drivers/slimbus/Kconfig
> @@ -25,6 +25,7 @@ config SLIM_QCOM_NGD_CTRL
>  	depends on HAS_IOMEM && DMA_ENGINE && NET
>  	depends on ARCH_QCOM || COMPILE_TEST
>  	select QCOM_QMI_HELPERS
> +	select QCOM_RPROC_COMMON
>  	help
>  	  Select driver if Qualcomm's SLIMbus Satellite Non-Generic Device
>  	  Component is programmed using Linux kernel.
> diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
> index 218aefc3531c..f62693653d2b 100644
> --- a/drivers/slimbus/qcom-ngd-ctrl.c
> +++ b/drivers/slimbus/qcom-ngd-ctrl.c
> @@ -13,6 +13,9 @@
>  #include <linux/slimbus.h>
>  #include <linux/delay.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/mutex.h>
> +#include <linux/notifier.h>
> +#include <linux/remoteproc/qcom_rproc.h>
>  #include <linux/of.h>
>  #include <linux/io.h>
>  #include <linux/soc/qcom/qmi.h>
> @@ -155,8 +158,14 @@ struct qcom_slim_ngd_ctrl {
>  	struct qcom_slim_ngd_dma_desc txdesc[QCOM_SLIM_NGD_DESC_NUM];
>  	struct completion reconf;
>  	struct work_struct m_work;
> +	struct work_struct ngd_up_work;
>  	struct workqueue_struct *mwq;
> +	struct completion qmi_up;
>  	spinlock_t tx_buf_lock;
> +	struct mutex tx_lock;
> +	struct mutex ssr_lock;
> +	struct notifier_block nb;
> +	void *notifier;
>  	enum qcom_slim_ngd_state state;
>  	dma_addr_t rx_phys_base;
>  	dma_addr_t tx_phys_base;
> @@ -868,14 +877,18 @@ static int qcom_slim_ngd_xfer_msg(struct slim_controller *sctrl,
>  	if (txn->msg && txn->msg->wbuf)
>  		memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes);
>
> +	mutex_lock(&ctrl->tx_lock);
>  	ret = qcom_slim_ngd_tx_msg_post(ctrl, pbuf, txn->rl);
> -	if (ret)
> +	if (ret) {
> +		mutex_unlock(&ctrl->tx_lock);
>  		return ret;
> +	}
>
>  	timeout = wait_for_completion_timeout(&tx_sent, HZ);
>  	if (!timeout) {
>  		dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
>  					txn->mt);
> +		mutex_unlock(&ctrl->tx_lock);
>  		return -ETIMEDOUT;
>  	}
>
> @@ -884,10 +897,12 @@ static int qcom_slim_ngd_xfer_msg(struct slim_controller *sctrl,
>  		if (!timeout) {
>  			dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x",
>  				txn->mc, txn->mt);
> +			mutex_unlock(&ctrl->tx_lock);
>  			return -ETIMEDOUT;
>  		}
>  	}
>
> +	mutex_unlock(&ctrl->tx_lock);
>  	return 0;
>  }
>
> @@ -1200,6 +1215,13 @@ static void qcom_slim_ngd_master_worker(struct work_struct *work)
>  	}
>  }
>
> +static int qcom_slim_ngd_update_device_status(struct device *dev, void *null)
> +{
> +	slim_report_absent(to_slim_device(dev));
> +
> +	return 0;
> +}
> +
>  static int qcom_slim_ngd_runtime_resume(struct device *dev)
>  {
>  	struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
> @@ -1267,7 +1289,7 @@ static int qcom_slim_ngd_qmi_new_server(struct qmi_handle *hdl,
>  	qmi->svc_info.sq_node = service->node;
>  	qmi->svc_info.sq_port = service->port;
>
> -	qcom_slim_ngd_enable(ctrl, true);
> +	complete(&ctrl->qmi_up);
>
>  	return 0;
>  }
> @@ -1280,10 +1302,9 @@ static void qcom_slim_ngd_qmi_del_server(struct qmi_handle *hdl,
>  	struct qcom_slim_ngd_ctrl *ctrl =
>  		container_of(qmi, struct qcom_slim_ngd_ctrl, qmi);
>
> +	reinit_completion(&ctrl->qmi_up);
>  	qmi->svc_info.sq_node = 0;
>  	qmi->svc_info.sq_port = 0;
> -
> -	qcom_slim_ngd_enable(ctrl, false);
>  }
>
>  static struct qmi_ops qcom_slim_ngd_qmi_svc_event_ops = {
> @@ -1333,6 +1354,64 @@ static const struct of_device_id qcom_slim_ngd_dt_match[] = {
>
>  MODULE_DEVICE_TABLE(of, qcom_slim_ngd_dt_match);
>
> +static void qcom_slim_ngd_down(struct qcom_slim_ngd_ctrl *ctrl)
> +{
> +	mutex_lock(&ctrl->ssr_lock);
> +	device_for_each_child(ctrl->ctrl.dev, NULL,
> +			      qcom_slim_ngd_update_device_status);
> +	qcom_slim_ngd_enable(ctrl, false);
> +	mutex_unlock(&ctrl->ssr_lock);
> +}
> +
> +static void qcom_slim_ngd_up_worker(struct work_struct *work)
> +{
> +	struct qcom_slim_ngd_ctrl *ctrl;
> +
> +	ctrl = container_of(work, struct qcom_slim_ngd_ctrl, ngd_up_work);
> +
> +	/* Make sure qmi service is up before continuing */
> +	wait_for_completion_interruptible(&ctrl->qmi_up);
> +
> +	mutex_lock(&ctrl->ssr_lock);
> +	qcom_slim_ngd_enable(ctrl, true);
> +	mutex_unlock(&ctrl->ssr_lock);
> +}
> +
> +static int qcom_slim_ngd_ssr_pdr_notify(struct qcom_slim_ngd_ctrl *ctrl,
> +					unsigned long action)
> +{
> +	switch (action) {
> +        case QCOM_SSR_BEFORE_SHUTDOWN:
> +		/* Make sure the last dma xfer is finished */
> +		mutex_lock(&ctrl->tx_lock);
> +		if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) {
> +			pm_runtime_get_noresume(ctrl->dev);
> +			ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN;
> +			qcom_slim_ngd_down(ctrl);
> +			qcom_slim_ngd_exit_dma(ctrl);
> +		}
> +		mutex_unlock(&ctrl->tx_lock);
> +                break;
> +        case QCOM_SSR_AFTER_POWERUP:
> +		schedule_work(&ctrl->ngd_up_work);
> +		break;
> +        default:
> +                break;
> +        }
> +
> +        return NOTIFY_OK;
> +}
> +
> +static int qcom_slim_ngd_ssr_notify(struct notifier_block *nb,
> +				    unsigned long action,
> +				    void *data)
> +{
> +	struct qcom_slim_ngd_ctrl *ctrl = container_of(nb,
> +					       struct qcom_slim_ngd_ctrl, nb);
> +
> +	return qcom_slim_ngd_ssr_pdr_notify(ctrl, action);
> +}
> +
>  static int of_qcom_slim_ngd_register(struct device *parent,
>  				     struct qcom_slim_ngd_ctrl *ctrl)
>  {
> @@ -1397,6 +1476,7 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
>  	}
>
>  	INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
> +	INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker);
>  	ctrl->mwq = create_singlethread_workqueue("ngd_master");
>  	if (!ctrl->mwq) {
>  		dev_err(&pdev->dev, "Failed to start master worker\n");
> @@ -1444,6 +1524,11 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>
> +	ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify;
> +	ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb);
> +	if (IS_ERR(ctrl->notifier))
> +		return PTR_ERR(ctrl->notifier);
> +
>  	ctrl->dev = dev;
>  	ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
>  	ctrl->framer.superfreq =
> @@ -1457,9 +1542,12 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
>  	ctrl->ctrl.wakeup = NULL;
>  	ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN;
>
> +	mutex_init(&ctrl->tx_lock);
> +	mutex_init(&ctrl->ssr_lock);
>  	spin_lock_init(&ctrl->tx_buf_lock);
>  	init_completion(&ctrl->reconf);
>  	init_completion(&ctrl->qmi.qmi_comp);
> +	init_completion(&ctrl->qmi_up);
>
>  	platform_driver_register(&qcom_slim_ngd_driver);
>  	return of_qcom_slim_ngd_register(dev, ctrl);
> @@ -1477,6 +1565,7 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev)
>  	struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
>
>  	pm_runtime_disable(&pdev->dev);
> +	qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb);
>  	qcom_slim_ngd_enable(ctrl, false);
>  	qcom_slim_ngd_exit_dma(ctrl);
>  	qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
> --
> 2.21.0

This makes NGD never come up if probed after ADSP is powered on since it registers its SSR notifier
after ADSP sent its after powerup notification.




[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux