mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 22:23:14 -04:00
Merge "soc: qcom: pmic_glink: add protection domain restart (PDR) support"
This commit is contained in:
commit
55aef73ec8
3 changed files with 162 additions and 6 deletions
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <soc/qcom/subsystem_notif.h>
|
||||
#include <soc/qcom/service-locator.h>
|
||||
#include <soc/qcom/service-notifier.h>
|
||||
#include <linux/soc/qcom/pmic_glink.h>
|
||||
|
||||
/**
|
||||
|
|
@ -45,6 +47,12 @@
|
|||
* @subsys_name: subsystem name from which SSR notifications should
|
||||
* be handled and notified to the clients
|
||||
* @subsys_handle: handle to subsystem notifier
|
||||
* @pdr_handle: handle to PDR notifier
|
||||
* @pdr_service_name: protection domain service name
|
||||
* @pdr_path_name: protection domain path name
|
||||
* @serv_loc_nb: notifier block for service locator
|
||||
* @pdr_nb: notifier block for protection domain restart
|
||||
* @pdr_state: protection domain service state
|
||||
*/
|
||||
struct pmic_glink_dev {
|
||||
struct rpmsg_device *rpdev;
|
||||
|
|
@ -68,6 +76,12 @@ struct pmic_glink_dev {
|
|||
struct notifier_block ssr_nb;
|
||||
const char *subsys_name;
|
||||
void *subsys_handle;
|
||||
void *pdr_handle;
|
||||
const char *pdr_service_name;
|
||||
const char *pdr_path_name;
|
||||
struct notifier_block serv_loc_nb;
|
||||
struct notifier_block pdr_nb;
|
||||
atomic_t pdr_state;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -148,6 +162,99 @@ static int pmic_glink_ssr_notifier_cb(struct notifier_block *nb,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int pmic_glink_pdr_notifier_cb(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
{
|
||||
struct pmic_glink_dev *pgdev = container_of(nb, struct pmic_glink_dev,
|
||||
pdr_nb);
|
||||
|
||||
pr_debug("code: %#lx\n", code);
|
||||
|
||||
switch (code) {
|
||||
case SERVREG_NOTIF_SERVICE_STATE_EARLY_DOWN_V01:
|
||||
pr_debug("PD state down for %s\n", pgdev->pdr_service_name);
|
||||
pmic_glink_notify_clients(pgdev, PMIC_GLINK_STATE_DOWN);
|
||||
atomic_set(&pgdev->pdr_state, code);
|
||||
break;
|
||||
case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
|
||||
/*
|
||||
* PMIC Glink clients have been notified already. So do
|
||||
* nothing here.
|
||||
*/
|
||||
break;
|
||||
case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
|
||||
/*
|
||||
* Do not notify PMIC Glink clients here but rather from
|
||||
* pmic_glink_init_work which will be run only after rpmsg
|
||||
* driver is probed and Glink communication is up.
|
||||
*/
|
||||
pr_debug("PD state up for %s\n", pgdev->pdr_service_name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void pmic_glink_register_pdr_service(struct pmic_glink_dev *pgdev,
|
||||
struct pd_qmi_client_data *pdr)
|
||||
{
|
||||
int i, curr_state;
|
||||
|
||||
if (pgdev->pdr_handle)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pdr->total_domains; i++)
|
||||
if (!strcmp(pdr->domain_list[i].name, pgdev->pdr_path_name))
|
||||
break;
|
||||
|
||||
if (i >= pdr->total_domains) {
|
||||
pr_err("PDR service %s is not available\n",
|
||||
pgdev->pdr_service_name);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("matching domain: %s instance id: %u\n",
|
||||
pdr->domain_list[i].name, pdr->domain_list[i].instance_id);
|
||||
pgdev->pdr_nb.notifier_call = pmic_glink_pdr_notifier_cb;
|
||||
pgdev->pdr_handle = service_notif_register_notifier(
|
||||
pdr->domain_list[i].name,
|
||||
pdr->domain_list[i].instance_id,
|
||||
&pgdev->pdr_nb, &curr_state);
|
||||
if (IS_ERR(pgdev->pdr_handle)) {
|
||||
pr_err("failed to register with service notifier rc=%ld\n",
|
||||
PTR_ERR(pgdev->pdr_handle));
|
||||
pgdev->pdr_handle = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_set(&pgdev->pdr_state, curr_state);
|
||||
pr_debug("current PDR state for %s is %d\n", pgdev->pdr_service_name,
|
||||
curr_state);
|
||||
}
|
||||
|
||||
static int pmic_glink_serv_loc_cb(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
{
|
||||
struct pmic_glink_dev *pgdev = container_of(nb, struct pmic_glink_dev,
|
||||
serv_loc_nb);
|
||||
struct pd_qmi_client_data *pdr = data;
|
||||
|
||||
pr_debug("code: %#lx\n", code);
|
||||
|
||||
if (code == LOCATOR_DOWN) {
|
||||
pr_warn("PDR service locator for client: %s service: %s is down\n",
|
||||
pdr->client_name, pdr->service_name);
|
||||
} else if (code == LOCATOR_UP) {
|
||||
pr_debug("PDR service locator for client: %s service: %s is up\n",
|
||||
pdr->client_name, pdr->service_name);
|
||||
pmic_glink_register_pdr_service(pgdev, pdr);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct pmic_glink_dev *get_pmic_glink_from_dev(struct device *dev)
|
||||
{
|
||||
struct pmic_glink_dev *tmp, *pos;
|
||||
|
|
@ -494,8 +601,12 @@ static void pmic_glink_init_work(struct work_struct *work)
|
|||
struct device *dev = pgdev->dev;
|
||||
int rc;
|
||||
|
||||
if (atomic_read(&pgdev->prev_state) == SUBSYS_BEFORE_SHUTDOWN) {
|
||||
if (atomic_read(&pgdev->pdr_state) ==
|
||||
SERVREG_NOTIF_SERVICE_STATE_EARLY_DOWN_V01 ||
|
||||
atomic_read(&pgdev->prev_state) == SUBSYS_BEFORE_SHUTDOWN) {
|
||||
pmic_glink_notify_clients(pgdev, PMIC_GLINK_STATE_UP);
|
||||
atomic_set(&pgdev->pdr_state,
|
||||
SERVREG_NOTIF_SERVICE_STATE_UP_V01);
|
||||
atomic_set(&pgdev->prev_state, SUBSYS_AFTER_POWERUP);
|
||||
}
|
||||
|
||||
|
|
@ -554,6 +665,34 @@ static int pmic_glink_probe(struct platform_device *pdev)
|
|||
of_property_read_string(dev->of_node, "qcom,subsys-name",
|
||||
&pgdev->subsys_name);
|
||||
|
||||
if (of_find_property(dev->of_node, "qcom,protection-domain", NULL)) {
|
||||
rc = of_property_read_string_index(dev->of_node,
|
||||
"qcom,protection-domain", 0,
|
||||
&pgdev->pdr_service_name);
|
||||
if (rc) {
|
||||
pr_err("Failed to get PDR service name rc=%d\n", rc);
|
||||
return rc;
|
||||
} else if (strlen(pgdev->pdr_service_name) >
|
||||
QMI_SERVREG_LOC_NAME_LENGTH_V01) {
|
||||
pr_err("PDR service name %s is too long\n",
|
||||
pgdev->pdr_service_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_property_read_string_index(dev->of_node,
|
||||
"qcom,protection-domain", 1,
|
||||
&pgdev->pdr_path_name);
|
||||
if (rc) {
|
||||
pr_err("Failed to get PDR path name rc=%d\n", rc);
|
||||
return rc;
|
||||
} else if (strlen(pgdev->pdr_path_name) >
|
||||
QMI_SERVREG_LOC_NAME_LENGTH_V01) {
|
||||
pr_err("PDR path name %s is too long\n",
|
||||
pgdev->pdr_path_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pgdev->rx_wq = create_singlethread_workqueue("pmic_glink_rx");
|
||||
if (!pgdev->rx_wq) {
|
||||
pr_err("Failed to create pmic_glink_rx wq\n");
|
||||
|
|
@ -569,6 +708,7 @@ static int pmic_glink_probe(struct platform_device *pdev)
|
|||
mutex_init(&pgdev->client_lock);
|
||||
idr_init(&pgdev->client_idr);
|
||||
atomic_set(&pgdev->prev_state, SUBSYS_BEFORE_POWERUP);
|
||||
atomic_set(&pgdev->pdr_state, SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01);
|
||||
|
||||
if (pgdev->subsys_name) {
|
||||
pgdev->ssr_nb.notifier_call = pmic_glink_ssr_notifier_cb;
|
||||
|
|
@ -583,6 +723,19 @@ static int pmic_glink_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (pgdev->pdr_service_name) {
|
||||
pgdev->serv_loc_nb.notifier_call = pmic_glink_serv_loc_cb;
|
||||
rc = get_service_location(pgdev->channel_name,
|
||||
pgdev->pdr_service_name, &pgdev->serv_loc_nb);
|
||||
if (rc < 0) {
|
||||
pr_err("Failed in get_service_location rc=%d\n", rc);
|
||||
goto error_service;
|
||||
}
|
||||
|
||||
pr_debug("Registering PDR for path_name: %s service_name: %s\n",
|
||||
pgdev->pdr_path_name, pgdev->pdr_service_name);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, pgdev);
|
||||
pgdev->dev = dev;
|
||||
|
||||
|
|
@ -593,6 +746,8 @@ static int pmic_glink_probe(struct platform_device *pdev)
|
|||
pr_debug("%s probed successfully\n", pgdev->channel_name);
|
||||
return 0;
|
||||
|
||||
error_service:
|
||||
subsys_notif_unregister_notifier(pgdev->subsys_handle, &pgdev->ssr_nb);
|
||||
error_subsys:
|
||||
idr_destroy(&pgdev->client_idr);
|
||||
destroy_workqueue(pgdev->rx_wq);
|
||||
|
|
@ -603,6 +758,7 @@ static int pmic_glink_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct pmic_glink_dev *pgdev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
service_notif_unregister_notifier(pgdev->pdr_handle, &pgdev->pdr_nb);
|
||||
subsys_notif_unregister_notifier(pgdev->subsys_handle, &pgdev->ssr_nb);
|
||||
device_init_wakeup(pgdev->dev, false);
|
||||
debugfs_remove_recursive(pgdev->debugfs_dir);
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ inited:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int get_service_location(char *client_name, char *service_name,
|
||||
int get_service_location(const char *client_name, const char *service_name,
|
||||
struct notifier_block *locator_nb)
|
||||
{
|
||||
struct pd_qmi_client_data *pqcd;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2016, 2018-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2015-2016, 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Process Domain Service Locator API header
|
||||
|
|
@ -63,7 +63,7 @@ struct notifier_block;
|
|||
* by the service locator.
|
||||
* Returns 0 on success; otherwise a value < 0 if no valid subsystem is found.
|
||||
*/
|
||||
int get_service_location(char *client_name, char *service_name,
|
||||
int get_service_location(const char *client_name, const char *service_name,
|
||||
struct notifier_block *locator_nb);
|
||||
|
||||
/*
|
||||
|
|
@ -77,8 +77,8 @@ int find_subsys(const char *pd_path, char *subsys);
|
|||
|
||||
#else
|
||||
|
||||
static inline int get_service_location(char *client_name,
|
||||
char *service_name, struct notifier_block *locator_nb)
|
||||
static inline int get_service_location(const char *client_name,
|
||||
const char *service_name, struct notifier_block *locator_nb)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue