Message ID | 20230908-topic-sm8550-upstream-pdcharge-ulog-v1-1-d1b16b02ced2@linaro.org |
---|---|
State | Accepted |
Commit | 086fdb48bc65d6fde0f0e7d42dbfb3c00ea52628 |
Headers | show |
Series | soc: qcom: add ADSP PDCharger ULOG driver | expand |
On Fri, 8 Sept 2023 at 13:53, Neil Armstrong <neil.armstrong@linaro.org> wrote: > > The Qualcomm PMIC PDCharger ULOG driver provides access to logs of > the ADSP firmware PDCharger module in charge of Battery and Power > Delivery on modern systems. > > Implement trace events as a simple rpmsg driver with an 1s interval > to retrieve the messages. > > The interface allows filtering the messages by subsystem and priority > level, this could be implemented later on. > > Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> > --- > drivers/soc/qcom/Kconfig | 12 +++ > drivers/soc/qcom/Makefile | 1 + > drivers/soc/qcom/pmic_pdcharger_ulog.c | 166 +++++++++++++++++++++++++++++++++ > drivers/soc/qcom/pmic_pdcharger_ulog.h | 36 +++++++ > 4 files changed, 215 insertions(+)
Hi Bjorn, On 08/09/2023 12:53, Neil Armstrong wrote: > The Qualcomm PMIC PDCharger ULOG driver provides access to logs of > the ADSP firmware PDCharger module in charge of Battery and Power > Delivery on modern systems. > > Implement trace events as a simple rpmsg driver with an 1s interval > to retrieve the messages. > > The interface allows filtering the messages by subsystem and priority > level, this could be implemented later on. Any thoughts on this? It's pretty handy to debug PDCharger firmware events, even more with enhanced usage of UCSI. Neil > > Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> > --- > drivers/soc/qcom/Kconfig | 12 +++ > drivers/soc/qcom/Makefile | 1 + > drivers/soc/qcom/pmic_pdcharger_ulog.c | 166 +++++++++++++++++++++++++++++++++ > drivers/soc/qcom/pmic_pdcharger_ulog.h | 36 +++++++ > 4 files changed, 215 insertions(+) > > diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig > index e597799e8121..5f63df3d5d6f 100644 > --- a/drivers/soc/qcom/Kconfig > +++ b/drivers/soc/qcom/Kconfig > @@ -93,6 +93,18 @@ config QCOM_PDR_HELPERS > select QCOM_QMI_HELPERS > depends on NET > > +config QCOM_PMIC_PDCHARGER_ULOG > + tristate "Qualcomm PMIC PDCharger ULOG driver" > + depends on RPMSG > + depends on EVENT_TRACING > + help > + The Qualcomm PMIC PDCharger ULOG driver provides access to logs of > + the ADSP firmware PDCharger module in charge of Battery and Power > + Delivery on modern systems. > + > + Say yes here to support PDCharger ULOG event tracing on modern > + Qualcomm platforms. > + > config QCOM_PMIC_GLINK > tristate "Qualcomm PMIC GLINK driver" > depends on RPMSG > diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile > index 99114c71092b..44f6efe9a48c 100644 > --- a/drivers/soc/qcom/Makefile > +++ b/drivers/soc/qcom/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_QCOM_OCMEM) += ocmem.o > obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o > obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o > obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o > +obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o > obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o > qmi_helpers-y += qmi_encdec.o qmi_interface.o > obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o > diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.c b/drivers/soc/qcom/pmic_pdcharger_ulog.c > new file mode 100644 > index 000000000000..f1aaacf05005 > --- /dev/null > +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.c > @@ -0,0 +1,166 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2019-2022, The Linux Foundation. All rights reserved. > + * Copyright (c) 2023, Linaro Ltd > + */ > +#include <linux/of_device.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/rpmsg.h> > +#include <linux/slab.h> > +#include <linux/soc/qcom/pdr.h> > +#include <linux/debugfs.h> > + > +#define CREATE_TRACE_POINTS > +#include "pmic_pdcharger_ulog.h" > + > +#define MSG_OWNER_CHG_ULOG 32778 > +#define MSG_TYPE_REQ_RESP 1 > + > +#define GET_CHG_ULOG_REQ 0x18 > +#define SET_CHG_ULOG_PROP_REQ 0x19 > + > +#define LOG_DEFAULT_TIME_MS 1000 > + > +#define MAX_ULOG_SIZE 8192 > + > +struct pmic_pdcharger_ulog_hdr { > + __le32 owner; > + __le32 type; > + __le32 opcode; > +}; > + > +struct pmic_pdcharger_ulog { > + struct rpmsg_device *rpdev; > + struct delayed_work ulog_work; > +}; > + > +struct get_ulog_req_msg { > + struct pmic_pdcharger_ulog_hdr hdr; > + u32 log_size; > +}; > + > +struct get_ulog_resp_msg { > + struct pmic_pdcharger_ulog_hdr hdr; > + u8 buf[MAX_ULOG_SIZE]; > +}; > + > +static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len) > +{ > + return rpmsg_send(pg->rpdev->ept, data, len); > +} > + > +static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg) > +{ > + struct get_ulog_req_msg req_msg = { > + .hdr = { > + .owner = MSG_OWNER_CHG_ULOG, > + .type = MSG_TYPE_REQ_RESP, > + .opcode = GET_CHG_ULOG_REQ > + }, > + .log_size = MAX_ULOG_SIZE > + }; > + > + return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg)); > +} > + > +static void pmic_pdcharger_ulog_work(struct work_struct *work) > +{ > + struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog, > + ulog_work.work); > + int rc; > + > + rc = pmic_pdcharger_ulog_request(pg); > + if (rc) { > + dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc); > + return; > + } > +} > + > +static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg, > + struct get_ulog_resp_msg *resp_msg, > + size_t len) > +{ > + char *token, *buf = resp_msg->buf; > + > + if (len != sizeof(*resp_msg)) { > + dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n", > + sizeof(*resp_msg), len); > + return; > + } > + > + buf[MAX_ULOG_SIZE - 1] = '\0'; > + > + do { > + token = strsep((char **)&buf, "\n"); > + if (token && strlen(token)) > + trace_pmic_pdcharger_ulog_msg(token); > + } while (token); > +} > + > +static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data, > + int len, void *priv, u32 addr) > +{ > + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); > + struct pmic_pdcharger_ulog_hdr *hdr = data; > + u32 opcode; > + > + opcode = le32_to_cpu(hdr->opcode); > + > + switch (opcode) { > + case GET_CHG_ULOG_REQ: > + schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS)); > + pmic_pdcharger_ulog_handle_message(pg, data, len); > + break; > + default: > + dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode); > + break; > + } > + > + return 0; > +} > + > +static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev) > +{ > + struct pmic_pdcharger_ulog *pg; > + struct device *dev = &rpdev->dev; > + > + pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL); > + if (!pg) > + return -ENOMEM; > + > + pg->rpdev = rpdev; > + INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work); > + > + dev_set_drvdata(dev, pg); > + > + pmic_pdcharger_ulog_request(pg); > + > + return 0; > +} > + > +static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev) > +{ > + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); > + > + cancel_delayed_work_sync(&pg->ulog_work); > +} > + > +static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = { > + { "PMIC_LOGS_ADSP_APPS" }, > + {} > +}; > + > +static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = { > + .probe = pmic_pdcharger_ulog_rpmsg_probe, > + .remove = pmic_pdcharger_ulog_rpmsg_remove, > + .callback = pmic_pdcharger_ulog_rpmsg_callback, > + .id_table = pmic_pdcharger_ulog_rpmsg_id_match, > + .drv = { > + .name = "qcom_pmic_pdcharger_ulog_rpmsg", > + }, > +}; > + > +module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver); > +MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.h b/drivers/soc/qcom/pmic_pdcharger_ulog.h > new file mode 100644 > index 000000000000..9d5d9af4fbe4 > --- /dev/null > +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.h > @@ -0,0 +1,36 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2023, Linaro Ltd > + */ > + > +#if !defined(_TRACE_PMIC_PDCHARGER_ULOG_H) || defined(TRACE_HEADER_MULTI_READ) > +#define _TRACE_PMIC_PDCHARGER_ULOG_H > + > +#include <linux/tracepoint.h> > + > +#undef TRACE_SYSTEM > +#define TRACE_SYSTEM pmic_pdcharger_ulog > + > +TRACE_EVENT(pmic_pdcharger_ulog_msg, > + TP_PROTO(char *msg), > + TP_ARGS(msg), > + TP_STRUCT__entry( > + __string(msg, msg) > + ), > + TP_fast_assign( > + __assign_str(msg, msg); > + ), > + TP_printk("%s", __get_str(msg)) > +); > + > +#endif /* _TRACE_PMIC_PDCHARGER_ULOG_H */ > + > +/* This part must be outside protection */ > + > +#undef TRACE_INCLUDE_PATH > +#define TRACE_INCLUDE_PATH . > + > +#undef TRACE_INCLUDE_FILE > +#define TRACE_INCLUDE_FILE pmic_pdcharger_ulog > + > +#include <trace/define_trace.h> > > --- > base-commit: 2dde18cd1d8fac735875f2e4987f11817cc0bc2c > change-id: 20230908-topic-sm8550-upstream-pdcharge-ulog-21ece9292474 > > Best regards,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e597799e8121..5f63df3d5d6f 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -93,6 +93,18 @@ config QCOM_PDR_HELPERS select QCOM_QMI_HELPERS depends on NET +config QCOM_PMIC_PDCHARGER_ULOG + tristate "Qualcomm PMIC PDCharger ULOG driver" + depends on RPMSG + depends on EVENT_TRACING + help + The Qualcomm PMIC PDCharger ULOG driver provides access to logs of + the ADSP firmware PDCharger module in charge of Battery and Power + Delivery on modern systems. + + Say yes here to support PDCharger ULOG event tracing on modern + Qualcomm platforms. + config QCOM_PMIC_GLINK tristate "Qualcomm PMIC GLINK driver" depends on RPMSG diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 99114c71092b..44f6efe9a48c 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_QCOM_OCMEM) += ocmem.o obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o +obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o qmi_helpers-y += qmi_encdec.o qmi_interface.o obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.c b/drivers/soc/qcom/pmic_pdcharger_ulog.c new file mode 100644 index 000000000000..f1aaacf05005 --- /dev/null +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd + */ +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rpmsg.h> +#include <linux/slab.h> +#include <linux/soc/qcom/pdr.h> +#include <linux/debugfs.h> + +#define CREATE_TRACE_POINTS +#include "pmic_pdcharger_ulog.h" + +#define MSG_OWNER_CHG_ULOG 32778 +#define MSG_TYPE_REQ_RESP 1 + +#define GET_CHG_ULOG_REQ 0x18 +#define SET_CHG_ULOG_PROP_REQ 0x19 + +#define LOG_DEFAULT_TIME_MS 1000 + +#define MAX_ULOG_SIZE 8192 + +struct pmic_pdcharger_ulog_hdr { + __le32 owner; + __le32 type; + __le32 opcode; +}; + +struct pmic_pdcharger_ulog { + struct rpmsg_device *rpdev; + struct delayed_work ulog_work; +}; + +struct get_ulog_req_msg { + struct pmic_pdcharger_ulog_hdr hdr; + u32 log_size; +}; + +struct get_ulog_resp_msg { + struct pmic_pdcharger_ulog_hdr hdr; + u8 buf[MAX_ULOG_SIZE]; +}; + +static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len) +{ + return rpmsg_send(pg->rpdev->ept, data, len); +} + +static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg) +{ + struct get_ulog_req_msg req_msg = { + .hdr = { + .owner = MSG_OWNER_CHG_ULOG, + .type = MSG_TYPE_REQ_RESP, + .opcode = GET_CHG_ULOG_REQ + }, + .log_size = MAX_ULOG_SIZE + }; + + return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg)); +} + +static void pmic_pdcharger_ulog_work(struct work_struct *work) +{ + struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog, + ulog_work.work); + int rc; + + rc = pmic_pdcharger_ulog_request(pg); + if (rc) { + dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc); + return; + } +} + +static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg, + struct get_ulog_resp_msg *resp_msg, + size_t len) +{ + char *token, *buf = resp_msg->buf; + + if (len != sizeof(*resp_msg)) { + dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n", + sizeof(*resp_msg), len); + return; + } + + buf[MAX_ULOG_SIZE - 1] = '\0'; + + do { + token = strsep((char **)&buf, "\n"); + if (token && strlen(token)) + trace_pmic_pdcharger_ulog_msg(token); + } while (token); +} + +static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 addr) +{ + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); + struct pmic_pdcharger_ulog_hdr *hdr = data; + u32 opcode; + + opcode = le32_to_cpu(hdr->opcode); + + switch (opcode) { + case GET_CHG_ULOG_REQ: + schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS)); + pmic_pdcharger_ulog_handle_message(pg, data, len); + break; + default: + dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode); + break; + } + + return 0; +} + +static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct pmic_pdcharger_ulog *pg; + struct device *dev = &rpdev->dev; + + pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL); + if (!pg) + return -ENOMEM; + + pg->rpdev = rpdev; + INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work); + + dev_set_drvdata(dev, pg); + + pmic_pdcharger_ulog_request(pg); + + return 0; +} + +static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev); + + cancel_delayed_work_sync(&pg->ulog_work); +} + +static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = { + { "PMIC_LOGS_ADSP_APPS" }, + {} +}; + +static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = { + .probe = pmic_pdcharger_ulog_rpmsg_probe, + .remove = pmic_pdcharger_ulog_rpmsg_remove, + .callback = pmic_pdcharger_ulog_rpmsg_callback, + .id_table = pmic_pdcharger_ulog_rpmsg_id_match, + .drv = { + .name = "qcom_pmic_pdcharger_ulog_rpmsg", + }, +}; + +module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver); +MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.h b/drivers/soc/qcom/pmic_pdcharger_ulog.h new file mode 100644 index 000000000000..9d5d9af4fbe4 --- /dev/null +++ b/drivers/soc/qcom/pmic_pdcharger_ulog.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Ltd + */ + +#if !defined(_TRACE_PMIC_PDCHARGER_ULOG_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_PMIC_PDCHARGER_ULOG_H + +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pmic_pdcharger_ulog + +TRACE_EVENT(pmic_pdcharger_ulog_msg, + TP_PROTO(char *msg), + TP_ARGS(msg), + TP_STRUCT__entry( + __string(msg, msg) + ), + TP_fast_assign( + __assign_str(msg, msg); + ), + TP_printk("%s", __get_str(msg)) +); + +#endif /* _TRACE_PMIC_PDCHARGER_ULOG_H */ + +/* This part must be outside protection */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pmic_pdcharger_ulog + +#include <trace/define_trace.h>
The Qualcomm PMIC PDCharger ULOG driver provides access to logs of the ADSP firmware PDCharger module in charge of Battery and Power Delivery on modern systems. Implement trace events as a simple rpmsg driver with an 1s interval to retrieve the messages. The interface allows filtering the messages by subsystem and priority level, this could be implemented later on. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> --- drivers/soc/qcom/Kconfig | 12 +++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/pmic_pdcharger_ulog.c | 166 +++++++++++++++++++++++++++++++++ drivers/soc/qcom/pmic_pdcharger_ulog.h | 36 +++++++ 4 files changed, 215 insertions(+) --- base-commit: 2dde18cd1d8fac735875f2e4987f11817cc0bc2c change-id: 20230908-topic-sm8550-upstream-pdcharge-ulog-21ece9292474 Best regards,