slim: ngd: Handle Process Domain restart

Slimbus master component driver typically resides in a domain on remote
processor (ADSP). If that domain restarts, slimbus master driver
restarts reinitializing the slimbus HW.
Handle such process domain restart, and use subsystem restart if the
process domain restart is not available.

Change-Id: I253c33d07aad513a6621571e870e1d3f66a1b6a1
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
This commit is contained in:
Sagar Dharia 2016-02-26 17:06:33 -07:00 committed by Girish Mahadevan
parent 503eb88359
commit 6354fad32c
2 changed files with 103 additions and 39 deletions

View file

@ -26,6 +26,9 @@
#include <linux/of_slimbus.h>
#include <linux/timer.h>
#include <linux/msm-sps.h>
#include <soc/qcom/service-locator.h>
#include <soc/qcom/service-notifier.h>
#include <soc/qcom/subsystem_notif.h>
#include "slim-msm.h"
#define NGD_SLIM_NAME "ngd_msm_ctrl"
@ -84,7 +87,9 @@ enum ngd_status {
static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf);
static int ngd_slim_runtime_resume(struct device *device);
static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart);
static void ngd_adsp_down(struct msm_slim_ctrl *dev);
static void ngd_dom_down(struct msm_slim_ctrl *dev);
static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code,
void *_cmd);
static irqreturn_t ngd_slim_interrupt(int irq, void *d)
{
@ -162,7 +167,7 @@ static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code);
switch (code) {
case QMI_SERVER_ARRIVE:
schedule_work(&qmi->ssr_up);
schedule_work(&dev->dsp.dom_up);
break;
default:
break;
@ -170,31 +175,97 @@ static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
return 0;
}
static int dsp_ssr_notify_cb(struct notifier_block *n, unsigned long code,
static void ngd_reg_ssr(struct msm_slim_ctrl *dev)
{
int ret;
const char *subsys_name = NULL;
dev->dsp.dom_t = MSM_SLIM_DOM_NONE;
ret = of_property_read_string(dev->dev->of_node,
"qcom,subsys-name", &subsys_name);
if (ret)
subsys_name = "adsp";
dev->dsp.nb.notifier_call = dsp_domr_notify_cb;
dev->dsp.domr = subsys_notif_register_notifier(subsys_name,
&dev->dsp.nb);
if (IS_ERR_OR_NULL(dev->dsp.domr)) {
dev_err(dev->dev,
"subsys_notif_register_notifier failed %ld",
PTR_ERR(dev->dsp.domr));
return;
}
dev->dsp.dom_t = MSM_SLIM_DOM_SS;
SLIM_INFO(dev, "reg-SSR with:%s, PDR not available\n",
subsys_name);
}
static int dsp_domr_notify_cb(struct notifier_block *n, unsigned long code,
void *_cmd)
{
int cur = -1;
struct msm_slim_ss *dsp = container_of(n, struct msm_slim_ss, nb);
struct msm_slim_ctrl *dev = container_of(dsp, struct msm_slim_ctrl,
dsp);
struct pd_qmi_client_data *reg;
SLIM_INFO(dev, "SLIM DSP SSR/PDR notify cb:0x%lx, type:%d\n",
code, dsp->dom_t);
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
SLIM_INFO(dev, "SLIM DSP SSR notify cb:%lu\n", code);
case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
/* wait for current transaction */
mutex_lock(&dev->tx_lock);
/* make sure autosuspend is not called until ADSP comes up*/
pm_runtime_get_noresume(dev->dev);
dev->state = MSM_CTRL_DOWN;
msm_slim_sps_exit(dev, false);
ngd_adsp_down(dev);
ngd_dom_down(dev);
mutex_unlock(&dev->tx_lock);
break;
case LOCATOR_UP:
reg = _cmd;
dev->dsp.domr = service_notif_register_notifier(
reg->domain_list->name,
reg->domain_list->instance_id,
&dev->dsp.nb,
&cur);
SLIM_INFO(dev, "reg-PD client:%s with service:%s\n",
reg->client_name, reg->service_name);
SLIM_INFO(dev, "reg-PD dom:%s instance:%d, cur:%d\n",
reg->domain_list->name,
reg->domain_list->instance_id, cur);
if (IS_ERR_OR_NULL(dev->dsp.domr))
ngd_reg_ssr(dev);
else
dev->dsp.dom_t = MSM_SLIM_DOM_PD;
break;
case LOCATOR_DOWN:
ngd_reg_ssr(dev);
default:
break;
}
return NOTIFY_DONE;
}
static void ngd_dom_init(struct msm_slim_ctrl *dev)
{
struct pd_qmi_client_data reg;
int ret;
memset(&reg, 0, sizeof(struct pd_qmi_client_data));
dev->dsp.nb.priority = 4;
dev->dsp.nb.notifier_call = dsp_domr_notify_cb;
scnprintf(reg.client_name, QMI_SERVREG_LOC_NAME_LENGTH_V01, "appsngd%d",
dev->ctrl.nr);
scnprintf(reg.service_name, QMI_SERVREG_LOC_NAME_LENGTH_V01,
"avs/audio");
ret = get_service_location(reg.client_name, reg.service_name,
&dev->dsp.nb);
if (ret)
ngd_reg_ssr(dev);
}
static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
void *_cmd)
{
@ -1492,6 +1563,7 @@ static int ngd_notify_slaves(void *data)
* controller is up
*/
slim_ctrl_add_boarddevs(&dev->ctrl);
ngd_dom_init(dev);
} else {
slim_framer_booted(ctrl);
}
@ -1516,7 +1588,7 @@ static int ngd_notify_slaves(void *data)
return 0;
}
static void ngd_adsp_down(struct msm_slim_ctrl *dev)
static void ngd_dom_down(struct msm_slim_ctrl *dev)
{
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
@ -1530,12 +1602,12 @@ static void ngd_adsp_down(struct msm_slim_ctrl *dev)
mutex_unlock(&dev->ssr_lock);
}
static void ngd_adsp_up(struct work_struct *work)
static void ngd_dom_up(struct work_struct *work)
{
struct msm_slim_qmi *qmi =
container_of(work, struct msm_slim_qmi, ssr_up);
struct msm_slim_ss *dsp =
container_of(work, struct msm_slim_ss, dom_up);
struct msm_slim_ctrl *dev =
container_of(qmi, struct msm_slim_ctrl, qmi);
container_of(dsp, struct msm_slim_ctrl, dsp);
mutex_lock(&dev->ssr_lock);
ngd_slim_enable(dev, true);
mutex_unlock(&dev->ssr_lock);
@ -1572,7 +1644,7 @@ static int ngd_slim_probe(struct platform_device *pdev)
struct resource *irq, *bam_irq;
bool rxreg_access = false;
bool slim_mdm = false;
const char *ext_modem_id = NULL, *subsys_name = NULL;
const char *ext_modem_id = NULL;
slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"slimbus_physical");
@ -1756,33 +1828,17 @@ static int ngd_slim_probe(struct platform_device *pdev)
pm_runtime_set_suspended(dev->dev);
pm_runtime_enable(dev->dev);
dev->dsp.nb.priority = 4;
ret = of_property_read_string(pdev->dev.of_node,
"qcom,subsys-name", &subsys_name);
if (ret) {
dev->dsp.nb.notifier_call = dsp_ssr_notify_cb;
dev->dsp.ssr = subsys_notif_register_notifier("adsp",
&dev->dsp.nb);
} else {
dev->dsp.nb.notifier_call = dsp_ssr_notify_cb;
dev->dsp.ssr = subsys_notif_register_notifier(subsys_name,
&dev->dsp.nb);
}
if (IS_ERR_OR_NULL(dev->dsp.ssr))
dev_err(dev->dev,
"subsys_notif_register_notifier failed %p",
dev->dsp.ssr);
if (slim_mdm) {
dev->ext_mdm.nb.notifier_call = mdm_ssr_notify_cb;
dev->ext_mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
dev->ext_mdm.domr = subsys_notif_register_notifier(ext_modem_id,
&dev->ext_mdm.nb);
if (IS_ERR_OR_NULL(dev->ext_mdm.ssr))
if (IS_ERR_OR_NULL(dev->ext_mdm.domr))
dev_err(dev->dev,
"subsys_notif_register_notifier failed %p",
dev->ext_mdm.ssr);
dev->ext_mdm.domr);
}
INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
INIT_WORK(&dev->dsp.dom_up, ngd_dom_up);
dev->qmi.nb.notifier_call = ngd_qmi_available;
pm_runtime_get_noresume(dev->dev);
@ -1837,11 +1893,14 @@ static int ngd_slim_remove(struct platform_device *pdev)
SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
pm_runtime_disable(&pdev->dev);
if (!IS_ERR_OR_NULL(dev->dsp.ssr))
subsys_notif_unregister_notifier(dev->dsp.ssr,
if (dev->dsp.dom_t == MSM_SLIM_DOM_SS)
subsys_notif_unregister_notifier(dev->dsp.domr,
&dev->dsp.nb);
if (!IS_ERR_OR_NULL(dev->ext_mdm.ssr))
subsys_notif_unregister_notifier(dev->ext_mdm.ssr,
if (dev->dsp.dom_t == MSM_SLIM_DOM_PD)
service_notif_unregister_notifier(dev->dsp.domr,
&dev->dsp.nb);
if (!IS_ERR_OR_NULL(dev->ext_mdm.domr))
subsys_notif_unregister_notifier(dev->ext_mdm.domr,
&dev->ext_mdm.nb);
kfree(dev->bulk.base);
free_irq(dev->irq, dev);

View file

@ -16,7 +16,6 @@
#include <linux/irq.h>
#include <linux/kthread.h>
#include <soc/qcom/msm_qmi_interface.h>
#include <soc/qcom/subsystem_notif.h>
#include <linux/ipc_logging.h>
/* Per spec.max 40 bytes per received message */
@ -229,14 +228,20 @@ struct msm_slim_qmi {
struct kthread_worker kworker;
struct completion qmi_comp;
struct notifier_block nb;
struct work_struct ssr_down;
struct work_struct ssr_up;
};
enum msm_slim_dom {
MSM_SLIM_DOM_NONE,
MSM_SLIM_DOM_PD,
MSM_SLIM_DOM_SS,
};
struct msm_slim_ss {
struct notifier_block nb;
void *ssr;
void *domr;
enum msm_ctrl_state state;
struct work_struct dom_up;
enum msm_slim_dom dom_t;
};
struct msm_slim_pdata {