slimbus: Add support for report-absent and device-down notification
device_down callback will be called when the device sends
report-absent message per slimbus specification, or if the device
cannot be reached due to some other reason (e.g. bus going down).
device_up will be called when the device sends reports present again.
Change-Id: Ie48c2e3891b55cb1ec9c675a32cdb0a568fdcc18
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 205bf37..0c9959c 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -998,7 +998,6 @@
container_of(qmi, struct msm_slim_ctrl, qmi);
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
- int i;
ngd_slim_enable(dev, false);
/* disconnect BAM pipes */
@@ -1007,14 +1006,9 @@
if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
dev->use_tx_msgqs = MSM_MSGQ_DOWN;
msm_slim_sps_exit(dev, false);
- mutex_lock(&ctrl->m_ctrl);
/* device up should be called again after SSR */
list_for_each_entry(sbdev, &ctrl->devs, dev_list)
- sbdev->notified = false;
- /* invalidate logical addresses */
- for (i = 0; i < ctrl->num_dev; i++)
- ctrl->addrt[i].valid = false;
- mutex_unlock(&ctrl->m_ctrl);
+ slim_report_absent(sbdev);
pr_info("SLIM ADSP SSR (DOWN) done");
}
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 201470f..b074289 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -286,20 +286,41 @@
.release = slim_dev_release,
};
-static void slim_report_present(struct work_struct *work)
+static void slim_report(struct work_struct *work)
{
u8 laddr;
- int ret;
+ int ret, i;
struct slim_driver *sbdrv;
struct slim_device *sbdev =
container_of(work, struct slim_device, wd);
- if (sbdev->notified || !sbdev->dev.driver)
+ struct slim_controller *ctrl = sbdev->ctrl;
+ if (!sbdev->dev.driver)
+ return;
+ /* check if device-up or down needs to be called */
+ mutex_lock(&ctrl->m_ctrl);
+ /* address no longer valid, means device reported absent */
+ for (i = 0; i < ctrl->num_dev; i++) {
+ if (sbdev->laddr == ctrl->addrt[i].laddr &&
+ ctrl->addrt[i].valid == false &&
+ sbdev->notified)
+ break;
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+ sbdrv = to_slim_driver(sbdev->dev.driver);
+ if (i < ctrl->num_dev) {
+ sbdev->notified = false;
+ if (sbdrv->device_down)
+ sbdrv->device_down(sbdev);
+ return;
+ }
+ if (sbdev->notified)
return;
ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
- sbdrv = to_slim_driver(sbdev->dev.driver);
- if (!ret && sbdrv->device_up) {
- sbdev->notified = true;
- sbdrv->device_up(sbdev);
+ if (!ret) {
+ if (sbdrv)
+ sbdev->notified = true;
+ if (sbdrv->device_up)
+ sbdrv->device_up(sbdev);
}
}
@@ -322,7 +343,7 @@
INIT_LIST_HEAD(&sbdev->mark_define);
INIT_LIST_HEAD(&sbdev->mark_suspend);
INIT_LIST_HEAD(&sbdev->mark_removal);
- INIT_WORK(&sbdev->wd, slim_report_present);
+ INIT_WORK(&sbdev->wd, slim_report);
mutex_lock(&ctrl->m_ctrl);
list_add_tail(&sbdev->dev_list, &ctrl->devs);
mutex_unlock(&ctrl->m_ctrl);
@@ -604,6 +625,31 @@
EXPORT_SYMBOL_GPL(slim_add_numbered_controller);
/*
+ * slim_report_absent: Controller calls this function when a device
+ * reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev)
+{
+ struct slim_controller *ctrl;
+ int i;
+ if (!sbdev)
+ return;
+ ctrl = sbdev->ctrl;
+ if (!ctrl)
+ return;
+ /* invalidate logical addresses */
+ mutex_lock(&ctrl->m_ctrl);
+ for (i = 0; i < ctrl->num_dev; i++) {
+ if (sbdev->laddr == ctrl->addrt[i].laddr)
+ ctrl->addrt[i].valid = false;
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+ queue_work(ctrl->wq, &sbdev->wd);
+}
+EXPORT_SYMBOL(slim_report_absent);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 132135e..cba4394 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -581,6 +581,11 @@
* @shutdown: Standard shutdown callback used during powerdown/halt.
* @suspend: Standard suspend callback used during system suspend
* @resume: Standard resume callback used during system resume
+ * @device_up: This callback is called when the device reports present and
+ * gets a logical address assigned to it
+ * @device_down: This callback is called when device reports absent, or the
+ * bus goes down. Device will report present when bus is up and
+ * device_up callback will be called again when that happens
* @driver: Slimbus device drivers should initialize name and owner field of
* this structure
* @id_table: List of slimbus devices supported by this driver
@@ -593,6 +598,8 @@
pm_message_t pmesg);
int (*resume)(struct slim_device *sldev);
int (*device_up)(struct slim_device *sldev);
+ int (*device_down)
+ (struct slim_device *sldev);
struct device_driver driver;
const struct slim_device_id *id_table;
@@ -1022,6 +1029,13 @@
u8 e_len, u8 *laddr, bool valid);
/*
+ * slim_report_absent: Controller calls this function when a device
+ * reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or that sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle