[PATCH] remoteproc: Create a separate workqueue for recovery tasks
Create an unbound high priority workqueue for recovery tasks. Recovery time is an important parameter for a subsystem and there might be situations where multiple subsystems crash around the same time. Scheduling into an unbound workqueue increases parallelization and avoids time impact. Also creating a high priority workqueue will utilize separate worker threads with higher nice values than normal ones. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/remoteproc_core.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 46c2937..8fd8166 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -48,6 +48,8 @@ static DEFINE_MUTEX(rproc_list_mutex); static LIST_HEAD(rproc_list); static struct notifier_block rproc_panic_nb; +static struct workqueue_struct *rproc_wq; + typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int offset, int avail); @@ -2475,7 +2477,7 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) rproc->name, rproc_crash_to_string(type)); /* create a new task to handle the error */ - schedule_work(>crash_handler); + queue_work(rproc_wq, >crash_handler); } EXPORT_SYMBOL(rproc_report_crash); @@ -2520,6 +2522,10 @@ static void __exit rproc_exit_panic(void) static int __init remoteproc_init(void) { + rproc_wq = alloc_workqueue("rproc_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!rproc_wq) + return -ENOMEM; + rproc_init_sysfs(); rproc_init_debugfs(); rproc_init_cdev(); @@ -2536,6 +2542,7 @@ static void __exit remoteproc_exit(void) rproc_exit_panic(); rproc_exit_debugfs(); rproc_exit_sysfs(); + destroy_workqueue(rproc_wq); } module_exit(remoteproc_exit); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] drivers: mdt_loader: Add parallel blobs loading capability
Add capability to load blobs parallely during loading of firmware. Create a high priority unbound workqueue and schedule work items to load the firmware blobs parallely. This helps in improving firmware loading times. Signed-off-by: Rishabh Bhatnagar --- drivers/soc/qcom/mdt_loader.c | 147 ++ 1 file changed, 107 insertions(+), 40 deletions(-) diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 24cd193..4e5d2aa 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -17,6 +17,26 @@ #include #include +static struct workqueue_struct *mdt_wq; + +struct fw_desc { + size_t mem_size; + void *mem_region; + const struct firmware *fw; + char *fw_name; + struct device *dev; + size_t fw_name_len; + phys_addr_t mem_reloc; +}; + +struct mdt_seg_data { + struct work_struct load_seg_work; + const struct elf32_phdr *phdr; + int seg_num; + int result; + struct fw_desc *desc; +}; + static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { if (phdr->p_type != PT_LOAD) @@ -126,6 +146,62 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len) } EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); +static void mdt_load_seg_work_fn(struct work_struct *work) +{ + struct mdt_seg_data *mdt_seg_data = container_of(work, struct mdt_seg_data, load_seg_work); + struct fw_desc *desc = mdt_seg_data->desc; + int seg_num = mdt_seg_data->seg_num; + const struct elf32_phdr *phdr = mdt_seg_data->phdr; + const struct firmware *seg_fw; + ssize_t offset; + void *ptr; + int ret; + char *fw_name = kstrdup(desc->fw_name, GFP_KERNEL); + + if (!mdt_phdr_valid(phdr)) + goto fw_free; + + offset = phdr->p_paddr - desc->mem_reloc; + if (offset < 0 || offset + phdr->p_memsz > desc->mem_size) { + dev_err(desc->dev, "segment outside memory range\n"); + mdt_seg_data->result = -EINVAL; + goto fw_free; + } + + ptr = desc->mem_region + offset; + + if (phdr->p_filesz && phdr->p_offset < desc->fw->size) { + /* Firmware is large enough to be non-split */ + if (phdr->p_offset + phdr->p_filesz > desc->fw->size) { + dev_err(desc->dev, + "failed to load segment %d from truncated file %s\n", + seg_num, desc->fw_name); + mdt_seg_data->result = -EINVAL; + goto fw_free; + } + + memcpy(ptr, desc->fw->data + phdr->p_offset, phdr->p_filesz); + } else if (phdr->p_filesz) { + /* Firmware not large enough, load split-out segments */ + sprintf(fw_name + desc->fw_name_len - 3, "b%02d", seg_num); + ret = request_firmware_into_buf(_fw, fw_name, desc->dev, + ptr, phdr->p_filesz); + if (ret) { + dev_err(desc->dev, "failed to load %s\n", fw_name); + mdt_seg_data->result = -EINVAL; + goto fw_free; + } + + release_firmware(seg_fw); + } + + if (phdr->p_memsz > phdr->p_filesz) + memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + +fw_free: + kfree(fw_name); +} + static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, const char *firmware, int pas_id, void *mem_region, phys_addr_t mem_phys, size_t mem_size, @@ -134,19 +210,18 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; const struct elf32_hdr *ehdr; - const struct firmware *seg_fw; + struct mdt_seg_data *segs; phys_addr_t mem_reloc; phys_addr_t min_addr = PHYS_ADDR_MAX; phys_addr_t max_addr = 0; size_t metadata_len; size_t fw_name_len; - ssize_t offset; void *metadata; char *fw_name; bool relocate = false; - void *ptr; int ret = 0; int i; + struct fw_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!fw || !mem_region || !mem_phys || !mem_size) return -EINVAL; @@ -217,54 +292,46 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, mem_reloc = mem_phys; } - for (i = 0; i < ehdr->e_phnum; i++) { - phdr = [i]; + if (!mdt_wq) + mdt_wq = alloc_workqueue("mdt_workqueue&
[PATCH v2 1/3] soc: qcom: Add tracepoints to mdt loader
Add trace events to the mdt loader driver. These events can help us trace the region where we are loading the segments and the time it takes to initialize the image and setup the memory region. Signed-off-by: Rishabh Bhatnagar --- drivers/soc/qcom/mdt_loader.c | 7 +++ include/trace/events/mdt_loader.h | 38 ++ 2 files changed, 45 insertions(+) create mode 100644 include/trace/events/mdt_loader.h diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 24cd193..96dc912 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -17,6 +17,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { if (phdr->p_type != PT_LOAD) @@ -198,6 +201,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (pas_init) { ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); + if (ret) { dev_err(dev, "unable to setup relocation\n"); goto out; @@ -232,6 +236,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, ptr = mem_region + offset; + if (phdr->p_filesz && phdr->p_offset < fw->size) { /* Firmware is large enough to be non-split */ if (phdr->p_offset + phdr->p_filesz > fw->size) { @@ -256,6 +261,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, release_firmware(seg_fw); } + trace_qcom_mdt_load_segment(mem_phys + offset, phdr->p_filesz, + fw_name); if (phdr->p_memsz > phdr->p_filesz) memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); } diff --git a/include/trace/events/mdt_loader.h b/include/trace/events/mdt_loader.h new file mode 100644 index 000..01c2461 --- /dev/null +++ b/include/trace/events/mdt_loader.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mdt_loader + +#if !defined(_TRACE_MDT_LOADER_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MDT_LOADER_H + +#include +#include + +TRACE_EVENT(qcom_mdt_load_segment, + + TP_PROTO(phys_addr_t region_start, size_t region_size, const char *fw), + + TP_ARGS(region_start, region_size, fw), + + TP_STRUCT__entry( + __field(phys_addr_t, region_start) + __field(size_t, region_size) + __string(fw, fw) + ), + + TP_fast_assign( + __entry->region_start = region_start; + __entry->region_size = region_size; + __assign_str(fw, fw); + ), + + TP_printk("firmware:%s region start=%pa size=%zx", + __get_str(fw), __entry->region_start, __entry->region_size) +); + +#endif +#include -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 0/3] Add events to trace remoteproc lifecycle
Insert tracepoints in mdt_loader, qcom_scm and remoteproc_core drivers. These tracepoints will be used to analyze the time taken at each step during bootup/shutdown of the remoteproc. Tracepoints in mdt_loader driver provides information about location and size of firmware segments being loaded. Also trace the scm pas calls used to boot/load remote processors. Changelog: v2 -> v1: - Add traces in qcom_scm driver - Add traces in remoteproc core to trace the remoteproc state - Trace the physical address where segment is loaded in mdt_loader Rishabh Bhatnagar (3): soc: qcom: Add tracepoints to mdt loader firmware: scm: Add tracepoints to scm driver for pas calls remoteproc: Add ftrace events to trace lifecycle of remoteprocs drivers/firmware/qcom_scm.c | 9 drivers/remoteproc/remoteproc_core.c | 19 +++- drivers/soc/qcom/mdt_loader.c| 7 +++ include/trace/events/mdt_loader.h| 38 +++ include/trace/events/qcom_scm.h | 34 ++ include/trace/events/remoteproc.h| 91 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/mdt_loader.h create mode 100644 include/trace/events/qcom_scm.h create mode 100644 include/trace/events/remoteproc.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 2/3] firmware: scm: Add tracepoints to scm driver for pas calls
Add trace events to the qcom_scm driver to trace pas calls. These events can help us analyze the time impact for each scm operation and can also serve as standard checkpoints in code. Signed-off-by: Rishabh Bhatnagar --- drivers/firmware/qcom_scm.c | 9 + include/trace/events/qcom_scm.h | 34 ++ 2 files changed, 43 insertions(+) create mode 100644 include/trace/events/qcom_scm.h diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 7be48c1..5bc9b65 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -19,6 +19,9 @@ #include "qcom_scm.h" +#define CREATE_TRACE_POINTS +#include + static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); module_param(download_mode, bool, 0); @@ -442,6 +445,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) }; struct qcom_scm_res res; + trace_qcom_scm_call("Start scm_pas_init_image"); /* * During the scm call memory protection will be enabled for the meta * data blob, so make sure it's physically contiguous, 4K aligned and @@ -467,6 +471,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) free_metadata: dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); + trace_qcom_scm_call("Complete scm_pas_init_image"); return ret ? : res.result[0]; } @@ -495,6 +500,7 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) }; struct qcom_scm_res res; + trace_qcom_scm_call("Start scm_pas_mem_setup"); ret = qcom_scm_clk_enable(); if (ret) return ret; @@ -502,6 +508,7 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) ret = qcom_scm_call(__scm->dev, , ); qcom_scm_clk_disable(); + trace_qcom_scm_call("Complete scm_pas_mem_setup"); return ret ? : res.result[0]; } EXPORT_SYMBOL(qcom_scm_pas_mem_setup); @@ -525,6 +532,7 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral) }; struct qcom_scm_res res; + trace_qcom_scm_call("Start auth_and_reset"); ret = qcom_scm_clk_enable(); if (ret) return ret; @@ -532,6 +540,7 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral) ret = qcom_scm_call(__scm->dev, , ); qcom_scm_clk_disable(); + trace_qcom_scm_call("Complete auth_and_reset"); return ret ? : res.result[0]; } EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); diff --git a/include/trace/events/qcom_scm.h b/include/trace/events/qcom_scm.h new file mode 100644 index 000..d918332 --- /dev/null +++ b/include/trace/events/qcom_scm.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_scm + +#if !defined(_TRACE_QCOM_SCM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_QCOM_SCM_H + +#include +#include + +TRACE_EVENT(qcom_scm_call, + + TP_PROTO(const char *event), + + TP_ARGS(event), + + TP_STRUCT__entry( + __string(event, event) + ), + + TP_fast_assign( + __assign_str(event, event); + ), + + TP_printk("qcom_scm_call event:%s", __get_str(event)) +); + +#endif +#include + -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 3/3] remoteproc: Add ftrace events to trace lifecycle of remoteprocs
Add trace events to trace bootup/shutdown/recovery of remote processors. These events are useful in analyzing the time spent in each step in the life cycle and can be used for performace analysis. Also these serve as standard checkpoints in debugging. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/remoteproc_core.c | 19 +++- include/trace/events/remoteproc.h| 91 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/remoteproc.h diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index dab2c0f..39da409 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -42,6 +42,9 @@ #include "remoteproc_internal.h" +#define CREATE_TRACE_POINTS +#include + #define HIGH_BITS_MASK 0xULL static DEFINE_MUTEX(rproc_list_mutex); @@ -1164,6 +1167,7 @@ static int rproc_prepare_subdevices(struct rproc *rproc) struct rproc_subdev *subdev; int ret; + trace_rproc_subdevices("Prepare subdevices", rproc->name); list_for_each_entry(subdev, >subdevs, node) { if (subdev->prepare) { ret = subdev->prepare(subdev); @@ -1188,6 +1192,7 @@ static int rproc_start_subdevices(struct rproc *rproc) struct rproc_subdev *subdev; int ret; + trace_rproc_subdevices("Start subdevices", rproc->name); list_for_each_entry(subdev, >subdevs, node) { if (subdev->start) { ret = subdev->start(subdev); @@ -1211,6 +1216,7 @@ static void rproc_stop_subdevices(struct rproc *rproc, bool crashed) { struct rproc_subdev *subdev; + trace_rproc_subdevices("Stop subdevices", rproc->name); list_for_each_entry_reverse(subdev, >subdevs, node) { if (subdev->stop) subdev->stop(subdev, crashed); @@ -1221,6 +1227,7 @@ static void rproc_unprepare_subdevices(struct rproc *rproc) { struct rproc_subdev *subdev; + trace_rproc_subdevices("Unprepare subdevices", rproc->name); list_for_each_entry_reverse(subdev, >subdevs, node) { if (subdev->unprepare) subdev->unprepare(subdev); @@ -1357,6 +1364,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw) struct device *dev = >dev; int ret; + trace_rproc_boot("loading firmware segments into memory", rproc->name); /* load the ELF segments to memory */ ret = rproc_load_segments(rproc, fw); if (ret) { @@ -1385,6 +1393,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw) goto reset_table_ptr; } + trace_rproc_boot("starting remoteproc", rproc->name); /* power up the remote processor */ ret = rproc->ops->start(rproc); if (ret) { @@ -1402,6 +1411,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw) rproc->state = RPROC_RUNNING; + trace_rproc_boot("remoteproc is up", rproc->name); dev_info(dev, "remote processor %s is now up\n", rproc->name); return 0; @@ -1648,6 +1658,7 @@ static int rproc_stop(struct rproc *rproc, bool crashed) /* the installed resource table is no longer accessible */ rproc->table_ptr = rproc->cached_table; + trace_rproc_shutdown("Stopping the remoteproc", rproc->name); /* power off the remote processor */ ret = rproc->ops->stop(rproc); if (ret) { @@ -1697,6 +1708,7 @@ int rproc_trigger_recovery(struct rproc *rproc) if (rproc->state != RPROC_CRASHED) goto unlock_mutex; + trace_rproc_recovery("Recover remoteproc", rproc->name); dev_err(dev, "recovering %s\n", rproc->name); ret = rproc_stop(rproc, true); @@ -1716,6 +1728,7 @@ int rproc_trigger_recovery(struct rproc *rproc) /* boot the remote processor up again */ ret = rproc_start(rproc, firmware_p); + trace_rproc_recovery("Recovery completed", rproc->name); release_firmware(firmware_p); unlock_mutex: @@ -1796,6 +1809,7 @@ int rproc_boot(struct rproc *rproc) /* skip the boot or attach process if rproc is already powered up */ if (atomic_inc_return(>power) > 1) { ret = 0; + trace_rproc_boot("Incrementing ref count and exiting", rproc->name); goto unlock_mutex; } @@ -1804,6 +1818,7 @@ int rproc_boot(struct rproc *rproc) ret = rproc_actuate(rproc); } else { + trace_rproc_boot("requesting firmw
[PATCH 2/2] remoteproc: qcom: Add trace events for q6v5_pas driver
Add tracepoints for q6v5_pas driver. These will help in analyzing the time taken by each step in remoteproc bootup/shutdown process and also serve as standard checkpoints in code. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_pas.c | 11 +++ include/trace/events/q6v5_pas.h| 34 ++ 2 files changed, 45 insertions(+) create mode 100644 include/trace/events/q6v5_pas.h diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 3837f23..b3c0a6a 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -29,6 +29,9 @@ #include "qcom_q6v5.h" #include "remoteproc_internal.h" +#define CREATE_TRACE_POINTS +#include + struct adsp_data { int crash_reason_smem; const char *firmware_name; @@ -121,12 +124,14 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int ret; + trace_q6v5_pas("setting up memory and loading segments", rproc->name); ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id, adsp->mem_region, adsp->mem_phys, adsp->mem_size, >mem_reloc); if (ret) return ret; + trace_q6v5_pas("done loading segments", rproc->name); qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size); return 0; @@ -137,6 +142,7 @@ static int adsp_start(struct rproc *rproc) struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int ret; + trace_q6v5_pas("Voting for resources", rproc->name); qcom_q6v5_prepare(>q6v5); ret = adsp_pds_enable(adsp, adsp->active_pds, adsp->active_pd_count); @@ -163,12 +169,14 @@ static int adsp_start(struct rproc *rproc) if (ret) goto disable_cx_supply; + trace_q6v5_pas("Before authenticate and reset", rproc->name); ret = qcom_scm_pas_auth_and_reset(adsp->pas_id); if (ret) { dev_err(adsp->dev, "failed to authenticate image and release reset\n"); goto disable_px_supply; } + trace_q6v5_pas("After authenticate and reset", rproc->name); ret = qcom_q6v5_wait_for_start(>q6v5, msecs_to_jiffies(5000)); if (ret == -ETIMEDOUT) { @@ -177,6 +185,7 @@ static int adsp_start(struct rproc *rproc) goto disable_px_supply; } + trace_q6v5_pas("Remoteproc is up", rproc->name); return 0; disable_px_supply: @@ -214,6 +223,7 @@ static int adsp_stop(struct rproc *rproc) int handover; int ret; + trace_q6v5_pas("Request stop", rproc->name); ret = qcom_q6v5_request_stop(>q6v5); if (ret == -ETIMEDOUT) dev_err(adsp->dev, "timed out on wait\n"); @@ -227,6 +237,7 @@ static int adsp_stop(struct rproc *rproc) if (handover) qcom_pas_handover(>q6v5); + trace_q6v5_pas("Remoteproc is down", rproc->name); return ret; } diff --git a/include/trace/events/q6v5_pas.h b/include/trace/events/q6v5_pas.h new file mode 100644 index 000..38ee5e2 --- /dev/null +++ b/include/trace/events/q6v5_pas.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM q6v5_pas + +#if !defined(_TRACE_Q6V5_PAS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_Q6V5_PAS_H + +#include + +TRACE_EVENT(q6v5_pas, + + TP_PROTO(const char *event, const char *rproc_name), + + TP_ARGS(event, rproc_name), + + TP_STRUCT__entry( + __string(event, event) + __string(rproc_name, rproc_name) + ), + + TP_fast_assign( + __assign_str(event, event); + __assign_str(rproc_name, rproc_name); + ), + + TP_printk("event=%s remoteproc:%s", __get_str(event), __get_str(rproc_name)) +); + +#endif +#include -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 0/2] Add trace events to q6v5_pas and mdt_loader driver
Create and insert trace points in mdt_loader and qcom_q6v5_pas drivers. These tracepoints will be used to analyze the time taken at each step during bootup/shutdown of the remoteproc. Also provide information about location and size of firmware segments being loaded. Rishabh Bhatnagar (2): soc: qcom: Add tracepoints to mdt loader remoteproc: qcom: Add trace events for q6v5_pas driver drivers/remoteproc/qcom_q6v5_pas.c | 11 drivers/soc/qcom/mdt_loader.c | 8 ++ include/trace/events/mdt_loader.h | 57 ++ include/trace/events/q6v5_pas.h| 34 +++ 4 files changed, 110 insertions(+) create mode 100644 include/trace/events/mdt_loader.h create mode 100644 include/trace/events/q6v5_pas.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH 1/2] soc: qcom: Add tracepoints to mdt loader
Add trace events to the mdt loader driver. These events can help us trace the region where we are loading the segments and the time it takes to initialize the image and setup the memory region. Signed-off-by: Rishabh Bhatnagar --- drivers/soc/qcom/mdt_loader.c | 8 ++ include/trace/events/mdt_loader.h | 57 +++ 2 files changed, 65 insertions(+) create mode 100644 include/trace/events/mdt_loader.h diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 24cd193..df69e23 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -17,6 +17,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + static bool mdt_phdr_valid(const struct elf32_phdr *phdr) { if (phdr->p_type != PT_LOAD) @@ -169,6 +172,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, goto out; } + trace_memory_setup("pas_init_image", fw_name); ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len); kfree(metadata); @@ -196,8 +200,10 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (relocate) { if (pas_init) { + trace_memory_setup("pas_mem_setup", fw_name); ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); + if (ret) { dev_err(dev, "unable to setup relocation\n"); goto out; @@ -232,6 +238,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, ptr = mem_region + offset; + trace_regions(ptr, phdr->p_filesz, i); + if (phdr->p_filesz && phdr->p_offset < fw->size) { /* Firmware is large enough to be non-split */ if (phdr->p_offset + phdr->p_filesz > fw->size) { diff --git a/include/trace/events/mdt_loader.h b/include/trace/events/mdt_loader.h new file mode 100644 index 000..6299f65 --- /dev/null +++ b/include/trace/events/mdt_loader.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mdt_loader + +#if !defined(_TRACE_MDT_LOADER_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MDT_LOADER_H + +#include +#include + +TRACE_EVENT(memory_setup, + + TP_PROTO(const char *event, char *fw_name), + + TP_ARGS(event, fw_name), + + TP_STRUCT__entry( + __string(event, event) + __string(fw_name, fw_name) + ), + + TP_fast_assign( + __assign_str(event, event); + __assign_str(fw_name, fw_name); + ), + + TP_printk("doing %s for %s", __get_str(event), __get_str(fw_name)) +); + +TRACE_EVENT(regions, + + TP_PROTO(void *region_start, size_t region_size, int i), + + TP_ARGS(region_start, region_size, i), + + TP_STRUCT__entry( + __field(void *, region_start) + __field(size_t, region_size) + __field(int, index) + ), + + TP_fast_assign( + __entry->region_start = region_start; + __entry->region_size = region_size; + __entry->index = i; + ), + + TP_printk("segment %d: region start=%pK size=%zx", __entry->index, + __entry->region_start, __entry->region_size) +); + +#endif +#include -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] remoteproc: qcom: Add notification timeouts
Clients can register their callbacks for power-on/off notifications of remote processors. While executing the notifier chain sometimes these callbacks may get stuck or take a long time which is not desired. To detect such cases this patch introduces a timeout and prints out a warning indicating that notifier chain is taking a long time. The timeout is set to 20secs by default and can be adjusted. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/Kconfig | 16 drivers/remoteproc/qcom_common.c | 41 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index d99548f..e1e623e 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -234,6 +234,22 @@ config QCOM_WCNSS_PIL Say y here to support the Peripheral Image Loader for the Qualcomm Wireless Connectivity Subsystem. +config QCOM_NOTIFY_TIMEOUT + int "Default timeout for ssr notifications to complete (in milliseconds)" + depends on QCOM_RPROC_COMMON + default 2 + help + As part of ssr notification clients can register their callbacks + to a notifier chain which is invoked whenever the remoteproc + powers-on/off. This option controls the timeout for ssr notifications + to complete. + This is a good to have debug feature as sometimes callbacks + can get stuck or take a long time. This feature helps in identifying + such scenarios. + + The default value is kept as 20 secs and should be left as it is + in most cases. + config ST_REMOTEPROC tristate "ST remoteproc support" depends on ARCH_STI diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 085fd73..d72c4f5 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -29,6 +29,8 @@ struct qcom_ssr_subsystem { const char *name; struct srcu_notifier_head notifier_list; struct list_head list; + struct timer_list notify_timer; + const char *notify_type; }; static LIST_HEAD(qcom_ssr_subsystem_list); @@ -198,6 +200,14 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) } EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); +static void notify_timeout_handler(struct timer_list *t) +{ + struct qcom_ssr_subsystem *info = from_timer(info, t, notify_timer); + + WARN(1, "srcu notifier chain for %s:%s taking too long", info->name, +info->notify_type); +} + static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) { struct qcom_ssr_subsystem *info; @@ -216,6 +226,9 @@ static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) info->name = kstrdup_const(name, GFP_KERNEL); srcu_init_notifier_head(>notifier_list); + /* Setup the notification timer */ + timer_setup(>notify_timer, notify_timeout_handler, 0); + /* Add to global notification list */ list_add_tail(>list, _ssr_subsystem_list); @@ -266,6 +279,18 @@ int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); +static inline void notify_ssr_clients(struct qcom_rproc_ssr *ssr, + enum qcom_ssr_notify_type type, + struct qcom_ssr_notify_data *data) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(CONFIG_QCOM_NOTIFY_TIMEOUT); + mod_timer(>info->notify_timer, timeout); + srcu_notifier_call_chain(>info->notifier_list, type, data); + del_timer_sync(>info->notify_timer); +} + static int ssr_notify_prepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); @@ -274,8 +299,8 @@ static int ssr_notify_prepare(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, -QCOM_SSR_BEFORE_POWERUP, ); + ssr->info->notify_type = "BEFORE_POWERUP"; + notify_ssr_clients(ssr, QCOM_SSR_BEFORE_POWERUP, ); return 0; } @@ -287,8 +312,8 @@ static int ssr_notify_start(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, -QCOM_SSR_AFTER_POWERUP, ); + ssr->info->notify_type = "AFTER_POWERUP"; + notify_ssr_clients(ssr, QCOM_SSR_AFTER_POWERUP, ); return 0; } @@ -300,8 +325,8 @@ static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) .crashed = crashed, }; - srcu_notifier_call_chain(>info->notifier_list, -
[PATCH v7 0/3] Move recovery/coredump configuration to sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. This patch series adds recovery/coredump configuration to sysfs interface and disables coredump collection by default. Having coredump disabled by default on production devices makes sense. Changelog: v7 -> v6: - Keep the debugfs entries intact for now. - Reorder the patches to have a consistent sysfs interface. v6 -> v5: - Disable coredump collection by default - Rename the "default" configuration to "enabled" to avoid confusion v5 -> v4: - Fix the cover-letter of tha patch series. v4 -> v3: - Remove the feature flag to expose recovery/coredump v3 -> v2: - Remove the coredump/recovery entries from debugfs - Expose recovery/coredump from sysfs under a feature flag v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (3): remoteproc: Change default dump configuration to "disabled" remoteproc: Add coredump as part of sysfs interface remoteproc: Add recovery configuration to the sysfs interface Documentation/ABI/testing/sysfs-class-remoteproc | 44 + drivers/remoteproc/remoteproc_coredump.c | 6 +- drivers/remoteproc/remoteproc_debugfs.c | 23 +++-- drivers/remoteproc/remoteproc_sysfs.c| 119 +++ include/linux/remoteproc.h | 8 +- 5 files changed, 181 insertions(+), 19 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v7 1/3] remoteproc: Change default dump configuration to "disabled"
Currently "default" configuration option means coredumps are enabled. To avoid confusion rename the "default" configuration option to "enabled" and disable collection of dumps by default as doing so makes sense for production devices. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/remoteproc_coredump.c | 6 +++--- drivers/remoteproc/remoteproc_debugfs.c | 23 +++ include/linux/remoteproc.h | 8 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index bb15a29..34530dc 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -257,7 +257,7 @@ void rproc_coredump(struct rproc *rproc) * directly read from device memory. */ data_size += elf_size_of_phdr(class); - if (dump_conf == RPROC_COREDUMP_DEFAULT) + if (dump_conf == RPROC_COREDUMP_ENABLED) data_size += segment->size; phnum++; @@ -297,14 +297,14 @@ void rproc_coredump(struct rproc *rproc) elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X); elf_phdr_set_p_align(class, phdr, 0); - if (dump_conf == RPROC_COREDUMP_DEFAULT) + if (dump_conf == RPROC_COREDUMP_ENABLED) rproc_copy_segment(rproc, data + offset, segment, 0, segment->size); offset += elf_phdr_get_p_filesz(class, phdr); phdr += elf_size_of_phdr(class); } - if (dump_conf == RPROC_COREDUMP_DEFAULT) { + if (dump_conf == RPROC_COREDUMP_ENABLED) { dev_coredumpv(>dev, data, data_size, GFP_KERNEL); return; } diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..7e58453 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -33,9 +33,9 @@ static struct dentry *rproc_dbg; * enum rproc_coredump_mechanism */ static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", [RPROC_COREDUMP_DISABLED] = "disabled", + [RPROC_COREDUMP_ENABLED]= "enabled", + [RPROC_COREDUMP_INLINE] = "inline", }; /* Expose the current coredump configuration via debugfs */ @@ -54,20 +54,19 @@ static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, /* * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". + * coredump mechanism dynamically. The default value of this entry is "disabled". * * The 'coredump' debugfs entry supports these commands: * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. + * disabled: By default coredump collection is disabled. Recovery will + * proceed without collecting any dump. + * + * enabled:When the remoteproc crashes the entire coredump will be copied + * to a separate buffer and exposed to userspace. * * inline: The coredump will not be copied to a separate buffer and the * recovery process will have to wait until data is read by * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. */ static ssize_t rproc_coredump_write(struct file *filp, const char __user *user_buf, size_t count, @@ -94,12 +93,12 @@ static ssize_t rproc_coredump_write(struct file *filp, goto out; } - if (!strncmp(buf, "disable", count)) { + if (!strncmp(buf, "disabled", count)) { rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "enabled", count)) { + rproc->dump_conf = RPROC_COREDUMP_ENABLED; } else if (!strncmp(buf, "inline", count)) { rproc->dump_conf = RPROC_COREDUMP_INLINE; - } else if (!strncmp(buf, "default", count)) { - rproc->dump_conf = RPROC_COREDUMP_DEFAULT; } else { dev_err(>dev, "Invalid coredump configuration\n"); err = -EINVAL; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 2fa68bf..3fa3ba6 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc
[PATCH v7 3/3] remoteproc: Add recovery configuration to the sysfs interface
Add recovery configuration to the sysfs interface. This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 + drivers/remoteproc/remoteproc_sysfs.c| 56 2 files changed, 76 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 050bd25..066b9b6 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration processor's device memory. Extra buffer will not be used to copy the dump. Also recovery process will not proceed until all data is read by usersapce. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 8500271..d1cf7bf 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -10,6 +10,61 @@ #define to_rproc(d) container_of(d, struct rproc, dev) +static ssize_t recovery_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ + struct rproc *rproc = to_rproc(dev); + + return sprintf(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n"); +} + +/* + * By writing to the 'recovery' sysfs entry, we control the behavior of the + * recovery mechanism dynamically. The default value of this entry is "enabled". + * + * The 'recovery' sysfs entry supports these commands: + * + * enabled:When enabled, the remote processor will be automatically + * recovered whenever it crashes. Moreover, if the remote + * processor crashes while recovery is disabled, it will + * be automatically recovered too as soon as recovery is enabled. + * + * disabled: When disabled, a remote processor will remain in a crashed + * state if it crashes. This is useful for debugging purposes; + * without it, debugging a crash is substantially harder. + * + * recover:This function will trigger an immediate recovery if the + * remote processor is in a crashed state, without changing + * or checking the recovery state (enabled/disabled). + * This is useful during debugging sessions, when one expects + * additional crashes to happen after enabling recovery. In this + * case, enabling recovery will make it hard to debug subsequent + * crashes, so it's recommended to keep recovery disabled, and + * instead use the "recover" command as needed. + */ +static ssize_t recovery_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rproc *rproc = to_rproc(dev); + + if (sysfs_streq(buf, "enabled")) { + /* change the flag and begin the recovery process if needed */ + rproc->recovery_disabled = false; + rproc_trigger_recovery(rproc); + } else if (sysfs_streq(buf, "disabled")) { + rproc->recovery_disabled = true; + } else if (sysfs_streq(buf, "recover")) { + /* begin the recovery process without changing the flag */ + rproc_trigger_recovery(rproc); + } else { + return -EINVAL; + } + + return count; +} +static DEVICE_ATTR_RW(recovery); + /* * A coredump-configuration-to-string lookup table, for exposing a * human readable configuration via sysfs. Always keep in sync with @@ -201,6 +256,7 @@ static DEVICE_ATTR_RO(name); static struct attribute *rproc_attrs[] = { _attr_coredump.attr, + _attr_recovery.attr, _attr_firmware.attr, _attr_state
[PATCH v7 2/3] remoteproc: Add coredump as part of sysfs interface
Add coredump as part of the sysfs interface. This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 + drivers/remoteproc/remoteproc_sysfs.c| 63 2 files changed, 87 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..050bd25 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "disabled" + "enabled" + "inline" + + "disabled" means no dump will be collected. + + "enabled" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index eea514c..8500271 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -10,6 +10,68 @@ #define to_rproc(d) container_of(d, struct rproc, dev) +/* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via sysfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DISABLED] = "disabled", + [RPROC_COREDUMP_ENABLED]= "enabled", + [RPROC_COREDUMP_INLINE] = "inline", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t coredump_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ + struct rproc *rproc = to_rproc(dev); + + return sprintf(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]); +} + +/* + * By writing to the 'coredump' sysfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' sysfs entry supports these commands: + * + * disabled: This is the default coredump mechanism. Recovery will proceed + * without collecting any dump. + * + * default:When the remoteproc crashes the entire coredump will be + * copied to a separate buffer and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + */ +static ssize_t coredump_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct rproc *rproc = to_rproc(dev); + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + return -EBUSY; + } + + if (sysfs_streq(buf, "disabled")) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (sysfs_streq(buf, "enabled")) { + rproc->dump_conf = RPROC_COREDUMP_ENABLED; + } else if (sysfs_streq(buf, "inline")) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + return -EINVAL; + } + + return count; +} +static DEVICE_ATTR_RW(coredump); + /* Expose the loaded / running firmware name via sysfs */ static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -138,6 +200,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_
[PATCH v6 0/3] Move recovery/coredump configuration to sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test builds and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. This patch series removes the recovery/coredump entries from debugfs and moves them to sysfs. Also, this disables the coredump collection by default as this is a requirement for production devices. Changelog: v6 -> v5: - Disable coredump collection by default - Rename the "default" configuration to "enabled" to avoid confusion v5 -> v4: - Fix the cover-letter of tha patch series. v4 -> v3: - Remove the feature flag to expose recovery/coredump v3 -> v2: - Remove the coredump/recovery entries from debugfs - Expose recovery/coredump from sysfs under a feature flag v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (3): remoteproc: Move coredump configuration to sysfs remoteproc: Move recovery configuration to sysfs remoteproc: Change default dump configuration to "disabled" Documentation/ABI/testing/sysfs-class-remoteproc | 46 +++ drivers/remoteproc/remoteproc_coredump.c | 6 +- drivers/remoteproc/remoteproc_debugfs.c | 168 --- drivers/remoteproc/remoteproc_sysfs.c| 120 include/linux/remoteproc.h | 8 +- 5 files changed, 173 insertions(+), 175 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 2/3] remoteproc: Move recovery configuration to sysfs
Move recovery configuration from debugfs to sysfs.This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 ++ drivers/remoteproc/remoteproc_debugfs.c | 78 drivers/remoteproc/remoteproc_sysfs.c| 56 + 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index f6c44fa..7368b50 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration all data is read by usersapce. "disabled" means no dump will be collected. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..c505f0e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -84,82 +84,6 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; -/* expose recovery flag via debugfs */ -static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; - - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -/* - * By writing to the 'recovery' debugfs entry, we control the behavior of the - * recovery mechanism dynamically. The default value of this entry is "enabled". - * - * The 'recovery' debugfs entry supports these commands: - * - * enabled:When enabled, the remote processor will be automatically - * recovered whenever it crashes. Moreover, if the remote - * processor crashes while recovery is disabled, it will - * be automatically recovered too as soon as recovery is enabled. - * - * disabled: When disabled, a remote processor will remain in a crashed - * state if it crashes. This is useful for debugging purposes; - * without it, debugging a crash is substantially harder. - * - * recover:This function will trigger an immediate recovery if the - * remote processor is in a crashed state, without changing - * or checking the recovery state (enabled/disabled). - * This is useful during debugging sessions, when one expects - * additional crashes to happen after enabling recovery. In this - * case, enabling recovery will make it hard to debug subsequent - * crashes, so it's recommended to keep recovery disabled, and - * instead use the "recover" command as needed. - */ -static ssize_t -rproc_recovery_write(struct file *filp, const char __user *user_buf, -size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[10]; - int ret; - - if (count < 1 || count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (!strncmp(buf, "enabled", count)) { - /* change the flag and begin the recovery process if needed */ - rproc->recovery_disabled = false; - rproc_trigger_recovery(rproc); - } else if (!strncmp(buf, "disabled", count)) { - rproc->recovery_disabled = true; - } else if (!strncmp(buf, "recover", count)) { - /* begin the recovery process without changing the flag */ -
[PATCH v6 1/3] remoteproc: Move coredump configuration to sysfs
Move coredump configuration from debugfs to sysfs.This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 drivers/remoteproc/remoteproc_sysfs.c| 64 + 3 files changed, 88 insertions(+), 90 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..f6c44fa 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..732770e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,94 +28,6 @@ static struct dentry *rproc_dbg; /* - * A coredump-configuration-to-string lookup table, for exposing a - * human readable configuration via debugfs. Always keep in sync with - * enum rproc_coredump_mechanism - */ -static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", - [RPROC_COREDUMP_DISABLED] = "disabled", -}; - -/* Expose the current coredump configuration via debugfs */ -static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[20]; - int len; - - len = scnprintf(buf, sizeof(buf), "%s\n", - rproc_coredump_str[rproc->dump_conf]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -/* - * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". - * - * The 'coredump' debugfs entry supports these commands: - * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. - * - * inline: The coredump will not be copied to a separate buffer and the - * recovery process will have to wait until data is read by - * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. - */ -static ssize_t rproc_coredump_write(struct file *filp, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - int ret, err = 0; - char buf[20]; - - if (count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (rproc->state == RPROC_CRASHED) { - dev_err(>dev, "can't change coredump configuration\n"); - err = -EBUSY; - goto out; - } - - if (!strncmp(buf, "disable", count)) { - rproc->dump_conf = RPROC_COREDUMP_DISABLED; - } else if (!strncmp(buf, "inline&
[PATCH v6 3/3] remoteproc: Change default dump configuration to "disabled"
Disable the coredump collection by default as doing so makes sense for production devices. Also rename the "default" configuration option to "enabled" to avoid confusion. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 10 ++ drivers/remoteproc/remoteproc_coredump.c | 6 +++--- drivers/remoteproc/remoteproc_sysfs.c| 10 +- include/linux/remoteproc.h | 8 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 7368b50..dec1686 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -67,11 +67,14 @@ Description:Remote processor coredump configuration Reports the coredump configuration of the remote processor, which will be one of: - "default" - "inline" "disabled" + "enabled" + "inline" + + "disabled" means no dump will be collected. This is the + default remoteproc coredump configuration. - "default" means when the remote processor's coredump is + "enabled" means when the remote processor's coredump is collected it will be copied to a separate buffer and that buffer is exposed to userspace. @@ -81,7 +84,6 @@ Description: Remote processor coredump configuration copy the dump. Also recovery process will not proceed until all data is read by usersapce. - "disabled" means no dump will be collected. What: /sys/class/remoteproc/.../recovery Date: July 2020 diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index bb15a29..34530dc 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -257,7 +257,7 @@ void rproc_coredump(struct rproc *rproc) * directly read from device memory. */ data_size += elf_size_of_phdr(class); - if (dump_conf == RPROC_COREDUMP_DEFAULT) + if (dump_conf == RPROC_COREDUMP_ENABLED) data_size += segment->size; phnum++; @@ -297,14 +297,14 @@ void rproc_coredump(struct rproc *rproc) elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X); elf_phdr_set_p_align(class, phdr, 0); - if (dump_conf == RPROC_COREDUMP_DEFAULT) + if (dump_conf == RPROC_COREDUMP_ENABLED) rproc_copy_segment(rproc, data + offset, segment, 0, segment->size); offset += elf_phdr_get_p_filesz(class, phdr); phdr += elf_size_of_phdr(class); } - if (dump_conf == RPROC_COREDUMP_DEFAULT) { + if (dump_conf == RPROC_COREDUMP_ENABLED) { dev_coredumpv(>dev, data, data_size, GFP_KERNEL); return; } diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index e60a014..eb98ed2 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -68,12 +68,12 @@ static DEVICE_ATTR_RW(recovery); /* * A coredump-configuration-to-string lookup table, for exposing a * human readable configuration via sysfs. Always keep in sync with - * enum rproc_coredump_mechanism + * enum rproc_dump_mechanism */ static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", [RPROC_COREDUMP_DISABLED] = "disabled", + [RPROC_COREDUMP_ENABLED]= "enabled", + [RPROC_COREDUMP_INLINE] = "inline", }; /* Expose the current coredump configuration via debugfs */ @@ -115,10 +115,10 @@ static ssize_t coredump_store(struct device *dev, if (sysfs_streq(buf, "disabled")) { rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (sysfs_streq(buf, "enabled")) { + rproc->dump_conf = RPROC_COREDUMP_ENABLED; } else if (sysfs_streq(buf, "inline")) { rproc->dump_conf = RPROC_COREDUMP_INLINE; - } else if (sysfs_streq(buf, "default")) { - rproc->dump_conf = RPROC_COREDUMP_DEFAULT; } else { dev_err(>dev, "Invalid coredump configuration\n"); return -EINVAL; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 2fa
[PATCH v5 0/2] Move recovery/coredump configuration to sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. This patch series removes the recovery/coredump entries from debugfs and moves them to sysfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test build and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. Changelog: v5 -> v4: - Fix the cover-letter of tha patch series. v4 -> v3: - Remove the feature flag to expose recovery/coredump v3 -> v2: - Remove the coredump/recovery entries from debugfs - Expose recovery/coredump from sysfs under a feature flag v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (2): remoteproc: Move coredump configuration to sysfs remoteproc: Move recovery configuration to sysfs Documentation/ABI/testing/sysfs-class-remoteproc | 44 ++ drivers/remoteproc/remoteproc_debugfs.c | 168 --- drivers/remoteproc/remoteproc_sysfs.c| 120 3 files changed, 164 insertions(+), 168 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v5 1/2] remoteproc: Move coredump configuration to sysfs
Move coredump configuration from debugfs to sysfs.This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 drivers/remoteproc/remoteproc_sysfs.c| 64 + 3 files changed, 88 insertions(+), 90 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..f6c44fa 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..732770e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,94 +28,6 @@ static struct dentry *rproc_dbg; /* - * A coredump-configuration-to-string lookup table, for exposing a - * human readable configuration via debugfs. Always keep in sync with - * enum rproc_coredump_mechanism - */ -static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", - [RPROC_COREDUMP_DISABLED] = "disabled", -}; - -/* Expose the current coredump configuration via debugfs */ -static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[20]; - int len; - - len = scnprintf(buf, sizeof(buf), "%s\n", - rproc_coredump_str[rproc->dump_conf]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -/* - * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". - * - * The 'coredump' debugfs entry supports these commands: - * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. - * - * inline: The coredump will not be copied to a separate buffer and the - * recovery process will have to wait until data is read by - * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. - */ -static ssize_t rproc_coredump_write(struct file *filp, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - int ret, err = 0; - char buf[20]; - - if (count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (rproc->state == RPROC_CRASHED) { - dev_err(>dev, "can't change coredump configuration\n"); - err = -EBUSY; - goto out; - } - - if (!strncmp(buf, "disable", count)) { - rproc->dump_conf = RPROC_COREDUMP_DISABLED; - } else if (!strncmp(buf, "inline&
[PATCH v5 2/2] remoteproc: Move recovery configuration to sysfs
Move recovery configuration from debugfs to sysfs.This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 ++ drivers/remoteproc/remoteproc_debugfs.c | 78 drivers/remoteproc/remoteproc_sysfs.c| 56 + 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index f6c44fa..7368b50 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration all data is read by usersapce. "disabled" means no dump will be collected. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..c505f0e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -84,82 +84,6 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; -/* expose recovery flag via debugfs */ -static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; - - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -/* - * By writing to the 'recovery' debugfs entry, we control the behavior of the - * recovery mechanism dynamically. The default value of this entry is "enabled". - * - * The 'recovery' debugfs entry supports these commands: - * - * enabled:When enabled, the remote processor will be automatically - * recovered whenever it crashes. Moreover, if the remote - * processor crashes while recovery is disabled, it will - * be automatically recovered too as soon as recovery is enabled. - * - * disabled: When disabled, a remote processor will remain in a crashed - * state if it crashes. This is useful for debugging purposes; - * without it, debugging a crash is substantially harder. - * - * recover:This function will trigger an immediate recovery if the - * remote processor is in a crashed state, without changing - * or checking the recovery state (enabled/disabled). - * This is useful during debugging sessions, when one expects - * additional crashes to happen after enabling recovery. In this - * case, enabling recovery will make it hard to debug subsequent - * crashes, so it's recommended to keep recovery disabled, and - * instead use the "recover" command as needed. - */ -static ssize_t -rproc_recovery_write(struct file *filp, const char __user *user_buf, -size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[10]; - int ret; - - if (count < 1 || count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (!strncmp(buf, "enabled", count)) { - /* change the flag and begin the recovery process if needed */ - rproc->recovery_disabled = false; - rproc_trigger_recovery(rproc); - } else if (!strncmp(buf, "disabled", count)) { - rproc->recovery_disabled = true; - } else if (!strncmp(buf, "recover", count)) { - /* begin the recovery process without changing the flag */ -
[PATCH v4 0/3] Move recovery/coredump configuration to sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. This patch series removes the recovery/coredump entries from debugfs and moves them to sysfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test build and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. Changelog: v4 -> v3: - Remove the feature flag to expose recovery/coredump v3 -> v2: - Remove the coredump/recovery entries from debugfs - Expose recovery/coredump from sysfs under a feature flag v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (3): remoteproc: Expose remoteproc configuration through sysfs remoteproc: Add coredump configuration to sysfs remoteproc: Add recovery configuration to sysfs Documentation/ABI/testing/sysfs-class-remoteproc | 44 drivers/remoteproc/Kconfig | 12 +++ drivers/remoteproc/remoteproc_debugfs.c | 10 +- drivers/remoteproc/remoteproc_sysfs.c| 126 +++ 4 files changed, 190 insertions(+), 2 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v4 2/2] remoteproc: Move recovery configuration to sysfs
Move recovery configuration from debugfs to sysfs. This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 ++ drivers/remoteproc/remoteproc_debugfs.c | 78 drivers/remoteproc/remoteproc_sysfs.c| 56 + 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index f6c44fa..7368b50 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration all data is read by usersapce. "disabled" means no dump will be collected. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..c505f0e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -84,82 +84,6 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; -/* expose recovery flag via debugfs */ -static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; - - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -/* - * By writing to the 'recovery' debugfs entry, we control the behavior of the - * recovery mechanism dynamically. The default value of this entry is "enabled". - * - * The 'recovery' debugfs entry supports these commands: - * - * enabled:When enabled, the remote processor will be automatically - * recovered whenever it crashes. Moreover, if the remote - * processor crashes while recovery is disabled, it will - * be automatically recovered too as soon as recovery is enabled. - * - * disabled: When disabled, a remote processor will remain in a crashed - * state if it crashes. This is useful for debugging purposes; - * without it, debugging a crash is substantially harder. - * - * recover:This function will trigger an immediate recovery if the - * remote processor is in a crashed state, without changing - * or checking the recovery state (enabled/disabled). - * This is useful during debugging sessions, when one expects - * additional crashes to happen after enabling recovery. In this - * case, enabling recovery will make it hard to debug subsequent - * crashes, so it's recommended to keep recovery disabled, and - * instead use the "recover" command as needed. - */ -static ssize_t -rproc_recovery_write(struct file *filp, const char __user *user_buf, -size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[10]; - int ret; - - if (count < 1 || count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (!strncmp(buf, "enabled", count)) { - /* change the flag and begin the recovery process if needed */ - rproc->recovery_disabled = false; - rproc_trigger_recovery(rproc); - } else if (!strncmp(buf, "disabled", count)) { - rproc->recovery_disabled = true; - } else if (!strncmp(buf, "recover", count)) { - /* begin the recovery process without changing the flag */ -
[PATCH v4 1/2] remoteproc: Move coredump configuration to sysfs
Move coredump configuration from debugfs to sysfs. This will allow usage of this configuration feature in production devices where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 drivers/remoteproc/remoteproc_sysfs.c| 64 + 3 files changed, 88 insertions(+), 90 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..f6c44fa 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..732770e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,94 +28,6 @@ static struct dentry *rproc_dbg; /* - * A coredump-configuration-to-string lookup table, for exposing a - * human readable configuration via debugfs. Always keep in sync with - * enum rproc_coredump_mechanism - */ -static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", - [RPROC_COREDUMP_DISABLED] = "disabled", -}; - -/* Expose the current coredump configuration via debugfs */ -static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[20]; - int len; - - len = scnprintf(buf, sizeof(buf), "%s\n", - rproc_coredump_str[rproc->dump_conf]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -/* - * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". - * - * The 'coredump' debugfs entry supports these commands: - * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. - * - * inline: The coredump will not be copied to a separate buffer and the - * recovery process will have to wait until data is read by - * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. - */ -static ssize_t rproc_coredump_write(struct file *filp, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - int ret, err = 0; - char buf[20]; - - if (count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (rproc->state == RPROC_CRASHED) { - dev_err(>dev, "can't change coredump configuration\n"); - err = -EBUSY; - goto out; - } - - if (!strncmp(buf, "disable", count)) { - rproc->dump_conf = RPROC_COREDUMP_DISABLED; - } else if (!strncmp(buf, "inline&
[PATCH v3 1/3] remoteproc: Expose remoteproc configuration through sysfs
Add a feature flag to expose some of the remoteproc configuration through sysfs. This feature is helpful in systems where debugfs is not available/mounted. Currently the recovery and coredump configuration is exposed through sysfs rather than debugfs when this feature is selected. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/Kconfig | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index c6659dfe..98d52cbe 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -275,6 +275,17 @@ config TI_K3_DSP_REMOTEPROC It's safe to say N here if you're not interested in utilizing the DSP slave processors. +config RPROC_SYSFS_CONFIGURATION_SUPPORT + bool "Expose remoteproc configuration sysfs entries" + default y + help + Say y here to expose recovery and coredump configuration sysfs + entries. This is helpful in operating systems where debugfs is + not available/mounted. + + It's safe to say N here if you are not interested in accessing + recovery and coredump configuration through sysfs. + endif # REMOTEPROC endmenu -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 2/3] remoteproc: Add coredump configuration to sysfs
Expose coredump configuration in sysfs under a feature flag. This is useful for systems where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 drivers/remoteproc/remoteproc_sysfs.c| 68 ++ 3 files changed, 92 insertions(+), 90 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..f6c44fa 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..732770e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,94 +28,6 @@ static struct dentry *rproc_dbg; /* - * A coredump-configuration-to-string lookup table, for exposing a - * human readable configuration via debugfs. Always keep in sync with - * enum rproc_coredump_mechanism - */ -static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", - [RPROC_COREDUMP_DISABLED] = "disabled", -}; - -/* Expose the current coredump configuration via debugfs */ -static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[20]; - int len; - - len = scnprintf(buf, sizeof(buf), "%s\n", - rproc_coredump_str[rproc->dump_conf]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -/* - * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". - * - * The 'coredump' debugfs entry supports these commands: - * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. - * - * inline: The coredump will not be copied to a separate buffer and the - * recovery process will have to wait until data is read by - * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. - */ -static ssize_t rproc_coredump_write(struct file *filp, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - int ret, err = 0; - char buf[20]; - - if (count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (rproc->state == RPROC_CRASHED) { - dev_err(>dev, "can't change coredump configuration\n"); - err = -EBUSY; - goto out; - } - - if (!strncmp(buf, "disable", count)) { - rproc->dump_conf = RPROC_COREDUMP_DISABLED; - } else if (!strncmp(buf, "inline", count)) { - rproc-&g
[PATCH v3 3/3] remoteproc: Add recovery configuration to sysfs
Expose recovery configuration in sysfs under a feature flag. This is useful for systems where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 ++ drivers/remoteproc/remoteproc_debugfs.c | 78 drivers/remoteproc/remoteproc_sysfs.c| 58 ++ 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index f6c44fa..7368b50 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration all data is read by usersapce. "disabled" means no dump will be collected. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..c505f0e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -84,82 +84,6 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; -/* expose recovery flag via debugfs */ -static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; - - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -/* - * By writing to the 'recovery' debugfs entry, we control the behavior of the - * recovery mechanism dynamically. The default value of this entry is "enabled". - * - * The 'recovery' debugfs entry supports these commands: - * - * enabled:When enabled, the remote processor will be automatically - * recovered whenever it crashes. Moreover, if the remote - * processor crashes while recovery is disabled, it will - * be automatically recovered too as soon as recovery is enabled. - * - * disabled: When disabled, a remote processor will remain in a crashed - * state if it crashes. This is useful for debugging purposes; - * without it, debugging a crash is substantially harder. - * - * recover:This function will trigger an immediate recovery if the - * remote processor is in a crashed state, without changing - * or checking the recovery state (enabled/disabled). - * This is useful during debugging sessions, when one expects - * additional crashes to happen after enabling recovery. In this - * case, enabling recovery will make it hard to debug subsequent - * crashes, so it's recommended to keep recovery disabled, and - * instead use the "recover" command as needed. - */ -static ssize_t -rproc_recovery_write(struct file *filp, const char __user *user_buf, -size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[10]; - int ret; - - if (count < 1 || count > sizeof(buf)) - return -EINVAL; - - ret = copy_from_user(buf, user_buf, count); - if (ret) - return -EFAULT; - - /* remove end of line */ - if (buf[count - 1] == '\n') - buf[count - 1] = '\0'; - - if (!strncmp(buf, "enabled", count)) { - /* change the flag and begin the recovery process if needed */ - rproc->recovery_disabled = false; - rproc_trigger_recovery(rproc); - } else if (!strncmp(buf, "disabled", count)) { - rproc->recovery_disabled = true; - } else if (!strncmp(buf, "recover", count)) { - /* begin the recovery process without changing the flag */ - rproc_trigger_recovery(rproc); -
[PATCH v3 0/3] Expose recovery/coredump configuration from sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. This patch series removes the recovery/coredump entries from debugfs and adds a configurable option to expose these interfaces from sysfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test build and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. Changelog: v3 -> v2: - Remove the coredump/recovery entries from debugfs - Expose recovery/coredump from sysfs under a feature flag v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (3): remoteproc: Expose remoteproc configuration through sysfs remoteproc: Add coredump configuration to sysfs remoteproc: Add recovery configuration to sysfs Documentation/ABI/testing/sysfs-class-remoteproc | 44 drivers/remoteproc/Kconfig | 12 +++ drivers/remoteproc/remoteproc_debugfs.c | 10 +- drivers/remoteproc/remoteproc_sysfs.c| 126 +++ 4 files changed, 190 insertions(+), 2 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 2/3] remoteproc: Add coredump configuration to sysfs
Expose coredump configuration in sysfs under a feature flag. This is useful for systems where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 24 + drivers/remoteproc/remoteproc_debugfs.c | 4 ++ drivers/remoteproc/remoteproc_sysfs.c| 68 3 files changed, 96 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..f6c44fa 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,27 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..48dfd0a 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -27,6 +27,7 @@ /* remoteproc debugfs parent dir */ static struct dentry *rproc_dbg; +#if (!IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT)) /* * A coredump-configuration-to-string lookup table, for exposing a * human readable configuration via debugfs. Always keep in sync with @@ -114,6 +115,7 @@ static const struct file_operations rproc_coredump_fops = { .open = simple_open, .llseek = generic_file_llseek, }; +#endif /* * Some remote processors may support dumping trace logs into a shared @@ -425,8 +427,10 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); +#if (!IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT)) debugfs_create_file("coredump", 0600, rproc->dbg_dir, rproc, _coredump_fops); +#endif } void __init rproc_init_debugfs(void) diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index eea514c..89b301a 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -10,6 +10,71 @@ #define to_rproc(d) container_of(d, struct rproc, dev) +#if IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT) +/* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via sysfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t coredump_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ + struct rproc *rproc = to_rproc(dev); + + return sprintf(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]); +} + +/* + * By writing to the 'coredump' sysfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' sysfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memo
[PATCH v2 1/3] remoteproc: Expose remoteproc configuration through sysfs
Add a feature flag to expose some of the remoteproc configuration through sysfs. This feature is helpful in systems where debugfs is not available/mounted. Currently the recovery and coredump configuration is exposed through sysfs rather than debugfs when this feature is selected. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/Kconfig | 12 1 file changed, 12 insertions(+) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index c6659dfe..8aecf70 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -275,6 +275,18 @@ config TI_K3_DSP_REMOTEPROC It's safe to say N here if you're not interested in utilizing the DSP slave processors. +config RPROC_SYSFS_CONFIGURATION_SUPPORT + bool "Expose remoteproc configuration sysfs entries" + default n + help + Say y here to expose recovery and coredump configuration sysfs + entries. This will remove the corresponding entries from debugfs + and expose it through sysfs. This is helpful in operating systems + where debugfs is not available. + + It's safe to say N here if you are not interested in accessing + recovery and coredump configuration through sysfs. + endif # REMOTEPROC endmenu -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 0/3] Expose recovery/coredump configuration from sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. This patch series adds a configurable option to move the recovery/coredump interfaces to sysfs. If the feature flag is selected it would move these interfaces to sysfs and remove the equivalent debugfs interface. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test build and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. Changelog: v1 -> v2: - Correct the contact name in the sysfs documentation. - Remove the redundant write documentation for coredump/recovery sysfs - Add a feature flag to make this interface switch configurable. Rishabh Bhatnagar (3): remoteproc: Expose remoteproc configuration through sysfs remoteproc: Add coredump configuration to sysfs remoteproc: Add recovery configuration to sysfs Documentation/ABI/testing/sysfs-class-remoteproc | 44 drivers/remoteproc/Kconfig | 12 +++ drivers/remoteproc/remoteproc_debugfs.c | 10 +- drivers/remoteproc/remoteproc_sysfs.c| 126 +++ 4 files changed, 190 insertions(+), 2 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v2 3/3] remoteproc: Add recovery configuration to sysfs
Expose recovery configuration in sysfs under a feature flag. This is useful for systems where access to debugfs might be limited. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 20 drivers/remoteproc/remoteproc_debugfs.c | 6 ++- drivers/remoteproc/remoteproc_sysfs.c| 58 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index f6c44fa..7368b50 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -82,3 +82,23 @@ Description: Remote processor coredump configuration all data is read by usersapce. "disabled" means no dump will be collected. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Bjorn Andersson , Ohad Ben-Cohen +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 48dfd0a..415a9ff 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -174,6 +174,7 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; +#if (!IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT)) /* expose recovery flag via debugfs */ static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, size_t count, loff_t *ppos) @@ -249,6 +250,7 @@ static const struct file_operations rproc_recovery_ops = { .open = simple_open, .llseek = generic_file_llseek, }; +#endif /* expose the crash trigger via debugfs */ static ssize_t @@ -419,8 +421,6 @@ void rproc_create_debug_dir(struct rproc *rproc) debugfs_create_file("name", 0400, rproc->dbg_dir, rproc, _name_ops); - debugfs_create_file("recovery", 0600, rproc->dbg_dir, - rproc, _recovery_ops); debugfs_create_file("crash", 0200, rproc->dbg_dir, rproc, _crash_ops); debugfs_create_file("resource_table", 0400, rproc->dbg_dir, @@ -430,6 +430,8 @@ void rproc_create_debug_dir(struct rproc *rproc) #if (!IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT)) debugfs_create_file("coredump", 0600, rproc->dbg_dir, rproc, _coredump_fops); + debugfs_create_file("recovery", 0600, rproc->dbg_dir, + rproc, _recovery_ops); #endif } diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index 89b301a..45cae4f 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -11,6 +11,63 @@ #define to_rproc(d) container_of(d, struct rproc, dev) #if IS_ENABLED(CONFIG_RPROC_SYSFS_CONFIGURATION_SUPPORT) + +/* expose recovery flag via sysfs */ +static ssize_t recovery_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ + struct rproc *rproc = to_rproc(dev); + + return sprintf(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n"); +} + +/* + * By writing to the 'recovery' sysfs entry, we control the behavior of the + * recovery mechanism dynamically. The default value of this entry is "enabled". + * + * The 'recovery' sysfs entry supports these commands: + * + * enabled:When enabled, the remote processor will be automatically + * recovered whenever it crashes. Moreover, if the remote + * processor crashes while recovery is disabled, it will + * be automatically recovered too as soon as recovery is enabled. + * + * disabled: When disabled, a remote processor will remain in a crashed + * state if it crashes. This is useful for debugging purposes; + * without it, debugging a crash is substantially harder. + * + * recover:This function will tri
[PATCH 2/2] remoteproc: Move recovery debugfs entry to sysfs
Expose recovery mechanism through sysfs rather than exposing through debugfs. Some operating systems may limit access to debugfs through access policies. This restricts user access to recovery mechanism, hence move it to sysfs. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 36 +++ drivers/remoteproc/remoteproc_debugfs.c | 77 drivers/remoteproc/remoteproc_sysfs.c| 57 ++ 3 files changed, 93 insertions(+), 77 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 812582a..16c5267 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -98,3 +98,39 @@ Description: Remote processor coredump configuration Writing "disable" will disable the coredump collection for that remoteproc. + +What: /sys/class/remoteproc/.../recovery +Date: July 2020 +Contact: Rishabh Bhatnagar +Description: Remote processor recovery mechanism + + Reports the recovery mechanism of the remote processor, + which will be one of: + + "enabled" + "disabled" + + "enabled" means, the remote processor will be automatically + recovered whenever it crashes. Moreover, if the remote + processor crashes while recovery is disabled, it will + be automatically recovered too as soon as recovery is enabled. + + "disabled" means, a remote processor will remain in a crashed + state if it crashes. This is useful for debugging purposes; + without it, debugging a crash is substantially harder. + + Writing this file controls the recovery mechanism of the + remote processor. The following options can be written: + + "enabled" + "disabled" + "recover" + + Writing "enabled" will enable recovery and recover the remote + processor if its crashed. + + Writing "disabled" will disable recovery and if crashed the + remote processor will remain in crashed state. + + Writing "recover" will trigger an immediate recovery if the + remote processor is in crashed state. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..71194a0 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -84,81 +84,6 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; -/* expose recovery flag via debugfs */ -static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; - - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -/* - * By writing to the 'recovery' debugfs entry, we control the behavior of the - * recovery mechanism dynamically. The default value of this entry is "enabled". - * - * The 'recovery' debugfs entry supports these commands: - * - * enabled:When enabled, the remote processor will be automatically - * recovered whenever it crashes. Moreover, if the remote - * processor crashes while recovery is disabled, it will - * be automatically recovered too as soon as recovery is enabled. - * - * disabled: When disabled, a remote processor will remain in a crashed - * state if it crashes. This is useful for debugging purposes; - * without it, debugging a crash is substantially harder. - * - * recover:This function will trigger an immediate recovery if the - * remote processor is in a crashed state, without changing - * or checking the recovery state (enabled/disabled). - * This is useful during debugging sessions, when one expects - * additional crashes to happen after enabling recovery. In this - * case, enabling recovery will make it hard to debug subsequent - * crashes, so it's recommended to keep recovery disabled, and - * instead use the "recover" command as needed. - */ -static ssize_t -rproc_recovery_write(struct file *filp, const char __user *user_buf, -size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[10]; - int ret; - - if (count < 1 || count > sizeof(buf)) - return -EI
[PATCH 1/2] remoteproc: Move coredump entry from debugfs to sysfs.
Expose coredump configuration from sysfs instead of debugfs. In some operating systems access to debugfs might be limited. This restricts user from selecting the coredump configuration at all, hence move this interface to sysfs. Signed-off-by: Rishabh Bhatnagar --- Documentation/ABI/testing/sysfs-class-remoteproc | 40 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 drivers/remoteproc/remoteproc_sysfs.c| 64 + 3 files changed, 104 insertions(+), 90 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc index 36094fb..812582a 100644 --- a/Documentation/ABI/testing/sysfs-class-remoteproc +++ b/Documentation/ABI/testing/sysfs-class-remoteproc @@ -58,3 +58,43 @@ Description: Remote processor name Reports the name of the remote processor. This can be used by userspace in exactly identifying a remote processor and ease up the usage in modifying the 'firmware' or 'state' files. + +What: /sys/class/remoteproc/.../coredump +Date: July 2020 +Contact: Rishabh Bhatnagar +Description: Remote processor coredump configuration + + Reports the coredump configuration of the remote processor, + which will be one of: + + "default" + "inline" + "disabled" + + "default" means when the remote processor's coredump is + collected it will be copied to a separate buffer and that + buffer is exposed to userspace. + + "inline" means when the remote processor's coredump is + collected userspace will directly read from the remote + processor's device memory. Extra buffer will not be used to + copy the dump. Also recovery process will not proceed until + all data is read by usersapce. + + "disabled" means no dump will be collected. + + Writing this file controls the coredump configuration of the + remote processor. The following configurations can be written: + + "default" + "inline" + "disable" + + Writing "default" will change the coredump configuration to + default option. + + Writing "inline" will change the coredump configuration to + inline. + + Writing "disable" will disable the coredump collection for + that remoteproc. diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 2e3b3e2..732770e 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,94 +28,6 @@ static struct dentry *rproc_dbg; /* - * A coredump-configuration-to-string lookup table, for exposing a - * human readable configuration via debugfs. Always keep in sync with - * enum rproc_coredump_mechanism - */ -static const char * const rproc_coredump_str[] = { - [RPROC_COREDUMP_DEFAULT]= "default", - [RPROC_COREDUMP_INLINE] = "inline", - [RPROC_COREDUMP_DISABLED] = "disabled", -}; - -/* Expose the current coredump configuration via debugfs */ -static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - char buf[20]; - int len; - - len = scnprintf(buf, sizeof(buf), "%s\n", - rproc_coredump_str[rproc->dump_conf]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, len); -} - -/* - * By writing to the 'coredump' debugfs entry, we control the behavior of the - * coredump mechanism dynamically. The default value of this entry is "default". - * - * The 'coredump' debugfs entry supports these commands: - * - * default:This is the default coredump mechanism. When the remoteproc - * crashes the entire coredump will be copied to a separate buffer - * and exposed to userspace. - * - * inline: The coredump will not be copied to a separate buffer and the - * recovery process will have to wait until data is read by - * userspace. But this avoid usage of extra memory. - * - * disabled: This will disable coredump. Recovery will proceed without - * collecting any dump. - */ -static ssize_t rproc_coredump_write(struct file *filp, - const char __user *user_buf, size_t count, - loff_t *ppos) -{ - struct rproc *rproc = filp->private_data; - int ret, err = 0; - cha
[PATCH 0/2] Move recovery and coredump interface to sysfs
>From Android R onwards Google has restricted access to debugfs in user and user-debug builds. This restricts access to most of the features exposed through debugfs. 'Coredump' and 'Recovery' are critical interfaces that are required for remoteproc to work on Qualcomm Chipsets. Coredump configuration needs to be set to "inline" in debug/test builds and "disabled" in production builds. Whereas recovery needs to be "disabled" for debugging purposes and "enabled" on production builds. Moving these interfaces to sysfs will allow usage for these interfaces for production and debug builds. Rishabh Bhatnagar (2): remoteproc: Move coredump entry from debugfs to sysfs. remoteproc: Move recovery debugfs entry to sysfs Documentation/ABI/testing/sysfs-class-remoteproc | 76 +++ drivers/remoteproc/remoteproc_debugfs.c | 167 --- drivers/remoteproc/remoteproc_sysfs.c| 123 + 3 files changed, 199 insertions(+), 167 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 0/5] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled until all data is read by userspace. This patchset also includes Sibi Sankar's patch to deal with chunk sizes lesser than segment size to make inline coredump work for modem. https://patchwork.kernel.org/patch/11637157/ Changelog: v8 -> v7: - Split out the qcom_q6v5_mss refactoring into a new patch - Remove zero size check in dump_segment function for mss - Remove segment number being passed as private member for the segment - Free the memory used by dump state header before signalling completion v7 -> v6: - Include Sibi's patch as part of this patchset - Add a linefeed when displaying coredump conf in debugfs - Fix a typo in remoteproc.h v6 -> v5: - Fix unsigned comaprison with negative bug found on gcc-9.3.0 v5 -> v4: - Rebase on top of linux-next - Modify qcom_q6v5_mss driver as a result of rebasing on latest tip. v4 -> v3: - Write a helper function to copy segment memory for every dump format - Change segment dump fn to add offset and size adn covert mss driver v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (4): remoteproc: Move coredump functionality to a new file remoteproc: Add size and offset arguments to segment dump function remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry Sibi Sankar (1): remoteproc: qcom_q6v5_mss: Replace mask based tracking with size drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 25 ++- drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 325 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 + drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 21 +- 7 files changed, 451 insertions(+), 206 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 1/5] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Reviewed-by: Sibi Sankar Tested-by: Sibi Sankar --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index e8b886e..8702a4e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9f04c30..57db042 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1239,19 +1237,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1518,182 +1503,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) -
[PATCH v8 2/5] remoteproc: qcom_q6v5_mss: Replace mask based tracking with size
From: Sibi Sankar In order to land inline coredump support for mss, the dump_segment function would need to support granularities less than the segment size. This is achieved by replacing mask based tracking with size. Signed-off-by: Sibi Sankar Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_mss.c | 17 - 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index feb70283b..037cd45 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -181,8 +181,8 @@ struct q6v5 { bool running; bool dump_mba_loaded; - unsigned long dump_segment_mask; - unsigned long dump_complete_mask; + size_t current_dump_size; + size_t total_dump_size; phys_addr_t mba_phys; void *mba_region; @@ -1203,7 +1203,6 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, { int ret = 0; struct q6v5 *qproc = rproc->priv; - unsigned long mask = BIT((unsigned long)segment->priv); int offset = segment->da - qproc->mpss_reloc; void *ptr = NULL; @@ -1229,10 +1228,10 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, memset(dest, 0xff, segment->size); } - qproc->dump_segment_mask |= mask; + qproc->current_dump_size += segment->size; /* Reclaim mba after copying segments */ - if (qproc->dump_segment_mask == qproc->dump_complete_mask) { + if (qproc->current_dump_size == qproc->total_dump_size) { if (qproc->dump_mba_loaded) { /* Try to reset ownership back to Q6 */ q6v5_xfer_mem_ownership(qproc, >mpss_perm, @@ -1274,7 +1273,7 @@ static int q6v5_start(struct rproc *rproc) "Failed to reclaim mba buffer system may become unstable\n"); /* Reset Dump Segment Mask */ - qproc->dump_segment_mask = 0; + qproc->current_dump_size = 0; qproc->running = true; return 0; @@ -1323,7 +1322,7 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); - qproc->dump_complete_mask = 0; + qproc->total_dump_size = 0; for (i = 0; i < ehdr->e_phnum; i++) { phdr = [i]; @@ -1334,11 +1333,11 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr, phdr->p_memsz, qcom_q6v5_dump_segment, - (void *)i); + NULL); if (ret) break; - qproc->dump_complete_mask |= BIT(i); + qproc->total_dump_size += phdr->p_memsz; } release_firmware(fw); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 5/5] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Tested-by: Sibi Sankar Reviewed-by: Sibi Sankar --- drivers/remoteproc/remoteproc_debugfs.c | 90 + 1 file changed, 90 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..2e3b3e2 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,94 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + char buf[20]; + int len; + + len = scnprintf(buf, sizeof(buf), "%s\n", + rproc_coredump_str[rproc->dump_conf]); + + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "inline", count)) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else if (!strncmp(buf, "default", count)) { + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +425,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 3/5] remoteproc: Pass size and offset as arguments to segment dump function
Change the segment dump API signature to include size and offset arguments. Refactor the qcom_q6v5_mss driver to use these arguments while copying the segment. Doing this lays the ground work for "inline" coredump functionality being added in the next patch. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_mss.c | 10 +- drivers/remoteproc/remoteproc_coredump.c | 5 +++-- include/linux/remoteproc.h | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 037cd45..6baa3ae 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1199,7 +1199,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) static void qcom_q6v5_dump_segment(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest) + void *dest, size_t cp_offset, size_t size) { int ret = 0; struct q6v5 *qproc = rproc->priv; @@ -1219,16 +1219,16 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } if (!ret) - ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); + ptr = ioremap_wc(qproc->mpss_phys + offset + cp_offset, size); if (ptr) { - memcpy(dest, ptr, segment->size); + memcpy(dest, ptr, size); iounmap(ptr); } else { - memset(dest, 0xff, segment->size); + memset(dest, 0xff, size); } - qproc->current_dump_size += segment->size; + qproc->current_dump_size += size; /* Reclaim mba after copying segments */ if (qproc->current_dump_size == qproc->total_dump_size) { diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..390f563 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -72,7 +72,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv) { struct rproc_dump_segment *segment; @@ -183,7 +184,7 @@ void rproc_coredump(struct rproc *rproc) elf_phdr_set_p_align(class, phdr, 0); if (segment->dump) { - segment->dump(rproc, segment, data + offset); + segment->dump(rproc, segment, data + offset, 0, segment->size); } else { ptr = rproc_da_to_va(rproc, segment->da, segment->size); if (!ptr) { diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index e7b7bab..eb08139 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -451,7 +451,7 @@ struct rproc_dump_segment { void *priv; void (*dump)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest); +void *dest, size_t offset, size_t size); loff_t offset; }; @@ -630,7 +630,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv); int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 4/5] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Signed-off-by: Rishabh Bhatnagar Tested-by: Sibi Sankar --- drivers/remoteproc/remoteproc_coredump.c | 156 +++ include/linux/remoteproc.h | 16 2 files changed, 154 insertions(+), 18 deletions(-) diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index 390f563..bb15a29 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -5,6 +5,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -12,6 +13,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -115,12 +122,110 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + vfree(dump_state->header); + complete(_state->dump_done); +} + +static void *rproc_coredump_find_segment(loff_t user_offset, +struct list_head *segments, +size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment; + } + user_offset -= segment->size; + } + + *data_left = 0; + return NULL; +} + +static void rproc_copy_segment(struct rproc *rproc, void *dest, + struct rproc_dump_segment *segment, + size_t offset, size_t size) +{ + void *ptr; + + if (segment->dump) { + segment->dump(rproc, segment, dest, offset, size); + } else { + ptr = rproc_da_to_va(rproc, segment->da + offset, size); + if (!ptr) { + dev_err(>dev, + "invalid copy request for segment %pad with offset %zu and size %zu)\n", + >da, offset, size); + memset(dest, 0xff, size); + } else { + memcpy(dest, ptr, size); + } + } +} + +static ssize_t rproc_coredump_read(char *buffer, loff_t offset, size_t count, + void *data, size_t header_sz) +{ + size_t seg_data, bytes_left = count; + ssize_t copy_sz; + struct rproc_dump_segment *seg; + struct rproc_coredump_state *dump_state = data; + struct rproc *rproc = dump_state->rproc; + void *elfcore = dump_state->header; + + /* Copy the vmalloc'ed header first. */ + if (offset < header_sz) { + copy_sz = memory_read_from_buffer(buffer, count, , + elfcore, header_sz); + + return copy_sz; + } + + /* +* Find out the segment memory chunk to be copied based on offset. +* Keep copying data until count bytes are read. +*/ + while (bytes_left) { + seg = rproc_coredump_find_segment(offset - header_sz, + >dump_segments, + _data); + /* EOF check */ + if (!seg) { + dev_info(>dev, "Ramdump done, %lld bytes read", +offset); + break; + } + + copy_sz = min_t(size_t, bytes_left, seg_data); + + rproc_copy_segment(rproc, buffer, seg, seg->size - seg_data, + copy_sz); + + offset += copy_sz; + buffer += copy_sz; + bytes_left -= copy_sz; + } + + return count - bytes_left; +} + /** * rproc_coredump() - perform coredump * @rproc: rproc handle * * This function will generate an ELF header for the registered segments - * and create a devcoredump dev
[PATCH v7 4/4] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Tested-by: Sibi Sankar Reviewed-by: Sibi Sankar --- drivers/remoteproc/remoteproc_debugfs.c | 90 + 1 file changed, 90 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..16a4196 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,94 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + char buf[20]; + int len; + + len = scnprintf(buf, sizeof(buf), "%s\n", + rproc_coredump_str[rproc->dump_conf]); + + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "inline", count)) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else if (!strncmp(buf, "default", count)) { + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +425,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v7 3/4] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Also modify the qcom_q6v5_mss driver to include size and offset in the segment dump function. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Sibi Sankar --- drivers/remoteproc/qcom_q6v5_mss.c | 11 ++- drivers/remoteproc/remoteproc_coredump.c | 160 +++ include/linux/remoteproc.h | 21 +++- 3 files changed, 166 insertions(+), 26 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index c6ce032..79df354 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1199,11 +1199,12 @@ static int q6v5_mpss_load(struct q6v5 *qproc) static void qcom_q6v5_dump_segment(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest) + void *dest, size_t cp_offset, size_t size) { int ret = 0; struct q6v5 *qproc = rproc->priv; int offset = segment->da - qproc->mpss_reloc; + size_t cp_size = size ? size : segment->size; void *ptr = NULL; /* Unlock mba before copying segments */ @@ -1219,16 +1220,16 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } if (!ret) - ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); + ptr = ioremap_wc(qproc->mpss_phys + offset + cp_offset, cp_size); if (ptr) { - memcpy(dest, ptr, segment->size); + memcpy(dest, ptr, cp_size); iounmap(ptr); } else { - memset(dest, 0xff, segment->size); + memset(dest, 0xff, cp_size); } - qproc->current_dump_size += segment->size; + qproc->current_dump_size += cp_size; /* Reclaim mba after copying segments */ if (qproc->current_dump_size == qproc->total_dump_size) { diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..646886f 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -5,6 +5,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -12,6 +13,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -72,7 +79,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv) { struct rproc_dump_segment *segment; @@ -114,12 +122,110 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + complete(_state->dump_done); + vfree(dump_state->header); +} + +static void *rproc_coredump_find_segment(loff_t user_offset, +struct list_head *segments, +size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment; + } + user_offset -= segment->size; + } + + *data_left = 0; + return NULL; +} + +static void rproc_copy_segment(struct rproc *rproc, void *dest, + struct rproc_dump_segment *segment, + size_t offset, size_t size) +{ + void *ptr; + + if (segment->dump) { + segment->dump(rproc, segment, dest, offset, size); +
[PATCH v7 1/4] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier Reviewed-by: Sibi Sankar Tested-by: Sibi Sankar --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index e8b886e..8702a4e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9f04c30..57db042 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1239,19 +1237,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1518,182 +1503,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) -
[PATCH v7 0/4] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled until all data is read by userspace. This patchset also includes Sibi Sankar's patch to deal with chunk sizes lesser than segment size to make inline coredump work for modem. https://patchwork.kernel.org/patch/11637157/ Changelog: v7 -> v6: - Include Sibi's patch as part of this patchset - Add a linefeed when displaying coredump conf in debugfs - Fix a typo in remoteproc.h v6 -> v5: - Fix unsigned comaprison with negative bug found on gcc-9.3.0 v5 -> v4: - Rebase on top of linux-next - Modify qcom_q6v5_mss driver as a result of rebasing on latest tip. v4 -> v3: - Write a helper function to copy segment memory for every dump format - Change segment dump fn to add offset and size adn covert mss driver v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (3): remoteproc: Move coredump functionality to a new file remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry Sibi Sankar (1): remoteproc: qcom_q6v5_mss: Replace mask based tracking with size drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 22 +-- drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 326 +++ drivers/remoteproc/remoteproc_debugfs.c | 90 + drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 21 +- 7 files changed, 451 insertions(+), 204 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v1 2/4] remoteproc: qcom_q6v5_mss: Replace mask based tracking with size
From: Sibi Sankar In order to land inline coredump support for mss, the dump_segment function would need to support granularities less than the segment size. This is achieved by replacing mask based tracking with size. Signed-off-by: Sibi Sankar Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_mss.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index feb70283b..c6ce032 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -181,8 +181,8 @@ struct q6v5 { bool running; bool dump_mba_loaded; - unsigned long dump_segment_mask; - unsigned long dump_complete_mask; + size_t current_dump_size; + size_t total_dump_size; phys_addr_t mba_phys; void *mba_region; @@ -1203,7 +1203,6 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, { int ret = 0; struct q6v5 *qproc = rproc->priv; - unsigned long mask = BIT((unsigned long)segment->priv); int offset = segment->da - qproc->mpss_reloc; void *ptr = NULL; @@ -1229,10 +1228,10 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, memset(dest, 0xff, segment->size); } - qproc->dump_segment_mask |= mask; + qproc->current_dump_size += segment->size; /* Reclaim mba after copying segments */ - if (qproc->dump_segment_mask == qproc->dump_complete_mask) { + if (qproc->current_dump_size == qproc->total_dump_size) { if (qproc->dump_mba_loaded) { /* Try to reset ownership back to Q6 */ q6v5_xfer_mem_ownership(qproc, >mpss_perm, @@ -1274,7 +1273,7 @@ static int q6v5_start(struct rproc *rproc) "Failed to reclaim mba buffer system may become unstable\n"); /* Reset Dump Segment Mask */ - qproc->dump_segment_mask = 0; + qproc->current_dump_size = 0; qproc->running = true; return 0; @@ -1323,7 +1322,7 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, ehdr = (struct elf32_hdr *)fw->data; phdrs = (struct elf32_phdr *)(ehdr + 1); - qproc->dump_complete_mask = 0; + qproc->total_dump_size = 0; for (i = 0; i < ehdr->e_phnum; i++) { phdr = [i]; @@ -1338,7 +1337,7 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc, if (ret) break; - qproc->dump_complete_mask |= BIT(i); + qproc->total_dump_size += phdr->p_memsz; } release_firmware(fw); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 2/3] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_coredump.c | 160 +++ include/linux/remoteproc.h | 21 +++- 3 files changed, 165 insertions(+), 25 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 903b2bb..d4ff9b8 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1200,12 +1200,13 @@ static int q6v5_mpss_load(struct q6v5 *qproc) static void qcom_q6v5_dump_segment(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest) + void *dest, size_t cp_offset, size_t size) { int ret = 0; struct q6v5 *qproc = rproc->priv; unsigned long mask = BIT((unsigned long)segment->priv); int offset = segment->da - qproc->mpss_reloc; + size_t cp_size = size ? size : segment->size; void *ptr = NULL; /* Unlock mba before copying segments */ @@ -1221,13 +1222,13 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } if (!ret) - ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); + ptr = ioremap_wc(qproc->mpss_phys + offset + cp_offset, cp_size); if (ptr) { - memcpy(dest, ptr, segment->size); + memcpy(dest, ptr, cp_size); iounmap(ptr); } else { - memset(dest, 0xff, segment->size); + memset(dest, 0xff, cp_size); } qproc->dump_segment_mask |= mask; diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..646886f 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -5,6 +5,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -12,6 +13,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -72,7 +79,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv) { struct rproc_dump_segment *segment; @@ -114,12 +122,110 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + complete(_state->dump_done); + vfree(dump_state->header); +} + +static void *rproc_coredump_find_segment(loff_t user_offset, +struct list_head *segments, +size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment; + } + user_offset -= segment->size; + } + + *data_left = 0; + return NULL; +} + +static void rproc_copy_segment(struct rproc *rproc, void *dest, + struct rproc_dump_segment *segment, + size_t offset, size_t size) +{ + void *ptr; + + if (segment->dump) { + segment->dump(rproc, segment, dest, offset, size); + } else { + ptr = rproc_da_to_va(rproc, segment->da + offset, size); + if (!ptr) { + dev_err(>dev, + "invalid copy request for segment %
[PATCH v6 0/3] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled until all data is read by userspace. Changelog: v6 -> v5: - Fix unsigned comaprison with negative bug found on gcc-9.3.0 v5 -> v4: - Rebase on top of linux-next v4 -> v3: - Write a helper function to copy segment memory for every dump format - Change segment dump fn to add offset and size adn covert mss driver v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (3): remoteproc: Move coredump functionality to a new file remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 328 +++ drivers/remoteproc/remoteproc_debugfs.c | 86 drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 21 +- 7 files changed, 443 insertions(+), 197 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 1/3] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index e8b886e..8702a4e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9f04c30..57db042 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1239,19 +1237,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1518,182 +1503,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) - return -EINVAL; - -
[PATCH v6 3/3] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/remoteproc_debugfs.c | 86 + 1 file changed, 86 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..cca0a91 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,90 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + const char *buf = rproc_coredump_str[rproc->dump_conf]; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "inline", count)) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else if (!strncmp(buf, "default", count)) { + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +421,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 1/2] remoteproc: qcom: Add per subsystem SSR notification
Currently there is a single notification chain which is called whenever any remoteproc shuts down. This leads to all the listeners being notified, and is not an optimal design as kernel drivers might only be interested in listening to notifications from a particular remoteproc. Create a global list of remoteproc notification info data structures. This will hold the name and notifier_list information for a particular remoteproc. The API to register for notifications will use name argument to retrieve the notification info data structure and the notifier block will be added to that data structure's notification chain. Also move from blocking notifier to srcu notifer based implementation to support dynamic notifier head creation. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 90 ++- drivers/remoteproc/qcom_common.h | 5 +- include/linux/remoteproc/qcom_rproc.h | 20 ++-- 3 files changed, 95 insertions(+), 20 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 9028cea..7a7384c 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,14 @@ #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) -static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); +struct qcom_ssr_subsystem { + const char *name; + struct srcu_notifier_head notifier_list; + struct list_head list; +}; + +static LIST_HEAD(qcom_ssr_subsystem_list); +static DEFINE_MUTEX(qcom_ssr_subsys_lock); static int glink_subdev_start(struct rproc_subdev *subdev) { @@ -189,37 +197,83 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) } EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); +static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) +{ + struct qcom_ssr_subsystem *info; + + mutex_lock(_ssr_subsys_lock); + /* Match in the global qcom_ssr_subsystem_list with name */ + list_for_each_entry(info, _ssr_subsystem_list, list) + if (!strcmp(info->name, name)) + goto out; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + info = ERR_PTR(-ENOMEM); + goto out; + } + info->name = kstrdup_const(name, GFP_KERNEL); + srcu_init_notifier_head(>notifier_list); + + /* Add to global notification list */ + list_add_tail(>list, _ssr_subsystem_list); + +out: + mutex_unlock(_ssr_subsys_lock); + return info; +} + /** * qcom_register_ssr_notifier() - register SSR notification handler - * @nb:notifier_block to notify for restart notifications + * @name: Subsystem's SSR name + * @nb:notifier_block to be invoked upon subsystem's state change * - * Returns 0 on success, negative errno on failure. + * This registers the @nb notifier block as part the notifier chain for a + * remoteproc associated with @name. The notifier block's callback + * will be invoked when the remote processor's SSR events occur + * (pre/post startup and pre/post shutdown). * - * This register the @notify function as handler for restart notifications. As - * remote processors are stopped this function will be called, with the SSR - * name passed as a parameter. + * Return: a subsystem cookie on success, ERR_PTR on failure. */ -int qcom_register_ssr_notifier(struct notifier_block *nb) +void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { - return blocking_notifier_chain_register(_notifiers, nb); + struct qcom_ssr_subsystem *info; + + info = qcom_ssr_get_subsys(name); + if (IS_ERR(info)) + return info; + + srcu_notifier_chain_register(>notifier_list, nb); + + return >notifier_list; } EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); /** * qcom_unregister_ssr_notifier() - unregister SSR notification handler + * @notify:subsystem coookie returned from qcom_register_ssr_notifier * @nb:notifier_block to unregister + * + * This function will unregister the notifier from the particular notifier + * chain. + * + * Return: 0 on success, %ENOENT otherwise. */ -void qcom_unregister_ssr_notifier(struct notifier_block *nb) +int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) { - blocking_notifier_chain_unregister(_notifiers, nb); + return srcu_notifier_chain_unregister(notify, nb); } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notify_data data = { + .name
[PATCH v6 0/2] Extend SSR notifications framework
This set of patches gives kernel client drivers the ability to register for a particular remoteproc's SSR notifications. Also the notifications are extended to before/after-powerup/shutdown stages. It also fixes the bug where clients need to register for notifications again if the platform driver is removed. This is done by creating a global list of per-remoteproc notification info data structures which remain static. An API is exported to register for a remoteproc's SSR notifications and uses remoteproc's ssr_name and notifier block as arguments. Changelog: v6 -> v5: - Fix mutec locking and naming convention v5 -> v4: - Make qcom_ssr_get_subsys static function - Fix mutex locking - Fix function comments v4 -> v3: - Fix naming convention v3 -> v2: - Create a global list of per remoteproc notification data structure - Pass ssr_name and crashed information as part of notification data - Move notification type enum to qcom_rproc.h from remoteproc.h v2 -> v1: - Fix commit text Rishabh Bhatnagar (1): remoteproc: qcom: Add per subsystem SSR notification Siddharth Gupta (1): remoteproc: qcom: Add notification types to SSR drivers/remoteproc/qcom_common.c | 128 ++ drivers/remoteproc/qcom_common.h | 5 +- include/linux/remoteproc/qcom_rproc.h | 36 -- 3 files changed, 149 insertions(+), 20 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 2/2] remoteproc: qcom: Add notification types to SSR
The SSR subdevice only adds callback for the unprepare event. Add callbacks for prepare, start and prepare events. The client driver for a particular remoteproc might be interested in knowing the status of the remoteproc while undergoing SSR, not just when the remoteproc has finished shutting down. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 44 ++- include/linux/remoteproc/qcom_rproc.h | 16 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 7a7384c..7ec4597 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -265,6 +265,44 @@ int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); +static int ssr_notify_prepare(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notify_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_POWERUP, ); + return 0; +} + +static int ssr_notify_start(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notify_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_POWERUP, ); + return 0; +} + +static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notify_data data = { + .name = ssr->info->name, + .crashed = crashed, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_SHUTDOWN, ); +} + static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); @@ -273,7 +311,8 @@ static void ssr_notify_unprepare(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, 0, ); + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_SHUTDOWN, ); } /** @@ -298,6 +337,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, } ssr->info = info; + ssr->subdev.prepare = ssr_notify_prepare; + ssr->subdev.start = ssr_notify_start; + ssr->subdev.stop = ssr_notify_stop; ssr->subdev.unprepare = ssr_notify_unprepare; rproc_add_subdev(rproc, >subdev); diff --git a/include/linux/remoteproc/qcom_rproc.h b/include/linux/remoteproc/qcom_rproc.h index 2a1d6d0..6470516 100644 --- a/include/linux/remoteproc/qcom_rproc.h +++ b/include/linux/remoteproc/qcom_rproc.h @@ -5,6 +5,22 @@ struct notifier_block; #if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON) +/** + * enum qcom_ssr_notify_type - Startup/Shutdown events related to a remoteproc + * processor. + * + * @QCOM_SSR_BEFORE_POWERUP: Remoteproc about to start (prepare stage) + * @QCOM_SSR_AFTER_POWERUP:Remoteproc is running (start stage) + * @QCOM_SSR_BEFORE_SHUTDOWN: Remoteproc crashed or shutting down (stop stage) + * @QCOM_SSR_AFTER_SHUTDOWN: Remoteproc is down (unprepare stage) + */ +enum qcom_ssr_notify_type { + QCOM_SSR_BEFORE_POWERUP, + QCOM_SSR_AFTER_POWERUP, + QCOM_SSR_BEFORE_SHUTDOWN, + QCOM_SSR_AFTER_SHUTDOWN, +}; + struct qcom_ssr_notify_data { const char *name; bool crashed; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v5 2/3] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_coredump.c | 162 +++ include/linux/remoteproc.h | 21 +++- 3 files changed, 167 insertions(+), 25 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 903b2bb..d4ff9b8 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1200,12 +1200,13 @@ static int q6v5_mpss_load(struct q6v5 *qproc) static void qcom_q6v5_dump_segment(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest) + void *dest, size_t cp_offset, size_t size) { int ret = 0; struct q6v5 *qproc = rproc->priv; unsigned long mask = BIT((unsigned long)segment->priv); int offset = segment->da - qproc->mpss_reloc; + size_t cp_size = size ? size : segment->size; void *ptr = NULL; /* Unlock mba before copying segments */ @@ -1221,13 +1222,13 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } if (!ret) - ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); + ptr = ioremap_wc(qproc->mpss_phys + offset + cp_offset, cp_size); if (ptr) { - memcpy(dest, ptr, segment->size); + memcpy(dest, ptr, cp_size); iounmap(ptr); } else { - memset(dest, 0xff, segment->size); + memset(dest, 0xff, cp_size); } qproc->dump_segment_mask |= mask; diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..e643a66 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -5,6 +5,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -12,6 +13,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -72,7 +79,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv) { struct rproc_dump_segment *segment; @@ -114,12 +122,112 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + complete(_state->dump_done); + vfree(dump_state->header); +} + +static void *rproc_coredump_find_segment(loff_t user_offset, +struct list_head *segments, +size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment; + } + user_offset -= segment->size; + } + + *data_left = 0; + return NULL; +} + +static void rproc_copy_segment(struct rproc *rproc, void *dest, + struct rproc_dump_segment *segment, + size_t offset, size_t size) +{ + void *ptr; + + if (segment->dump) { + segment->dump(rproc, segment, dest, offset, size); + } else { + ptr = rproc_da_to_va(rproc, segment->da + offset, size); + if (!ptr) { + dev_err(>dev, + "invalid copy request (%zu, %zu)\n", +
[PATCH v5 3/3] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/remoteproc_debugfs.c | 86 + 1 file changed, 86 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..cca0a91 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,90 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + const char *buf = rproc_coredump_str[rproc->dump_conf]; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "inline", count)) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else if (!strncmp(buf, "default", count)) { + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +421,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v5 1/3] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index e8b886e..8702a4e 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9f04c30..57db042 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1239,19 +1237,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1518,182 +1503,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) - return -EINVAL; - -
[PATCH v5 0/3] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled until all data is read by userspace. Changelog: v5 -> v4: - Rebase on top of linux-next v4 -> v3: - Write a helper function to copy segment memory for every dump format - Change segment dump fn to add offset and size adn covert mss driver v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (3): remoteproc: Move coredump functionality to a new file remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 328 +++ drivers/remoteproc/remoteproc_debugfs.c | 86 drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 21 +- 7 files changed, 443 insertions(+), 197 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v5 1/2] remoteproc: qcom: Add per subsystem SSR notification
Currently there is a single notification chain which is called whenever any remoteproc shuts down. This leads to all the listeners being notified, and is not an optimal design as kernel drivers might only be interested in listening to notifications from a particular remoteproc. Create a global list of remoteproc notification info data structures. This will hold the name and notifier_list information for a particular remoteproc. The API to register for notifications will use name argument to retrieve the notification info data structure and the notifier block will be added to that data structure's notification chain. Also move from blocking notifier to srcu notifer based implementation to support dynamic notifier head creation. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 86 +-- drivers/remoteproc/qcom_common.h | 5 +- include/linux/remoteproc/qcom_rproc.h | 20 ++-- 3 files changed, 91 insertions(+), 20 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 9028cea..658f2ca 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,14 @@ #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) -static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); +struct qcom_ssr_subsystem { + const char *name; + struct srcu_notifier_head notifier_list; + struct list_head list; +}; + +static LIST_HEAD(qcom_ssr_subsystem_list); +static DEFINE_MUTEX(qcom_ssr_subsys_lock); static int glink_subdev_start(struct rproc_subdev *subdev) { @@ -189,37 +197,80 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) } EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); +static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) +{ + struct qcom_ssr_subsystem *info; + + mutex_lock(_ssr_subsys_lock); + /* Match in the global qcom_ssr_subsystem_list with name */ + list_for_each_entry(info, _ssr_subsystem_list, list) + if (!strcmp(info->name, name)) + return info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + info->name = kstrdup_const(name, GFP_KERNEL); + srcu_init_notifier_head(>notifier_list); + + /* Add to global notification list */ + list_add_tail(>list, _ssr_subsystem_list); + mutex_unlock(_ssr_subsys_lock); + + return info; +} + /** * qcom_register_ssr_notifier() - register SSR notification handler - * @nb:notifier_block to notify for restart notifications + * @name: Subsystem's SSR name + * @nb:notifier_block to be invoked upon subsystem's state change * - * Returns 0 on success, negative errno on failure. + * This registers the @nb notifier block as part the notifier chain for a + * remoteproc associated with @name. The notifier block's callback + * will be invoked when the remote processor's SSR events occur + * (pre/post startup and pre/post shutdown). * - * This register the @notify function as handler for restart notifications. As - * remote processors are stopped this function will be called, with the SSR - * name passed as a parameter. + * Return: a subsystem cookie on success, ERR_PTR on failure. */ -int qcom_register_ssr_notifier(struct notifier_block *nb) +void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { - return blocking_notifier_chain_register(_notifiers, nb); + struct qcom_ssr_subsystem *info; + + info = qcom_ssr_get_subsys(name); + if (IS_ERR(info)) + return info; + + srcu_notifier_chain_register(>notifier_list, nb); + + return >notifier_list; } EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); /** * qcom_unregister_ssr_notifier() - unregister SSR notification handler + * @notify:subsystem coookie returned from qcom_register_ssr_notifier * @nb:notifier_block to unregister + * + * This function will unregister the notifier from the particular notifier + * chain. + * + * Return: 0 on success, %ENOENT otherwise. */ -void qcom_unregister_ssr_notifier(struct notifier_block *nb) +int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) { - blocking_notifier_chain_unregister(_notifiers, nb); + return srcu_notifier_chain_unregister(notify, nb); } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, +
[PATCH v5 0/2] Extend SSR notifications framework
This set of patches gives kernel client drivers the ability to register for a particular remoteproc's SSR notifications. Also the notifications are extended to before/after-powerup/shutdown stages. It also fixes the bug where clients need to register for notifications again if the platform driver is removed. This is done by creating a global list of per-remoteproc notification info data structures which remain static. An API is exported to register for a remoteproc's SSR notifications and uses remoteproc's ssr_name and notifier block as arguments. Changelog: v5 -> v4: - Make qcom_ssr_get_subsys static function - Fix mutex locking - Fix function comments v4 -> v3: - Fix naming convention v3 -> v2: - Create a global list of per remoteproc notification data structure - Pass ssr_name and crashed information as part of notification data - Move notification type enum to qcom_rproc.h from remoteproc.h v2 -> v1: - Fix commit text Rishabh Bhatnagar (1): remoteproc: qcom: Add per subsystem SSR notification Siddharth Gupta (1): remoteproc: qcom: Add notification types to SSR drivers/remoteproc/qcom_common.c | 128 ++ drivers/remoteproc/qcom_common.h | 5 +- include/linux/remoteproc/qcom_rproc.h | 36 -- 3 files changed, 149 insertions(+), 20 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v5 2/2] remoteproc: qcom: Add notification types to SSR
The SSR subdevice only adds callback for the unprepare event. Add callbacks for prepare, start and prepare events. The client driver for a particular remoteproc might be interested in knowing the status of the remoteproc while undergoing SSR, not just when the remoteproc has finished shutting down. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 44 ++- include/linux/remoteproc/qcom_rproc.h | 16 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 658f2ca..0848bf1 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -262,6 +262,44 @@ int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); +static int ssr_notify_prepare(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_POWERUP, ); + return 0; +} + +static int ssr_notify_start(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_POWERUP, ); + return 0; +} + +static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = crashed, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_SHUTDOWN, ); +} + static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); @@ -270,7 +308,8 @@ static void ssr_notify_unprepare(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, 0, ); + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_SHUTDOWN, ); } /** @@ -294,6 +333,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, } ssr->info = info; + ssr->subdev.prepare = ssr_notify_prepare; + ssr->subdev.start = ssr_notify_start; + ssr->subdev.stop = ssr_notify_stop; ssr->subdev.unprepare = ssr_notify_unprepare; rproc_add_subdev(rproc, >subdev); diff --git a/include/linux/remoteproc/qcom_rproc.h b/include/linux/remoteproc/qcom_rproc.h index 58422b1..83ac8e8 100644 --- a/include/linux/remoteproc/qcom_rproc.h +++ b/include/linux/remoteproc/qcom_rproc.h @@ -5,6 +5,22 @@ struct notifier_block; #if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON) +/** + * enum qcom_ssr_notif_type - Startup/Shutdown events related to a remoteproc + * processor. + * + * @QCOM_SSR_BEFORE_POWERUP: Remoteproc about to start (prepare stage) + * @QCOM_SSR_AFTER_POWERUP:Remoteproc is running (start stage) + * @QCOM_SSR_BEFORE_SHUTDOWN: Remoteproc crashed or shutting down (stop stage) + * @QCOM_SSR_AFTER_SHUTDOWN: Remoteproc is down (unprepare stage) + */ +enum qcom_ssr_notif_type { + QCOM_SSR_BEFORE_POWERUP, + QCOM_SSR_AFTER_POWERUP, + QCOM_SSR_BEFORE_SHUTDOWN, + QCOM_SSR_AFTER_SHUTDOWN, +}; + struct qcom_ssr_notif_data { const char *name; bool crashed; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v4 1/2] remoteproc: qcom: Add per subsystem SSR notification
Currently there is a single notification chain which is called whenever any remoteproc shuts down. This leads to all the listeners being notified, and is not an optimal design as kernel drivers might only be interested in listening to notifications from a particular remoteproc. Create a global list of remoteproc notification info data structures. This will hold the name and notifier_list information for a particular remoteproc. The API to register for notifications will use name argument to retrieve the notification info data structure and the notifier block will be added to that data structure's notification chain. Also move from blocking notifier to srcu notifer based implementation to support dynamic notifier head creation. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 84 ++- drivers/remoteproc/qcom_common.h | 5 ++- include/linux/remoteproc/qcom_rproc.h | 20 ++--- 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 9028cea..61ff2dd 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,14 @@ #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) -static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); +struct qcom_ssr_subsystem { + const char *name; + struct srcu_notifier_head notifier_list; + struct list_head list; +}; + +static LIST_HEAD(qcom_ssr_subsystem_list); +DEFINE_MUTEX(qcom_ssr_subsys_lock); static int glink_subdev_start(struct rproc_subdev *subdev) { @@ -189,39 +197,79 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) } EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); +struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) +{ + struct qcom_ssr_subsystem *info; + + /* Match in the global qcom_ssr_subsystem_list with name */ + list_for_each_entry(info, _ssr_subsystem_list, list) { + if (!strcmp(info->name, name)) + return info; + } + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + info->name = kstrdup_const(name, GFP_KERNEL); + srcu_init_notifier_head(>notifier_list); + + /* Add to global notif list */ + INIT_LIST_HEAD(>list); + list_add_tail(>list, _ssr_subsystem_list); + + return info; +} + /** * qcom_register_ssr_notifier() - register SSR notification handler + * @name: name that will be searched in global ssr subsystem list * @nb:notifier_block to notify for restart notifications * - * Returns 0 on success, negative errno on failure. + * Returns a subsystem cookie on success, ERR_PTR on failure. * - * This register the @notify function as handler for restart notifications. As - * remote processors are stopped this function will be called, with the SSR - * name passed as a parameter. + * This registers the @nb notifier block as part the notifier chain for a + * remoteproc associated with @name. The notifier block's callback + * will be invoked when the particular remote processor is stopped. */ -int qcom_register_ssr_notifier(struct notifier_block *nb) +void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { - return blocking_notifier_chain_register(_notifiers, nb); + struct qcom_ssr_subsystem *info; + + mutex_lock(_ssr_subsys_lock); + info = qcom_ssr_get_subsys(name); + if (IS_ERR(info)) { + mutex_unlock(_ssr_subsys_lock); + return info; + } + + srcu_notifier_chain_register(>notifier_list, nb); + mutex_unlock(_ssr_subsys_lock); + return >notifier_list; } EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); /** * qcom_unregister_ssr_notifier() - unregister SSR notification handler + * @notify:subsystem coookie returned from qcom_register_ssr_notifier * @nb:notifier_block to unregister */ -void qcom_unregister_ssr_notifier(struct notifier_block *nb) +int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) { - blocking_notifier_chain_unregister(_notifiers, nb); + return srcu_notifier_chain_unregister(notify, nb); } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; - blocking_notifier_call_chain(_notifiers, 0, (void *)ssr->name); + srcu_notifier_call
[PATCH v4 2/2] remoteproc: qcom: Add notification types to SSR
From: Siddharth Gupta The SSR subdevice only adds callback for the unprepare event. Add callbacks for unprepare, start and prepare events. The client driver for a particular remoteproc might be interested in knowing the status of the remoteproc while undergoing SSR, not just when the remoteproc has finished shutting down. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 46 +-- include/linux/remoteproc/qcom_rproc.h | 14 +++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 61ff2dd..5c5a1eb 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -228,7 +228,7 @@ struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) * * This registers the @nb notifier block as part the notifier chain for a * remoteproc associated with @name. The notifier block's callback - * will be invoked when the particular remote processor is stopped. + * will be invoked when the particular remote processor is started/stopped. */ void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { @@ -258,6 +258,44 @@ int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); +static int ssr_notify_prepare(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_POWERUP, ); + return 0; +} + +static int ssr_notify_start(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_POWERUP, ); + return 0; +} + +static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct qcom_ssr_notif_data data = { + .name = ssr->info->name, + .crashed = crashed, + }; + + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_BEFORE_SHUTDOWN, ); +} + static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); @@ -266,7 +304,8 @@ static void ssr_notify_unprepare(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, 0, ); + srcu_notifier_call_chain(>info->notifier_list, +QCOM_SSR_AFTER_SHUTDOWN, ); } @@ -294,6 +333,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, mutex_unlock(_ssr_subsys_lock); ssr->info = info; + ssr->subdev.prepare = ssr_notify_prepare; + ssr->subdev.start = ssr_notify_start; + ssr->subdev.stop = ssr_notify_stop; ssr->subdev.unprepare = ssr_notify_unprepare; rproc_add_subdev(rproc, >subdev); diff --git a/include/linux/remoteproc/qcom_rproc.h b/include/linux/remoteproc/qcom_rproc.h index 58422b1..a558183 100644 --- a/include/linux/remoteproc/qcom_rproc.h +++ b/include/linux/remoteproc/qcom_rproc.h @@ -5,6 +5,20 @@ #if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON) +/** + * enum qcom_ssr_notif_type - Different stages of remoteproc notifications + * @QCOM_SSR_BEFORE_SHUTDOWN: unprepare stage of remoteproc + * @QCOM_SSR_AFTER_SHUTDOWN: stop stage of remoteproc + * @QCOM_SSR_BEFORE_POWERUP: prepare stage of remoteproc + * @QCOM_SSR_AFTER_POWERUP:start stage of remoteproc + */ +enum qcom_ssr_notif_type { + QCOM_SSR_BEFORE_SHUTDOWN, + QCOM_SSR_AFTER_SHUTDOWN, + QCOM_SSR_BEFORE_POWERUP, + QCOM_SSR_AFTER_POWERUP, +}; + struct qcom_ssr_notif_data { const char *name; bool crashed; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v4 0/2] Extend SSR notifications framework
This set of patches gives kernel client drivers the ability to register for a particular remoteproc's SSR notifications. Also the notifications are extended to before/after-powerup/shutdown stages. It also fixes the bug where clients need to register for notifications again if the platform driver is removed. This is done by creating a global list of per-remoteproc notification info data structures which remain static. An API is exported to register for a remoteproc's SSR notifications and uses remoteproc's ssr_name and notifier block as arguments. Changelog: v4 -> v3: - Fix naming convention v3 -> v2: - Create a global list of per remoteproc notification data structure - Pass ssr_name and crashed information as part of notification data - Move notification type enum to qcom_rproc.h from remoteproc.h v2 -> v1: - Fix commit text Rishabh Bhatnagar (1): remoteproc: qcom: Add per subsystem SSR notification Siddharth Gupta (1): remoteproc: qcom: Add notification types to SSR drivers/remoteproc/qcom_common.c | 126 ++ drivers/remoteproc/qcom_common.h | 5 +- include/linux/remoteproc/qcom_rproc.h | 34 +++-- 3 files changed, 146 insertions(+), 19 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[v4 PATCH 0/3] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled until all data is read by userspace. Changelog: v4 -> v3: - Write a helper function to copy segment memory for every dump format - Change segment dump fn to add offset and size adn covert mss driver v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (3): remoteproc: Move coredump functionality to a new file remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 328 +++ drivers/remoteproc/remoteproc_debugfs.c | 86 drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 21 +- 7 files changed, 443 insertions(+), 197 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v4 1/3] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 0effd38..f1a33c3 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4bd0f45..22575f4 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1238,19 +1236,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1509,182 +1494,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) - return -EINVAL; - -
[PATCH v4 2/3] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/qcom_q6v5_mss.c | 9 +- drivers/remoteproc/remoteproc_coredump.c | 162 +++ include/linux/remoteproc.h | 21 +++- 3 files changed, 167 insertions(+), 25 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 38d2b21..a1aea19 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1231,12 +1231,13 @@ static int q6v5_mpss_load(struct q6v5 *qproc) static void qcom_q6v5_dump_segment(struct rproc *rproc, struct rproc_dump_segment *segment, - void *dest) + void *dest, size_t offset, size_t size) { int ret = 0; struct q6v5 *qproc = rproc->priv; unsigned long mask = BIT((unsigned long)segment->priv); - void *ptr = rproc_da_to_va(rproc, segment->da, segment->size); + size_t copy_size = size ? size : segment->size; + void *ptr = rproc_da_to_va(rproc, segment->da + offset, copy_size); /* Unlock mba before copying segments */ if (!qproc->dump_mba_loaded) { @@ -1251,9 +1252,9 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc, } if (!ptr || ret) - memset(dest, 0xff, segment->size); + memset(dest, 0xff, copy_size); else - memcpy(dest, ptr, segment->size); + memcpy(dest, ptr, copy_size); qproc->dump_segment_mask |= mask; diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..e643a66 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -5,6 +5,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -12,6 +13,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -72,7 +79,8 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, -void *dest), +void *dest, size_t offset, +size_t size), void *priv) { struct rproc_dump_segment *segment; @@ -114,12 +122,112 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + complete(_state->dump_done); + vfree(dump_state->header); +} + +static void *rproc_coredump_find_segment(loff_t user_offset, +struct list_head *segments, +size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment; + } + user_offset -= segment->size; + } + + *data_left = 0; + return NULL; +} + +static void rproc_copy_segment(struct rproc *rproc, void *dest, + struct rproc_dump_segment *segment, + size_t offset, size_t size) +{ + void *ptr; + + if (segment->dump) { + segment->dump(rproc, segment, dest, offset, size); + } else { + ptr = rproc_da_to_va(rproc, segment->da + offset, size); + if (!ptr) { + dev_err(>dev, + "invalid copy request (%zu, %zu)\n", + segment->
[PATCH v4 3/3] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar Reviewed-by: Bjorn Andersson Reviewed-by: Mathieu Poirier --- drivers/remoteproc/remoteproc_debugfs.c | 86 + 1 file changed, 86 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..cca0a91 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,90 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [RPROC_COREDUMP_DEFAULT]= "default", + [RPROC_COREDUMP_INLINE] = "inline", + [RPROC_COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + const char *buf = rproc_coredump_str[rproc->dump_conf]; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) { + rproc->dump_conf = RPROC_COREDUMP_DISABLED; + } else if (!strncmp(buf, "inline", count)) { + rproc->dump_conf = RPROC_COREDUMP_INLINE; + } else if (!strncmp(buf, "default", count)) { + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; + } else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +421,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 1/3] remoteproc: Move coredump functionality to a new file
Move all coredump functionality to an individual file. This is being done so that the current functionality can be extended in future patchsets. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 - drivers/remoteproc/remoteproc_coredump.c | 204 +++ drivers/remoteproc/remoteproc_internal.h | 4 + 4 files changed, 209 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 0effd38..f1a33c3 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o remoteproc-y := remoteproc_core.o +remoteproc-y += remoteproc_coredump.o remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4bd0f45..22575f4 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,6 @@ #include #include "remoteproc_internal.h" -#include "remoteproc_elf_helpers.h" #define HIGH_BITS_MASK 0xULL @@ -1238,19 +1236,6 @@ static int rproc_alloc_registered_carveouts(struct rproc *rproc) return 0; } -/** - * rproc_coredump_cleanup() - clean up dump_segments list - * @rproc: the remote processor handle - */ -static void rproc_coredump_cleanup(struct rproc *rproc) -{ - struct rproc_dump_segment *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, >dump_segments, node) { - list_del(>node); - kfree(entry); - } -} /** * rproc_resource_cleanup() - clean up and free all acquired resources @@ -1509,182 +1494,6 @@ static int rproc_stop(struct rproc *rproc, bool crashed) return 0; } -/** - * rproc_coredump_add_segment() - add segment of device memory to coredump - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * - * Add device memory to the list of segments to be included in a coredump for - * the remoteproc. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_segment); - -/** - * rproc_coredump_add_custom_segment() - add custom coredump segment - * @rproc: handle of a remote processor - * @da:device address - * @size: size of segment - * @dumpfn:custom dump function called for each segment during coredump - * @priv: private data - * - * Add device memory to the list of segments to be included in the coredump - * and associate the segment with the given custom dump function and private - * data. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_add_custom_segment(struct rproc *rproc, - dma_addr_t da, size_t size, - void (*dumpfn)(struct rproc *rproc, -struct rproc_dump_segment *segment, -void *dest), - void *priv) -{ - struct rproc_dump_segment *segment; - - segment = kzalloc(sizeof(*segment), GFP_KERNEL); - if (!segment) - return -ENOMEM; - - segment->da = da; - segment->size = size; - segment->priv = priv; - segment->dump = dumpfn; - - list_add_tail(>node, >dump_segments); - - return 0; -} -EXPORT_SYMBOL(rproc_coredump_add_custom_segment); - -/** - * rproc_coredump_set_elf_info() - set coredump elf information - * @rproc: handle of a remote processor - * @class: elf class for coredump elf file - * @machine: elf machine for coredump elf file - * - * Set elf information which will be used for coredump elf file. - * - * Return: 0 on success, negative errno on error. - */ -int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) -{ - if (class != ELFCLASS64 && class != ELFCLASS32) - return -EINVAL; - - rproc->elf_class = class; - rproc->elf_machine = mach
[PATCH v3 3/3] remoteproc: Add coredump debugfs entry
Add coredump debugfs entry to configure the type of dump that will be collected during recovery. User can select between default or inline coredump functionality. Also coredump collection can be disabled through this interface. This functionality can be configured differently for different remote processors. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/remoteproc_debugfs.c | 86 + 1 file changed, 86 insertions(+) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 732770e..2f611de 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,90 @@ static struct dentry *rproc_dbg; /* + * A coredump-configuration-to-string lookup table, for exposing a + * human readable configuration via debugfs. Always keep in sync with + * enum rproc_coredump_mechanism + */ +static const char * const rproc_coredump_str[] = { + [COREDUMP_DEFAULT] = "default", + [COREDUMP_INLINE] = "inline", + [COREDUMP_DISABLED] = "disabled", +}; + +/* Expose the current coredump configuration via debugfs */ +static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + const char *buf = rproc_coredump_str[rproc->dump_conf]; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +/* + * By writing to the 'coredump' debugfs entry, we control the behavior of the + * coredump mechanism dynamically. The default value of this entry is "default". + * + * The 'coredump' debugfs entry supports these commands: + * + * default:This is the default coredump mechanism. When the remoteproc + * crashes the entire coredump will be copied to a separate buffer + * and exposed to userspace. + * + * inline: The coredump will not be copied to a separate buffer and the + * recovery process will have to wait until data is read by + * userspace. But this avoid usage of extra memory. + * + * disabled: This will disable coredump. Recovery will proceed without + * collecting any dump. + */ +static ssize_t rproc_coredump_write(struct file *filp, +const char __user *user_buf, size_t count, +loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + int ret, err = 0; + char buf[20]; + + if (count > sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (rproc->state == RPROC_CRASHED) { + dev_err(>dev, "can't change coredump configuration\n"); + err = -EBUSY; + goto out; + } + + if (!strncmp(buf, "disable", count)) + rproc->dump_conf = COREDUMP_DISABLED; + else if (!strncmp(buf, "inline", count)) + rproc->dump_conf = COREDUMP_INLINE; + else if (!strncmp(buf, "default", count)) + rproc->dump_conf = COREDUMP_DEFAULT; + else { + dev_err(>dev, "Invalid coredump configuration\n"); + err = -EINVAL; + } +out: + return err ? err : count; +} + +static const struct file_operations rproc_coredump_fops = { + .read = rproc_coredump_read, + .write = rproc_coredump_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +/* * Some remote processors may support dumping trace logs into a shared * memory buffer. We expose this trace buffer using debugfs, so users * can easily tell what's going on remotely. @@ -337,6 +421,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, _rsc_table_fops); debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, rproc, _carveouts_fops); + debugfs_create_file("coredump", 0600, rproc->dbg_dir, + rproc, _coredump_fops); } void __init rproc_init_debugfs(void) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 0/3] Extend coredump functionality
This patch series moves the coredump functionality to a separate file and adds "inline" coredump feature. Inline coredump directly copies segments from device memory during coredump to userspace. This avoids extra memory usage at the cost of speed. Recovery is stalled untill all data is read by userspace. Changelog: v3 -> v2: - Move entire coredump functionality to remoteproc_coredump.c - Modify rproc_coredump to perform dump according to conf. set by userspace - Move the userspace configuration to debugfs from sysfs. - Keep the default coredump implementation as is v2 -> v1: - Introduce new file for coredump. - Add userspace sysfs configuration for dump type. Rishabh Bhatnagar (3): remoteproc: Move coredump functionality to a new file remoteproc: Add inline coredump functionality remoteproc: Add coredump debugfs entry drivers/remoteproc/Makefile | 1 + drivers/remoteproc/remoteproc_core.c | 191 -- drivers/remoteproc/remoteproc_coredump.c | 322 +++ drivers/remoteproc/remoteproc_debugfs.c | 86 + drivers/remoteproc/remoteproc_internal.h | 4 + include/linux/remoteproc.h | 15 ++ 6 files changed, 428 insertions(+), 191 deletions(-) create mode 100644 drivers/remoteproc/remoteproc_coredump.c -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 2/3] remoteproc: Add inline coredump functionality
The current coredump implementation uses vmalloc area to copy all the segments. But this might put strain on low memory targets as the firmware size sometimes is in tens of MBs. The situation becomes worse if there are multiple remote processors undergoing recovery at the same time. This patch adds inline coredump functionality that avoids extra memory usage. This requires recovery to be halted until data is read by userspace and free function is called. Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/remoteproc_coredump.c | 129 +-- include/linux/remoteproc.h | 15 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index ded0244..de75e89 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -12,6 +12,12 @@ #include "remoteproc_internal.h" #include "remoteproc_elf_helpers.h" +struct rproc_coredump_state { + struct rproc *rproc; + void *header; + struct completion dump_done; +}; + /** * rproc_coredump_cleanup() - clean up dump_segments list * @rproc: the remote processor handle @@ -114,12 +120,96 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) } EXPORT_SYMBOL(rproc_coredump_set_elf_info); +static void rproc_coredump_free(void *data) +{ + struct rproc_coredump_state *dump_state = data; + + complete(_state->dump_done); + vfree(dump_state->header); +} + +static unsigned long rproc_coredump_find_segment(loff_t user_offset, + struct list_head *segments, + size_t *data_left) +{ + struct rproc_dump_segment *segment; + + list_for_each_entry(segment, segments, node) { + if (user_offset < segment->size) { + *data_left = segment->size - user_offset; + return segment->da + user_offset; + } + user_offset -= segment->size; + } + + *data_left = 0; + return 0; +} + +static ssize_t rproc_coredump_read(char *buffer, loff_t offset, size_t count, + void *data, size_t header_sz) +{ + void *device_mem; + size_t seg_data; + size_t copy_sz, bytes_left = count; + unsigned long addr; + struct rproc_coredump_state *dump_state = data; + struct rproc *rproc = dump_state->rproc; + void *elfcore = dump_state->header; + + /* Copy the vmalloc'ed header first. */ + if (offset < header_sz) { + copy_sz = memory_read_from_buffer(buffer, count, , + elfcore, header_sz); + if (copy_sz < 0) + return -EINVAL; + + return copy_sz; + } + + /* Find out the segment memory chunk to be copied based on offset. +* Keep copying data until count bytes are read. +*/ + while (bytes_left) { + addr = rproc_coredump_find_segment(offset - header_sz, + >dump_segments, + _data); + /* EOF check */ + if (seg_data == 0) { + dev_info(>dev, "Ramdump done, %lld bytes read", +offset); + break; + } + + copy_sz = min_t(size_t, bytes_left, seg_data); + + device_mem = rproc_da_to_va(rproc, addr, copy_sz); + if (!device_mem) { + dev_err(>dev, "Coredump: %lx with size %zd out of remoteproc carveout\n", + addr, copy_sz); + return -ENOMEM; + } + memcpy(buffer, device_mem, copy_sz); + + offset += copy_sz; + buffer += copy_sz; + bytes_left -= copy_sz; + } + + return count - bytes_left; +} + /** * rproc_coredump() - perform coredump * @rproc: rproc handle * * This function will generate an ELF header for the registered segments - * and create a devcoredump device associated with rproc. + * and create a devcoredump device associated with rproc. Based on the + * coredump configuration this function will directly copy the segments + * from device memory to userspace or copy segments from device memory to + * a separate buffer, which can then be read by userspace. + * The first approach avoids using extra vmalloc memory. But it will stall + * recovery flow until dump is read by userspace. */ void rproc_coredump(struct rproc *rproc) { @@ -132,8 +222,10 @@ void rproc_coredump(struct rproc *rproc) void *ptr; u8 class = rproc
[PATCH] remoteproc: core: Prevent system suspend during remoteproc recovery
The system might go into suspend during recovery of any remoteproc. This will interrupt the recovery process in between increasing the recovery time. Make the platform device as wakeup capable and use pm_stay_wake/pm_relax APIs to avoid system from going into suspend during recovery. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar Acked-by: Mathieu Poirier --- drivers/remoteproc/qcom_q6v5_pas.c | 2 ++ drivers/remoteproc/remoteproc_core.c | 5 + 2 files changed, 7 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index edf9d0e..e608578 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -398,6 +398,8 @@ static int adsp_probe(struct platform_device *pdev) adsp->has_aggre2_clk = desc->has_aggre2_clk; platform_set_drvdata(pdev, adsp); + device_wakeup_enable(adsp->dev); + ret = adsp_alloc_memory_region(adsp); if (ret) goto free_rproc; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 097f33e..6a1cb98 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1712,6 +1712,8 @@ static void rproc_crash_handler_work(struct work_struct *work) if (!rproc->recovery_disabled) rproc_trigger_recovery(rproc); + + pm_relax(rproc->dev.parent); } /** @@ -2208,6 +2210,9 @@ void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) return; } + /* Prevent suspend while the remoteproc is being recovered */ + pm_stay_awake(rproc->dev.parent); + dev_err(>dev, "crash detected in %s: type %s\n", rproc->name, rproc_crash_to_string(type)); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 1/2] remoteproc: qcom: Add per subsystem SSR notification
Currently there is a single notification chain which is called whenever any remoteproc shuts down. This leads to all the listeners being notified, and is not an optimal design as kernel drivers might only be interested in listening to notifications from a particular remoteproc. Create a global list of remoteproc notification info data structures. This will hold the name and notifier_list information for a particular remoteproc. The API to register for notifications will use name argument to retrieve the notification info data structure and the notifier block will be added to that data structure's notification chain. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 89 ++- drivers/remoteproc/qcom_common.h | 10 +++- include/linux/remoteproc/qcom_rproc.h | 20 ++-- 3 files changed, 99 insertions(+), 20 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 60650bc..7cd17be 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -15,16 +15,18 @@ #include #include #include +#include #include "remoteproc_internal.h" #include "qcom_common.h" +#define MAX_NAME_LEN 20 +DEFINE_MUTEX(rproc_notif_lock); + #define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev) #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) -static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); - static int glink_subdev_start(struct rproc_subdev *subdev) { struct qcom_rproc_glink *glink = to_glink_subdev(subdev); @@ -174,39 +176,81 @@ void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) } EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); +struct rproc_notif_info *find_notif_info(const char *name) +{ + struct rproc_notif_info *info; + + /* Match in the global rproc_notif_list with name */ + list_for_each_entry(info, _notif_list, list) { + if (!strncmp(info->name, name, strlen(name))) + return info; + } + return NULL; +} + /** * qcom_register_ssr_notifier() - register SSR notification handler + * @name: pointer to name which will be searched in the global notif_list * @nb:notifier_block to notify for restart notifications * - * Returns 0 on success, negative errno on failure. + * Returns pointer to srcu notifier head on success, ERR_PTR on failure. * - * This register the @notify function as handler for restart notifications. As - * remote processors are stopped this function will be called, with the SSR - * name passed as a parameter. + * This registers the @nb notifier block as part the notifier chain for a + * remoteproc associated with @name. The notifier block's callback + * will be invoked when the particular remote processor is stopped. */ -int qcom_register_ssr_notifier(struct notifier_block *nb) +void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { - return blocking_notifier_chain_register(_notifiers, nb); + struct rproc_notif_info *info; + + mutex_lock(_notif_lock); + info = find_notif_info(name); + if (!info) { + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + mutex_unlock(_notif_lock); + return ERR_PTR(-ENOMEM); + } + info->name = kstrndup(name, MAX_NAME_LEN, GFP_KERNEL); + srcu_init_notifier_head(>notifier_list); + + /* Add to global notif list */ + INIT_LIST_HEAD(>list); + list_add_tail(>list, _notif_list); + } + + srcu_notifier_chain_register(>notifier_list, nb); + mutex_unlock(_notif_lock); + return >notifier_list; } EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); /** * qcom_unregister_ssr_notifier() - unregister SSR notification handler + * @notify:pointer to srcu notifier head * @nb:notifier_block to unregister */ -void qcom_unregister_ssr_notifier(struct notifier_block *nb) +int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) { - blocking_notifier_chain_unregister(_notifiers, nb); + if (!notify) + return -EINVAL; + + return srcu_notifier_chain_unregister(notify, nb); } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct rproc_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; - blocking_notifier_call_chain(_notifiers, 0, (void *)ssr->name); + srcu_notifier_call_chain(>info->notifier_list, 0, ); }
[PATCH v3 0/2] Extend SSR notifications framework
This set of patches gives kernel client drivers the ability to register for a particular remoteproc's SSR notifications. Also the notifications are extended to before/after-powerup/shutdown stages. It also fixes the bug where clients need to register for notifications again if the platform driver is removed. This is done by creating a global list of per-remoteproc notification info data structures which remain static. An API is exported to register for a remoteproc's SSR notifications and uses remoteproc's ssr_name and notifier block as arguments. Rishabh Bhatnagar (1): remoteproc: qcom: Add per subsystem SSR notification Siddharth Gupta (1): remoteproc: qcom: Add notification types to SSR v3 -> v2: - Create a global list of per remoteproc notification data structure - Pass ssr_name and crashed information as part of notification data - Move notification type enum to qcom_rproc.h from remoteproc.h v2 -> v1: - Fix commit text drivers/remoteproc/qcom_common.c | 133 ++ drivers/remoteproc/qcom_common.h | 11 ++- include/linux/remoteproc/qcom_rproc.h | 34 +++-- 3 files changed, 157 insertions(+), 21 deletions(-) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v3 2/2] remoteproc: qcom: Add notification types to SSR
From: Siddharth Gupta The SSR subdevice only adds callback for the unprepare event. Add callbacks for unprepare, start and prepare events. The client driver for a particular remoteproc might be interested in knowing the status of the remoteproc while undergoing SSR, not just when the remoteproc has finished shutting down. Signed-off-by: Siddharth Gupta Signed-off-by: Rishabh Bhatnagar --- drivers/remoteproc/qcom_common.c | 46 +-- include/linux/remoteproc/qcom_rproc.h | 14 +++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 7cd17be..0d91cf3 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -197,7 +197,7 @@ struct rproc_notif_info *find_notif_info(const char *name) * * This registers the @nb notifier block as part the notifier chain for a * remoteproc associated with @name. The notifier block's callback - * will be invoked when the particular remote processor is stopped. + * will be invoked when the particular remote processor is started/stopped. */ void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) { @@ -239,6 +239,44 @@ int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); +static int ssr_notify_prepare(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct rproc_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +RPROC_BEFORE_POWERUP, ); + return 0; +} + +static int ssr_notify_start(struct rproc_subdev *subdev) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct rproc_notif_data data = { + .name = ssr->info->name, + .crashed = false, + }; + + srcu_notifier_call_chain(>info->notifier_list, +RPROC_AFTER_POWERUP, ); + return 0; +} + +static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) +{ + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); + struct rproc_notif_data data = { + .name = ssr->info->name, + .crashed = crashed, + }; + + srcu_notifier_call_chain(>info->notifier_list, +RPROC_BEFORE_SHUTDOWN, ); +} + static void ssr_notify_unprepare(struct rproc_subdev *subdev) { struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); @@ -247,7 +285,8 @@ static void ssr_notify_unprepare(struct rproc_subdev *subdev) .crashed = false, }; - srcu_notifier_call_chain(>info->notifier_list, 0, ); + srcu_notifier_call_chain(>info->notifier_list, +RPROC_AFTER_SHUTDOWN, ); } @@ -282,6 +321,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, } mutex_unlock(_notif_lock); ssr->info = info; + ssr->subdev.prepare = ssr_notify_prepare; + ssr->subdev.start = ssr_notify_start; + ssr->subdev.stop = ssr_notify_stop; ssr->subdev.unprepare = ssr_notify_unprepare; rproc_add_subdev(rproc, >subdev); diff --git a/include/linux/remoteproc/qcom_rproc.h b/include/linux/remoteproc/qcom_rproc.h index 3dc65c0..567c1f9 100644 --- a/include/linux/remoteproc/qcom_rproc.h +++ b/include/linux/remoteproc/qcom_rproc.h @@ -5,6 +5,20 @@ #if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON) +/** + * enum rproc_notif_type - Different stages of remoteproc notifications + * @RPROC_BEFORE_SHUTDOWN: unprepare stage of remoteproc + * @RPROC_AFTER_SHUTDOWN: stop stage of remoteproc + * @RPROC_BEFORE_POWERUP: prepare stage of remoteproc + * @RPROC_AFTER_POWERUP: start stage of remoteproc + */ +enum rproc_notif_type { + RPROC_BEFORE_SHUTDOWN, + RPROC_AFTER_SHUTDOWN, + RPROC_BEFORE_POWERUP, + RPROC_AFTER_POWERUP, +}; + struct rproc_notif_data { const char *name; bool crashed; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v1] dd: Invoke one probe retry cycle after some initcall levels
From: Rishabh Bhatnagar Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level after subsys initcall, allowing these drivers to be probed earlier. To give an example many Qualcomm drivers are dependent on the regulator and bus driver. Both the regulator and bus driver are probed in the subsys_initcall level. Now the probe of bus driver requires regulator to be working. If the probe of bus driver happens before regulator, then bus driver's probe will be deferred and all other device's probes which depend on bus driver will also be deferred. The impact of this problem is reduced if we have this patch. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- Changes since v0: * Remove arch_initcall_sync(deferred_probe_initcall) from patch. This is not really needed as none of the devices are re-probed in arch_initcall_sync level. drivers/base/dd.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..9aa41aa 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,43 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v1] dd: Invoke one probe retry cycle after some initcall levels
From: Rishabh Bhatnagar Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level after subsys initcall, allowing these drivers to be probed earlier. To give an example many Qualcomm drivers are dependent on the regulator and bus driver. Both the regulator and bus driver are probed in the subsys_initcall level. Now the probe of bus driver requires regulator to be working. If the probe of bus driver happens before regulator, then bus driver's probe will be deferred and all other device's probes which depend on bus driver will also be deferred. The impact of this problem is reduced if we have this patch. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- Changes since v0: * Remove arch_initcall_sync(deferred_probe_initcall) from patch. This is not really needed as none of the devices are re-probed in arch_initcall_sync level. drivers/base/dd.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..9aa41aa 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,43 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v1] dd: Invoke one probe retry cycle after some initcall levels
Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level after subsys initcall, allowing these drivers to be probed earlier. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- To give an example many Qualcomm drivers are dependent on the regulator and bus driver. Both the regulator and bus driver are probed in the subsys_initcall level. Now the probe of bus driver requires regulator to be working. If the probe of bus driver happens before regulator, then bus driver's probe will be deferred and all other device's probes which depend on bus driver will also be deferred. The impact of this problem is reduced if we have this patch. Changes since v0: * Remove arch_initcall_sync(deferred_probe_initcall) from patch. This is not really needed as none of the devices are re-probed in arch_initcall_sync level. drivers/base/dd.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..9aa41aa 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,43 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v1] dd: Invoke one probe retry cycle after some initcall levels
Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level after subsys initcall, allowing these drivers to be probed earlier. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- To give an example many Qualcomm drivers are dependent on the regulator and bus driver. Both the regulator and bus driver are probed in the subsys_initcall level. Now the probe of bus driver requires regulator to be working. If the probe of bus driver happens before regulator, then bus driver's probe will be deferred and all other device's probes which depend on bus driver will also be deferred. The impact of this problem is reduced if we have this patch. Changes since v0: * Remove arch_initcall_sync(deferred_probe_initcall) from patch. This is not really needed as none of the devices are re-probed in arch_initcall_sync level. drivers/base/dd.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..9aa41aa 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,43 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] firmware: Fix security issue with request_firmware_into_buf()
When calling request_firmware_into_buf() with the FW_OPT_NOCACHE flag it is expected that firmware is loaded into buffer from memory. But inside alloc_lookup_fw_priv every new firmware that is loaded is added to the firmware cache (fwc) list head. So if any driver requests a firmware that is already loaded the code iterates over the above mentioned list and it can end up giving a pointer to other device driver's firmware buffer. Also the existing copy may either be modified by drivers, remote processors or even freed. This causes a potential security issue with batched requests when using request_firmware_into_buf. Fix alloc_lookup_fw_priv to not add to the fwc head list if FW_OPT_NOCACHE is set, and also don't do the lookup in the list. Fixes: 0e742e9275 ("firmware: provide infrastructure to make fw caching optional") Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/firmware_loader/main.c | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 0943e70..b3c0498 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -209,21 +209,24 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name) static int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, struct fw_priv **fw_priv, void *dbuf, - size_t size) + size_t size, enum fw_opt opt_flags) { struct fw_priv *tmp; spin_lock(>lock); - tmp = __lookup_fw_priv(fw_name); - if (tmp) { - kref_get(>ref); - spin_unlock(>lock); - *fw_priv = tmp; - pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); - return 1; + if (!(opt_flags & FW_OPT_NOCACHE)) { + tmp = __lookup_fw_priv(fw_name); + if (tmp) { + kref_get(>ref); + spin_unlock(>lock); + *fw_priv = tmp; + pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); + return 1; + } } + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); - if (tmp) + if (tmp && !(opt_flags & FW_OPT_NOCACHE)) list_add(>list, >head); spin_unlock(>lock); @@ -493,7 +496,8 @@ int assign_fw(struct firmware *fw, struct device *device, */ static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, - struct device *device, void *dbuf, size_t size) + struct device *device, void *dbuf, size_t size, + enum fw_opt opt_flags) { struct firmware *firmware; struct fw_priv *fw_priv; @@ -511,7 +515,8 @@ int assign_fw(struct firmware *fw, struct device *device, return 0; /* assigned */ } - ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size); + ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size, + opt_flags); /* * bind with 'priv' now to avoid warning in failure path @@ -571,7 +576,8 @@ static void fw_abort_batch_reqs(struct firmware *fw) goto out; } - ret = _request_firmware_prepare(, name, device, buf, size); + ret = _request_firmware_prepare(, name, device, buf, size, + opt_flags); if (ret <= 0) /* error or already assigned */ goto out; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] firmware: Fix security issue with request_firmware_into_buf()
When calling request_firmware_into_buf() with the FW_OPT_NOCACHE flag it is expected that firmware is loaded into buffer from memory. But inside alloc_lookup_fw_priv every new firmware that is loaded is added to the firmware cache (fwc) list head. So if any driver requests a firmware that is already loaded the code iterates over the above mentioned list and it can end up giving a pointer to other device driver's firmware buffer. Also the existing copy may either be modified by drivers, remote processors or even freed. This causes a potential security issue with batched requests when using request_firmware_into_buf. Fix alloc_lookup_fw_priv to not add to the fwc head list if FW_OPT_NOCACHE is set, and also don't do the lookup in the list. Fixes: 0e742e9275 ("firmware: provide infrastructure to make fw caching optional") Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/firmware_loader/main.c | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 0943e70..b3c0498 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -209,21 +209,24 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name) static int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, struct fw_priv **fw_priv, void *dbuf, - size_t size) + size_t size, enum fw_opt opt_flags) { struct fw_priv *tmp; spin_lock(>lock); - tmp = __lookup_fw_priv(fw_name); - if (tmp) { - kref_get(>ref); - spin_unlock(>lock); - *fw_priv = tmp; - pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); - return 1; + if (!(opt_flags & FW_OPT_NOCACHE)) { + tmp = __lookup_fw_priv(fw_name); + if (tmp) { + kref_get(>ref); + spin_unlock(>lock); + *fw_priv = tmp; + pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); + return 1; + } } + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); - if (tmp) + if (tmp && !(opt_flags & FW_OPT_NOCACHE)) list_add(>list, >head); spin_unlock(>lock); @@ -493,7 +496,8 @@ int assign_fw(struct firmware *fw, struct device *device, */ static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, - struct device *device, void *dbuf, size_t size) + struct device *device, void *dbuf, size_t size, + enum fw_opt opt_flags) { struct firmware *firmware; struct fw_priv *fw_priv; @@ -511,7 +515,8 @@ int assign_fw(struct firmware *fw, struct device *device, return 0; /* assigned */ } - ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size); + ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size, + opt_flags); /* * bind with 'priv' now to avoid warning in failure path @@ -571,7 +576,8 @@ static void fw_abort_batch_reqs(struct firmware *fw) goto out; } - ret = _request_firmware_prepare(, name, device, buf, size); + ret = _request_firmware_prepare(, name, device, buf, size, + opt_flags); if (ret <= 0) /* error or already assigned */ goto out; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] firmware: Avoid caching firmware when FW_OPT_NOCACHE is set
When calling request_firmware_into_buf(), we pass the FW_OPT_NOCACHE flag with the intent of skipping the caching mechanism of the firmware loader. Unfortunately, that doesn't work, because alloc_lookup_fw_priv() isn't told to _not_ add the struct firmware_buf to the firmware cache (fwc) list. So when we call request_firmware_into_buf() the second time, we find the buffer in the cache and return it immediately without reloading. This may break users of request_firmware_into_buf that are expecting a fresh copy of the firmware to be reloaded into memory. The existing copy may either be modified by drivers, remote processors or even freed. Fix fw_lookup_and_allocate_buf to not add to the fwc list if FW_OPT_NOCACHE is set, and also don't do the lookup in the list. Fixes: 0e742e9271 ("firmware: provide infrastructure to make fw caching optional") Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/firmware_loader/main.c | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 2e0c37a..db9038c0 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -210,21 +210,24 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name) static int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, struct fw_priv **fw_priv, void *dbuf, - size_t size) + size_t size, enum fw_opt opt_flags) { struct fw_priv *tmp; spin_lock(>lock); - tmp = __lookup_fw_priv(fw_name); - if (tmp) { - kref_get(>ref); - spin_unlock(>lock); - *fw_priv = tmp; - pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); - return 1; + if (!(opt_flags & FW_OPT_NOCACHE)) { + tmp = __lookup_fw_priv(fw_name); + if (tmp) { + kref_get(>ref); + spin_unlock(>lock); + *fw_priv = tmp; + pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); + return 1; + } } + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); - if (tmp) + if (tmp && !(opt_flags & FW_OPT_NOCACHE)) list_add(>list, >head); spin_unlock(>lock); @@ -500,7 +503,8 @@ int assign_fw(struct firmware *fw, struct device *device, */ static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, - struct device *device, void *dbuf, size_t size) + struct device *device, void *dbuf, size_t size, + enum fw_opt opt_flags) { struct firmware *firmware; struct fw_priv *fw_priv; @@ -518,7 +522,8 @@ int assign_fw(struct firmware *fw, struct device *device, return 0; /* assigned */ } - ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size); + ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size, + opt_flags); /* * bind with 'priv' now to avoid warning in failure path @@ -578,7 +583,8 @@ static void fw_abort_batch_reqs(struct firmware *fw) goto out; } - ret = _request_firmware_prepare(, name, device, buf, size); + ret = _request_firmware_prepare(, name, device, buf, size, + opt_flags); if (ret <= 0) /* error or already assigned */ goto out; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] firmware: Avoid caching firmware when FW_OPT_NOCACHE is set
When calling request_firmware_into_buf(), we pass the FW_OPT_NOCACHE flag with the intent of skipping the caching mechanism of the firmware loader. Unfortunately, that doesn't work, because alloc_lookup_fw_priv() isn't told to _not_ add the struct firmware_buf to the firmware cache (fwc) list. So when we call request_firmware_into_buf() the second time, we find the buffer in the cache and return it immediately without reloading. This may break users of request_firmware_into_buf that are expecting a fresh copy of the firmware to be reloaded into memory. The existing copy may either be modified by drivers, remote processors or even freed. Fix fw_lookup_and_allocate_buf to not add to the fwc list if FW_OPT_NOCACHE is set, and also don't do the lookup in the list. Fixes: 0e742e9271 ("firmware: provide infrastructure to make fw caching optional") Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/firmware_loader/main.c | 30 ++ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 2e0c37a..db9038c0 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -210,21 +210,24 @@ static struct fw_priv *__lookup_fw_priv(const char *fw_name) static int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, struct fw_priv **fw_priv, void *dbuf, - size_t size) + size_t size, enum fw_opt opt_flags) { struct fw_priv *tmp; spin_lock(>lock); - tmp = __lookup_fw_priv(fw_name); - if (tmp) { - kref_get(>ref); - spin_unlock(>lock); - *fw_priv = tmp; - pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); - return 1; + if (!(opt_flags & FW_OPT_NOCACHE)) { + tmp = __lookup_fw_priv(fw_name); + if (tmp) { + kref_get(>ref); + spin_unlock(>lock); + *fw_priv = tmp; + pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); + return 1; + } } + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); - if (tmp) + if (tmp && !(opt_flags & FW_OPT_NOCACHE)) list_add(>list, >head); spin_unlock(>lock); @@ -500,7 +503,8 @@ int assign_fw(struct firmware *fw, struct device *device, */ static int _request_firmware_prepare(struct firmware **firmware_p, const char *name, - struct device *device, void *dbuf, size_t size) + struct device *device, void *dbuf, size_t size, + enum fw_opt opt_flags) { struct firmware *firmware; struct fw_priv *fw_priv; @@ -518,7 +522,8 @@ int assign_fw(struct firmware *fw, struct device *device, return 0; /* assigned */ } - ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size); + ret = alloc_lookup_fw_priv(name, _cache, _priv, dbuf, size, + opt_flags); /* * bind with 'priv' now to avoid warning in failure path @@ -578,7 +583,8 @@ static void fw_abort_batch_reqs(struct firmware *fw) goto out; } - ret = _request_firmware_prepare(, name, device, buf, size); + ret = _request_firmware_prepare(, name, device, buf, size, + opt_flags); if (ret <= 0) /* error or already assigned */ goto out; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] dd: Invoke one probe retry cycle after every initcall level
Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level, allowing these drivers to be probed earlier. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/dd.c | 33 +++-- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..e6a6821 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,44 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +arch_initcall_sync(deferred_probe_initcall); +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] dd: Invoke one probe retry cycle after every initcall level
Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level, allowing these drivers to be probed earlier. Signed-off-by: Vikram Mulukutla Signed-off-by: Rishabh Bhatnagar --- drivers/base/dd.c | 33 +++-- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1435d72..e6a6821 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -224,23 +224,44 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +static void enable_trigger_defer_cycle(void) +{ + driver_deferred_probe_enable = true; + driver_deferred_probe_trigger(); + /* +* Sort as many dependencies as possible before the next initcall +* level +*/ + flush_work(_probe_work); +} + /** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. + * all the registered initcall functions at a particular level are completed. + * This function is invoked at every *_initcall_sync level. */ static int deferred_probe_initcall(void) { - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(_probe_work); + enable_trigger_defer_cycle(); + driver_deferred_probe_enable = false; + return 0; +} +arch_initcall_sync(deferred_probe_initcall); +subsys_initcall_sync(deferred_probe_initcall); +fs_initcall_sync(deferred_probe_initcall); +device_initcall_sync(deferred_probe_initcall); + +static int deferred_probe_enable_fn(void) +{ + /* Enable deferred probing for all time */ + enable_trigger_defer_cycle(); initcalls_done = true; return 0; } -late_initcall(deferred_probe_initcall); +late_initcall(deferred_probe_enable_fn); /** * device_is_bound() - Check if device is bound to a driver -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] lib: rhashtable: Correct self-assignment in rhashtable.c
In file lib/rhashtable.c line 777, skip variable is assigned to itself. The following error was observed: lib/rhashtable.c:777:41: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] error, forbidden warning: rhashtable.c:777 This error was found when compiling with Clang 6.0. Change it to iter->skip. Change-Id: I5abd1ce5ba76737a73bd6eca94b07b1bd5267523 Signed-off-by: Rishabh Bhatnagar --- lib/rhashtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 9427b57..3109b2e 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -774,7 +774,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) skip++; if (list == iter->list) { iter->p = p; - skip = skip; + iter->skip = skip; goto found; } } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH] lib: rhashtable: Correct self-assignment in rhashtable.c
In file lib/rhashtable.c line 777, skip variable is assigned to itself. The following error was observed: lib/rhashtable.c:777:41: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign] error, forbidden warning: rhashtable.c:777 This error was found when compiling with Clang 6.0. Change it to iter->skip. Change-Id: I5abd1ce5ba76737a73bd6eca94b07b1bd5267523 Signed-off-by: Rishabh Bhatnagar --- lib/rhashtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 9427b57..3109b2e 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -774,7 +774,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) skip++; if (list == iter->list) { iter->p = p; - skip = skip; + iter->skip = skip; goto found; } } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 0/2] SDM845 System Cache Driver
This series implements system cache or LLCC(Last Level Cache Controller) driver for SDM845 SOC. The purpose of the driver is to partition the system cache and program the settings such as priortiy, lines to probe while doing a look up in the system cache, low power related settings etc. The partitions are called cache slices. Each cache slice is associated with size and SCID(System Cache ID). The driver also provides API for clients to query the cache slice details,activate and deactivate them. The driver can be broadly classified into: * SOC specific driver: llcc-sdm845.c: Cache partitioning and cache slice properties for usecases on sdm845 that need to use system cache. * API : llcc-slice.c: Exports APIs to clients to query cache slice details, activate and deactivate cache slices. Changes since v7: * Change the DT node name to cache-controller. * Use the module_platform_driver_macro * Use GENMASK and SZ_* macros * Correct indentation, and remove unnecessary assignemnts. * Addresed all comments by Andy Schevchenko except the comment to ignore some lines of code going over 80 characters. Changes since v6: * Remove the max-slices property from DT. * Make client's slice_ids as macros. * Unlock mutex while returning from function in case of error. Changes since v5: * Remove client information from DT. * Make the llcc driver data as global. * Check return value of llcc_update_act_ctrl function * Change error returned from -EFAULT to -EINVAL Changes since v4: * Remove null pointer checks as per comments. * Remove extra blank lines. Changes since v3: * Use the regmap_read_poll_timeout function * Check for regmap read/write errors. * Remove memory barrier after regmap write * Derive memory bank offsets using stride macro variable * Remove debug statements from code * Remove the qcom_llcc_remove function * Use if IS_ENABLED in place of ifdef for built-in module * Change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL * Remove unnecessary free functions * Change the variable names as per review comments Changes since v2: * Corrected the Makefile to fix compilation. Changes since v1: * Added Makefile and Kconfig. Changes since v0: * Removed the syscon and simple-mfd approach * Updated the device tree nodes to mention LLCC as a single HW block * Moved llcc bank offsets from device tree and handled the offset in the driver. ckad...@codeaurora.org (2): dt-bindings: Documentation for qcom, llcc drivers: soc: Add LLCC driver .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 94 ++ drivers/soc/qcom/llcc-slice.c | 335 + include/linux/soc/qcom/llcc-qcom.h | 180 +++ 6 files changed, 654 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 0/2] SDM845 System Cache Driver
This series implements system cache or LLCC(Last Level Cache Controller) driver for SDM845 SOC. The purpose of the driver is to partition the system cache and program the settings such as priortiy, lines to probe while doing a look up in the system cache, low power related settings etc. The partitions are called cache slices. Each cache slice is associated with size and SCID(System Cache ID). The driver also provides API for clients to query the cache slice details,activate and deactivate them. The driver can be broadly classified into: * SOC specific driver: llcc-sdm845.c: Cache partitioning and cache slice properties for usecases on sdm845 that need to use system cache. * API : llcc-slice.c: Exports APIs to clients to query cache slice details, activate and deactivate cache slices. Changes since v7: * Change the DT node name to cache-controller. * Use the module_platform_driver_macro * Use GENMASK and SZ_* macros * Correct indentation, and remove unnecessary assignemnts. * Addresed all comments by Andy Schevchenko except the comment to ignore some lines of code going over 80 characters. Changes since v6: * Remove the max-slices property from DT. * Make client's slice_ids as macros. * Unlock mutex while returning from function in case of error. Changes since v5: * Remove client information from DT. * Make the llcc driver data as global. * Check return value of llcc_update_act_ctrl function * Change error returned from -EFAULT to -EINVAL Changes since v4: * Remove null pointer checks as per comments. * Remove extra blank lines. Changes since v3: * Use the regmap_read_poll_timeout function * Check for regmap read/write errors. * Remove memory barrier after regmap write * Derive memory bank offsets using stride macro variable * Remove debug statements from code * Remove the qcom_llcc_remove function * Use if IS_ENABLED in place of ifdef for built-in module * Change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL * Remove unnecessary free functions * Change the variable names as per review comments Changes since v2: * Corrected the Makefile to fix compilation. Changes since v1: * Added Makefile and Kconfig. Changes since v0: * Removed the syscon and simple-mfd approach * Updated the device tree nodes to mention LLCC as a single HW block * Moved llcc bank offsets from device tree and handled the offset in the driver. ckad...@codeaurora.org (2): dt-bindings: Documentation for qcom, llcc drivers: soc: Add LLCC driver .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 94 ++ drivers/soc/qcom/llcc-slice.c | 335 + include/linux/soc/qcom/llcc-qcom.h | 180 +++ 6 files changed, 654 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 1/2] dt-bindings: Documentation for qcom, llcc
Documentation for last level cache controller device tree bindings, client bindings usage examples. Signed-off-by: Channagoud Kadabi <ckad...@codeaurora.org> Signed-off-by: Rishabh Bhatnagar <risha...@codeaurora.org> Reviewed-by: Evan Green <evgr...@chromium.org> Reviewed-by: Rob Herring <r...@kernel.org> --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 000..5e85749 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,26 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-llcc" + +- reg: + Usage: required + Value Type: + Definition: Start address and the the size of the register region. + +Example: + + cache-controller@110 { + compatible = "qcom,sdm845-llcc"; + reg = <0x110 0x25>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 1/2] dt-bindings: Documentation for qcom, llcc
Documentation for last level cache controller device tree bindings, client bindings usage examples. Signed-off-by: Channagoud Kadabi Signed-off-by: Rishabh Bhatnagar Reviewed-by: Evan Green Reviewed-by: Rob Herring --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 000..5e85749 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,26 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-llcc" + +- reg: + Usage: required + Value Type: + Definition: Start address and the the size of the register region. + +Example: + + cache-controller@110 { + compatible = "qcom,sdm845-llcc"; + reg = <0x110 0x25>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v8 2/2] drivers: soc: Add LLCC driver
LLCC (Last Level Cache Controller) provides additional cache memory in the system. LLCC is partitioned into multiple slices and each slice gets its own priority, size, ID and other config parameters. LLCC driver programs these parameters for each slice. Clients that are assigned to use LLCC need to get information such size & ID of the slice they get and activate or deactivate the slice as needed. LLCC driver provides API for the clients to perform these operations. Signed-off-by: Channagoud Kadabi <ckad...@codeaurora.org> Signed-off-by: Rishabh Bhatnagar <risha...@codeaurora.org> Reviewed-by: Evan Green <evgr...@chromium.org> Reviewed-by: Rob Herring <r...@kernel.org> --- drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 94 +++ drivers/soc/qcom/llcc-slice.c | 335 + include/linux/soc/qcom/llcc-qcom.h | 180 5 files changed, 628 insertions(+) create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e050eb8..0b550f9 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -21,6 +21,23 @@ config QCOM_GSBI functions for connecting the underlying serial UART, SPI, and I2C devices to the output pins. +config QCOM_LLCC + tristate "Qualcomm Technologies, Inc. LLCC driver" + depends on ARCH_QCOM + help + Qualcomm Technologies, Inc. platform specific + Last Level Cache Controller(LLCC) driver. This provides interfaces + to clients that use the LLCC. Say yes here to enable LLCC slice + driver. + +config QCOM_SDM845_LLCC + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" + depends on QCOM_LLCC + help + Say yes here to enable the LLCC driver for SDM845. This provides + data required to configure LLCC so that clients can start using the + LLCC slices. + config QCOM_MDT_LOADER tristate select QCOM_SCM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dcebf28..e16d6a2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM)+= smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o +obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c new file mode 100644 index 000..2e1e4f0 --- /dev/null +++ b/drivers/soc/qcom/llcc-sdm845.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +/* + * SCT(System Cache Table) entry contains of the following members: + * usecase_id: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Boolean indicating if the slice has a fixed capacity + * bonus_ways: Bonus ways are additional ways to be used for any slice, + * if client ends up using more than reserved cache ways. Bonus + * ways are allocated only if they are not reserved for some + * other client. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot + * be used by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice: normal or TCM(Tightly Coupled Memory) + * probe_target_ways: Determines what ways to probe for access hit. When + *configured to 1 only bonus and reserved ways are probed. + *When configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maintained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immediately after the SCT is programmed + */ +#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .usecase_id = uid, \ + .slice_id = sid,\ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway
[PATCH v8 2/2] drivers: soc: Add LLCC driver
LLCC (Last Level Cache Controller) provides additional cache memory in the system. LLCC is partitioned into multiple slices and each slice gets its own priority, size, ID and other config parameters. LLCC driver programs these parameters for each slice. Clients that are assigned to use LLCC need to get information such size & ID of the slice they get and activate or deactivate the slice as needed. LLCC driver provides API for the clients to perform these operations. Signed-off-by: Channagoud Kadabi Signed-off-by: Rishabh Bhatnagar Reviewed-by: Evan Green Reviewed-by: Rob Herring --- drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 94 +++ drivers/soc/qcom/llcc-slice.c | 335 + include/linux/soc/qcom/llcc-qcom.h | 180 5 files changed, 628 insertions(+) create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e050eb8..0b550f9 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -21,6 +21,23 @@ config QCOM_GSBI functions for connecting the underlying serial UART, SPI, and I2C devices to the output pins. +config QCOM_LLCC + tristate "Qualcomm Technologies, Inc. LLCC driver" + depends on ARCH_QCOM + help + Qualcomm Technologies, Inc. platform specific + Last Level Cache Controller(LLCC) driver. This provides interfaces + to clients that use the LLCC. Say yes here to enable LLCC slice + driver. + +config QCOM_SDM845_LLCC + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" + depends on QCOM_LLCC + help + Say yes here to enable the LLCC driver for SDM845. This provides + data required to configure LLCC so that clients can start using the + LLCC slices. + config QCOM_MDT_LOADER tristate select QCOM_SCM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dcebf28..e16d6a2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM)+= smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o +obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c new file mode 100644 index 000..2e1e4f0 --- /dev/null +++ b/drivers/soc/qcom/llcc-sdm845.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +/* + * SCT(System Cache Table) entry contains of the following members: + * usecase_id: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Boolean indicating if the slice has a fixed capacity + * bonus_ways: Bonus ways are additional ways to be used for any slice, + * if client ends up using more than reserved cache ways. Bonus + * ways are allocated only if they are not reserved for some + * other client. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot + * be used by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice: normal or TCM(Tightly Coupled Memory) + * probe_target_ways: Determines what ways to probe for access hit. When + *configured to 1 only bonus and reserved ways are probed. + *When configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maintained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immediately after the SCT is programmed + */ +#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .usecase_id = uid, \ + .slice_id = sid,\ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ +
[PATCH v7 0/2] SDM845 System Cache Driver
This series implements system cache or LLCC(Last Level Cache Controller) driver for SDM845 SOC. The purpose of the driver is to partition the system cache and program the settings such as priortiy, lines to probe while doing a look up in the system cache, low power related settings etc. The partitions are called cache slices. Each cache slice is associated with size and SCID(System Cache ID). The driver also provides API for clients to query the cache slice details,activate and deactivate them. The driver can be broadly classified into: * SOC specific driver: llcc-sdm845.c: Cache partitioning and cache slice properties for usecases on sdm845 that need to use system cache. * API : llcc-slice.c: Exports APIs to clients to query cache slice details, activate and deactivate cache slices. Changes since v6: * Remove the max-slices property from DT. * Make client's slice_ids as macros. * Unlock mutex while returning from function in case of error. Changes since v5: * Remove client information from DT. * Make the llcc driver data as global. * Check return value of llcc_update_act_ctrl function * Change error returned from -EFAULT to -EINVAL Changes since v4: * Remove null pointer checks as per comments. * Remove extra blank lines. Changes since v3: * Use the regmap_read_poll_timeout function * Check for regmap read/write errors. * Remove memory barrier after regmap write * Derive memory bank offsets using stride macro variable * Remove debug statements from code * Remove the qcom_llcc_remove function * Use if IS_ENABLED in place of ifdef for built-in module * Change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL * Remove unnecessary free functions * Change the variable names as per review comments Changes since v2: * Corrected the Makefile to fix compilation. Changes since v1: * Added Makefile and Kconfig. Changes since v0: * Removed the syscon and simple-mfd approach * Updated the device tree nodes to mention LLCC as a single HW block * Moved llcc bank offsets from device tree and handled the offset in the driver. ckad...@codeaurora.org (2): dt-bindings: Documentation for qcom, llcc drivers: soc: Add LLCC driver .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 106 +++ drivers/soc/qcom/llcc-slice.c | 337 + include/linux/soc/qcom/llcc-qcom.h | 180 +++ 6 files changed, 668 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v7 0/2] SDM845 System Cache Driver
This series implements system cache or LLCC(Last Level Cache Controller) driver for SDM845 SOC. The purpose of the driver is to partition the system cache and program the settings such as priortiy, lines to probe while doing a look up in the system cache, low power related settings etc. The partitions are called cache slices. Each cache slice is associated with size and SCID(System Cache ID). The driver also provides API for clients to query the cache slice details,activate and deactivate them. The driver can be broadly classified into: * SOC specific driver: llcc-sdm845.c: Cache partitioning and cache slice properties for usecases on sdm845 that need to use system cache. * API : llcc-slice.c: Exports APIs to clients to query cache slice details, activate and deactivate cache slices. Changes since v6: * Remove the max-slices property from DT. * Make client's slice_ids as macros. * Unlock mutex while returning from function in case of error. Changes since v5: * Remove client information from DT. * Make the llcc driver data as global. * Check return value of llcc_update_act_ctrl function * Change error returned from -EFAULT to -EINVAL Changes since v4: * Remove null pointer checks as per comments. * Remove extra blank lines. Changes since v3: * Use the regmap_read_poll_timeout function * Check for regmap read/write errors. * Remove memory barrier after regmap write * Derive memory bank offsets using stride macro variable * Remove debug statements from code * Remove the qcom_llcc_remove function * Use if IS_ENABLED in place of ifdef for built-in module * Change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL * Remove unnecessary free functions * Change the variable names as per review comments Changes since v2: * Corrected the Makefile to fix compilation. Changes since v1: * Added Makefile and Kconfig. Changes since v0: * Removed the syscon and simple-mfd approach * Updated the device tree nodes to mention LLCC as a single HW block * Moved llcc bank offsets from device tree and handled the offset in the driver. ckad...@codeaurora.org (2): dt-bindings: Documentation for qcom, llcc drivers: soc: Add LLCC driver .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 106 +++ drivers/soc/qcom/llcc-slice.c | 337 + include/linux/soc/qcom/llcc-qcom.h | 180 +++ 6 files changed, 668 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v7 2/2] drivers: soc: Add LLCC driver
LLCC (Last Level Cache Controller) provides additional cache memory in the system. LLCC is partitioned into multiple slices and each slice gets its own priority, size, ID and other config parameters. LLCC driver programs these parameters for each slice. Clients that are assigned to use LLCC need to get information such size & ID of the slice they get and activate or deactivate the slice as needed. LLCC driver provides API for the clients to perform these operations. Signed-off-by: Channagoud Kadabi <ckad...@codeaurora.org> Signed-off-by: Rishabh Bhatnagar <risha...@codeaurora.org> --- drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 106 drivers/soc/qcom/llcc-slice.c | 337 + include/linux/soc/qcom/llcc-qcom.h | 180 5 files changed, 642 insertions(+) create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e050eb8..0b550f9 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -21,6 +21,23 @@ config QCOM_GSBI functions for connecting the underlying serial UART, SPI, and I2C devices to the output pins. +config QCOM_LLCC + tristate "Qualcomm Technologies, Inc. LLCC driver" + depends on ARCH_QCOM + help + Qualcomm Technologies, Inc. platform specific + Last Level Cache Controller(LLCC) driver. This provides interfaces + to clients that use the LLCC. Say yes here to enable LLCC slice + driver. + +config QCOM_SDM845_LLCC + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" + depends on QCOM_LLCC + help + Say yes here to enable the LLCC driver for SDM845. This provides + data required to configure LLCC so that clients can start using the + LLCC slices. + config QCOM_MDT_LOADER tristate select QCOM_SCM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dcebf28..e16d6a2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM)+= smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o +obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c new file mode 100644 index 000..bda2234 --- /dev/null +++ b/drivers/soc/qcom/llcc-sdm845.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +/* + * SCT(System Cache Table) entry contains of the following members: + * usecase_id: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Boolean indicating if the slice has a fixed capacity + * bonus_ways: Bonus ways are additional ways to be used for any slice, + * if client ends up using more than reserved cache ways. Bonus + * ways are allocated only if they are not reserved for some + * other client. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot + * be used by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice: normal or TCM(Tightly Coupled Memory) + * probe_target_ways: Determines what ways to probe for access hit. When + *configured to 1 only bonus and reserved ways are probed. + *When configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maintained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immediately after the SCT is programmed + */ +#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .usecase_id = uid, \ + .slice_id = sid,\ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ +
[PATCH v7 2/2] drivers: soc: Add LLCC driver
LLCC (Last Level Cache Controller) provides additional cache memory in the system. LLCC is partitioned into multiple slices and each slice gets its own priority, size, ID and other config parameters. LLCC driver programs these parameters for each slice. Clients that are assigned to use LLCC need to get information such size & ID of the slice they get and activate or deactivate the slice as needed. LLCC driver provides API for the clients to perform these operations. Signed-off-by: Channagoud Kadabi Signed-off-by: Rishabh Bhatnagar --- drivers/soc/qcom/Kconfig | 17 ++ drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/llcc-sdm845.c | 106 drivers/soc/qcom/llcc-slice.c | 337 + include/linux/soc/qcom/llcc-qcom.h | 180 5 files changed, 642 insertions(+) create mode 100644 drivers/soc/qcom/llcc-sdm845.c create mode 100644 drivers/soc/qcom/llcc-slice.c create mode 100644 include/linux/soc/qcom/llcc-qcom.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e050eb8..0b550f9 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -21,6 +21,23 @@ config QCOM_GSBI functions for connecting the underlying serial UART, SPI, and I2C devices to the output pins. +config QCOM_LLCC + tristate "Qualcomm Technologies, Inc. LLCC driver" + depends on ARCH_QCOM + help + Qualcomm Technologies, Inc. platform specific + Last Level Cache Controller(LLCC) driver. This provides interfaces + to clients that use the LLCC. Say yes here to enable LLCC slice + driver. + +config QCOM_SDM845_LLCC + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" + depends on QCOM_LLCC + help + Say yes here to enable the LLCC driver for SDM845. This provides + data required to configure LLCC so that clients can start using the + LLCC slices. + config QCOM_MDT_LOADER tristate select QCOM_SCM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dcebf28..e16d6a2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM)+= smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o +obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c new file mode 100644 index 000..bda2234 --- /dev/null +++ b/drivers/soc/qcom/llcc-sdm845.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +/* + * SCT(System Cache Table) entry contains of the following members: + * usecase_id: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Boolean indicating if the slice has a fixed capacity + * bonus_ways: Bonus ways are additional ways to be used for any slice, + * if client ends up using more than reserved cache ways. Bonus + * ways are allocated only if they are not reserved for some + * other client. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot + * be used by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice: normal or TCM(Tightly Coupled Memory) + * probe_target_ways: Determines what ways to probe for access hit. When + *configured to 1 only bonus and reserved ways are probed. + *When configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maintained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immediately after the SCT is programmed + */ +#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .usecase_id = uid, \ + .slice_id = sid,\ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ + .probe_target_ways = ptw, \ +
[PATCH v7 1/2] dt-bindings: Documentation for qcom, llcc
Documentation for last level cache controller device tree bindings, client bindings usage examples. Signed-off-by: Channagoud Kadabi <ckad...@codeaurora.org> Signed-off-by: Rishabh Bhatnagar <risha...@codeaurora.org> --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 000..0ebbf0a --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,26 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-llcc" + +- reg: + Usage: required + Value Type: + Definition: Start address and the the size of the register region. + +Example: + + qcom,llcc@110 { + compatible = "qcom,sdm845-llcc"; + reg = <0x110 0x25>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v7 1/2] dt-bindings: Documentation for qcom, llcc
Documentation for last level cache controller device tree bindings, client bindings usage examples. Signed-off-by: Channagoud Kadabi Signed-off-by: Rishabh Bhatnagar --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 26 ++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 000..0ebbf0a --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,26 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-llcc" + +- reg: + Usage: required + Value Type: + Definition: Start address and the the size of the register region. + +Example: + + qcom,llcc@110 { + compatible = "qcom,sdm845-llcc"; + reg = <0x110 0x25>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
[PATCH v6 1/2] dt-bindings: Documentation for qcom, llcc
Documentation for last level cache controller device tree bindings, client bindings usage examples. Signed-off-by: Channagoud Kadabi <ckad...@codeaurora.org> Signed-off-by: Rishabh Bhatnagar <risha...@codeaurora.org> --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 32 ++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 000..a586a17 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,32 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-llcc" + +- reg: + Usage: required + Value Type: + Definition: Start address and the range of the LLCC registers. + +- max-slices: + usage: required + Value Type: + Definition: Number of cache slices supported by hardware + +Example: + + llcc: qcom,llcc@110 { + compatible = "qcom,sdm845-llcc"; + reg = <0x110 0x25>; + max-slices = <32>; + }; -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project