Commit 2f194646 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rproc-v5.1' of git://github.com/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson:
 "This contains the last patches in Loic's remoteproc resource table
  handling changes, a number of updates to documentation, support for
  invoking the crash handler (for testing purposes), a fix for the
  handling of virtio devices during recovery, performance state votes in
  Qualcomm modem driver, support for specifying board specific firmware
  path for Qualcomm modem driver and improved support for graceful
  shutdown of Qualcomm remoteprocs"

* tag 'rproc-v5.1' of git://github.com/andersson/remoteproc: (33 commits)
  remoteproc: fix for "dma-mapping: remove the DMA_MEMORY_EXCLUSIVE flag"
  remoteproc: fix rproc_check_carveout_da() returned error and comments
  remoteproc: fix trace buffer va initialization
  remoteproc: fix rproc_alloc_carveout() for rproc with iommu domain
  remoteproc: add warning on resource table cast
  remoteproc: fix rproc_alloc_carveout() bad variable cast
  remoteproc: fix rproc_da_to_va in case of unallocated carveout
  remoteproc: correct rproc_mem_entry_init() comments
  remoteproc: fix recovery procedure
  rpmsg: virtio: change header file sort style
  rpmsg: virtio: allocate buffer from parent
  remoteproc: st: add reserved memory support
  remoteproc: create vdev subdevice with specific dma memory pool
  remoteproc: q6v5_adsp: Remove voting for lpass_aon clock
  dt-binding: remoteproc: Remove lpass_aon clock from adsp pil clock list
  remoteproc: q6v5-mss: Active powerdomain for SDM845
  remoteproc: q6v5-mss: Vote for rpmh power domains
  remoteproc: qcom: Add support for parsing fw dt bindings
  remoteproc: qcom_q6v5: don't auto boot remote processor
  remoteproc: qcom: Wait for shutdown-ack/ind on sysmon shutdown
  ...
parents dc2535be d664ce75
...@@ -35,7 +35,7 @@ on the Qualcomm Technology Inc. ADSP Hexagon core. ...@@ -35,7 +35,7 @@ on the Qualcomm Technology Inc. ADSP Hexagon core.
Value type: <stringlist> Value type: <stringlist>
Definition: List of clock input name strings sorted in the same Definition: List of clock input name strings sorted in the same
order as the clocks property. Definition must have order as the clocks property. Definition must have
"xo", "sway_cbcr", "lpass_aon", "lpass_ahbs_aon_cbcr", "xo", "sway_cbcr", "lpass_ahbs_aon_cbcr",
"lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep" "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep"
and "qdsp6ss_core". and "qdsp6ss_core".
...@@ -100,13 +100,12 @@ ADSP, as it is found on SDM845 boards. ...@@ -100,13 +100,12 @@ ADSP, as it is found on SDM845 boards.
clocks = <&rpmhcc RPMH_CXO_CLK>, clocks = <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_LPASS_SWAY_CLK>, <&gcc GCC_LPASS_SWAY_CLK>,
<&lpasscc LPASS_AUDIO_WRAPPER_AON_CLK>,
<&lpasscc LPASS_Q6SS_AHBS_AON_CLK>, <&lpasscc LPASS_Q6SS_AHBS_AON_CLK>,
<&lpasscc LPASS_Q6SS_AHBM_AON_CLK>, <&lpasscc LPASS_Q6SS_AHBM_AON_CLK>,
<&lpasscc LPASS_QDSP6SS_XO_CLK>, <&lpasscc LPASS_QDSP6SS_XO_CLK>,
<&lpasscc LPASS_QDSP6SS_SLEEP_CLK>, <&lpasscc LPASS_QDSP6SS_SLEEP_CLK>,
<&lpasscc LPASS_QDSP6SS_CORE_CLK>; <&lpasscc LPASS_QDSP6SS_CORE_CLK>;
clock-names = "xo", "sway_cbcr", "lpass_aon", clock-names = "xo", "sway_cbcr",
"lpass_ahbs_aon_cbcr", "lpass_ahbs_aon_cbcr",
"lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "lpass_ahbm_aon_cbcr", "qdsp6ss_xo",
"qdsp6ss_sleep", "qdsp6ss_core"; "qdsp6ss_sleep", "qdsp6ss_core";
......
...@@ -19,13 +19,30 @@ on the Qualcomm ADSP Hexagon core. ...@@ -19,13 +19,30 @@ on the Qualcomm ADSP Hexagon core.
- interrupts-extended: - interrupts-extended:
Usage: required Usage: required
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: must list the watchdog, fatal IRQs ready, handover and Definition: reference to the interrupts that match interrupt-names
stop-ack IRQs
- interrupt-names: - interrupt-names:
Usage: required Usage: required
Value type: <stringlist> Value type: <stringlist>
Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack" Definition: The interrupts needed depends on the compatible
string:
qcom,msm8974-adsp-pil:
qcom,msm8996-adsp-pil:
qcom,msm8996-slpi-pil:
qcom,qcs404-adsp-pas:
qcom,qcs404-cdsp-pas:
qcom,sdm845-adsp-pas:
qcom,sdm845-cdsp-pas:
must be "wdog", "fatal", "ready", "handover", "stop-ack"
qcom,qcs404-wcss-pas:
must be "wdog", "fatal", "ready", "handover", "stop-ack",
"shutdown-ack"
- firmware-name:
Usage: optional
Value type: <string>
Definition: must list the relative firmware image path for the
Hexagon Core.
- clocks: - clocks:
Usage: required Usage: required
......
...@@ -28,24 +28,51 @@ on the Qualcomm Hexagon core. ...@@ -28,24 +28,51 @@ on the Qualcomm Hexagon core.
- interrupts-extended: - interrupts-extended:
Usage: required Usage: required
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: must list the watchdog, fatal IRQs ready, handover and Definition: reference to the interrupts that match interrupt-names
stop-ack IRQs
- interrupt-names: - interrupt-names:
Usage: required Usage: required
Value type: <stringlist> Value type: <stringlist>
Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack" Definition: The interrupts needed depends on the the compatible
string:
qcom,q6v5-pil:
qcom,ipq8074-wcss-pil:
qcom,msm8916-mss-pil:
qcom,msm8974-mss-pil:
must be "wdog", "fatal", "ready", "handover", "stop-ack"
qcom,msm8996-mss-pil:
qcom,sdm845-mss-pil:
must be "wdog", "fatal", "ready", "handover", "stop-ack",
"shutdown-ack"
- firmware-name:
Usage: optional
Value type: <stringlist>
Definition: must list the relative firmware image paths for mba and
modem. They are used for booting and authenticating the
Hexagon core.
- clocks: - clocks:
Usage: required Usage: required
Value type: <phandle> Value type: <phandle>
Definition: reference to the iface, bus and mem clocks to be held on Definition: reference to the clocks that match clock-names
behalf of the booting of the Hexagon core
- clock-names: - clock-names:
Usage: required Usage: required
Value type: <stringlist> Value type: <stringlist>
Definition: must be "iface", "bus", "mem" Definition: The clocks needed depend on the compatible string:
qcom,ipq8074-wcss-pil:
no clock names required
qcom,q6v5-pil:
qcom,msm8916-mss-pil:
qcom,msm8974-mss-pil:
must be "iface", "bus", "mem", "xo"
qcom,msm8996-mss-pil:
must be "iface", "bus", "mem", "xo", "gpll0_mss",
"snoc_axi", "mnoc_axi", "pnoc", "qdss"
qcom,sdm845-mss-pil:
must be "iface", "bus", "mem", "xo", "gpll0_mss",
"snoc_axi", "mnoc_axi", "prng"
- resets: - resets:
Usage: required Usage: required
...@@ -65,6 +92,19 @@ on the Qualcomm Hexagon core. ...@@ -65,6 +92,19 @@ on the Qualcomm Hexagon core.
must be "mss_restart", "pdc_reset" for the modem must be "mss_restart", "pdc_reset" for the modem
sub-system on SDM845 SoCs sub-system on SDM845 SoCs
For the compatible strings below the following supplies are required:
"qcom,q6v5-pil"
"qcom,msm8916-mss-pil",
- cx-supply:
- mx-supply:
- pll-supply:
Usage: required
Value type: <phandle>
Definition: reference to the regulators to be held on behalf of the
booting of the Hexagon core
For the compatible string below the following supplies are required:
"qcom,msm8974-mss-pil"
- cx-supply: - cx-supply:
- mss-supply: - mss-supply:
- mx-supply: - mx-supply:
...@@ -74,6 +114,33 @@ on the Qualcomm Hexagon core. ...@@ -74,6 +114,33 @@ on the Qualcomm Hexagon core.
Definition: reference to the regulators to be held on behalf of the Definition: reference to the regulators to be held on behalf of the
booting of the Hexagon core booting of the Hexagon core
For the compatible string below the following supplies are required:
"qcom,msm8996-mss-pil"
- pll-supply:
Usage: required
Value type: <phandle>
Definition: reference to the regulators to be held on behalf of the
booting of the Hexagon core
- power-domains:
Usage: required
Value type: <phandle>
Definition: reference to power-domains that match power-domain-names
- power-domain-names:
Usage: required
Value type: <stringlist>
Definition: The power-domains needed depend on the compatible string:
qcom,q6v5-pil:
qcom,ipq8074-wcss-pil:
qcom,msm8916-mss-pil:
qcom,msm8974-mss-pil:
no power-domain names required
qcom,msm8996-mss-pil:
must be "cx", "mx"
qcom,sdm845-mss-pil:
must be "cx", "mx", "mss", "load_state"
- qcom,smem-states: - qcom,smem-states:
Usage: required Usage: required
Value type: <phandle> Value type: <phandle>
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
/* list of clocks required by ADSP PIL */ /* list of clocks required by ADSP PIL */
static const char * const adsp_clk_id[] = { static const char * const adsp_clk_id[] = {
"sway_cbcr", "lpass_aon", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr", "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core",
}; };
...@@ -439,6 +439,10 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -439,6 +439,10 @@ static int adsp_probe(struct platform_device *pdev)
adsp->sysmon = qcom_add_sysmon_subdev(rproc, adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name, desc->sysmon_name,
desc->ssctl_id); desc->ssctl_id);
if (IS_ERR(adsp->sysmon)) {
ret = PTR_ERR(adsp->sysmon);
goto disable_pm;
}
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
......
This diff is collapsed.
...@@ -258,6 +258,7 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -258,6 +258,7 @@ static int adsp_probe(struct platform_device *pdev)
const struct adsp_data *desc; const struct adsp_data *desc;
struct qcom_adsp *adsp; struct qcom_adsp *adsp;
struct rproc *rproc; struct rproc *rproc;
const char *fw_name;
int ret; int ret;
desc = of_device_get_match_data(&pdev->dev); desc = of_device_get_match_data(&pdev->dev);
...@@ -267,8 +268,14 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -267,8 +268,14 @@ static int adsp_probe(struct platform_device *pdev)
if (!qcom_scm_is_available()) if (!qcom_scm_is_available())
return -EPROBE_DEFER; return -EPROBE_DEFER;
fw_name = desc->firmware_name;
ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
&fw_name);
if (ret < 0 && ret != -EINVAL)
return ret;
rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops, rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
desc->firmware_name, sizeof(*adsp)); fw_name, sizeof(*adsp));
if (!rproc) { if (!rproc) {
dev_err(&pdev->dev, "unable to allocate remoteproc\n"); dev_err(&pdev->dev, "unable to allocate remoteproc\n");
return -ENOMEM; return -ENOMEM;
...@@ -304,6 +311,10 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -304,6 +311,10 @@ static int adsp_probe(struct platform_device *pdev)
adsp->sysmon = qcom_add_sysmon_subdev(rproc, adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name, desc->sysmon_name,
desc->ssctl_id); desc->ssctl_id);
if (IS_ERR(adsp->sysmon)) {
ret = PTR_ERR(adsp->sysmon);
goto free_rproc;
}
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
......
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/notifier.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/remoteproc/qcom_rproc.h> #include <linux/remoteproc/qcom_rproc.h>
...@@ -25,6 +26,7 @@ struct qcom_sysmon { ...@@ -25,6 +26,7 @@ struct qcom_sysmon {
const char *name; const char *name;
int shutdown_irq;
int ssctl_version; int ssctl_version;
int ssctl_instance; int ssctl_instance;
...@@ -34,6 +36,8 @@ struct qcom_sysmon { ...@@ -34,6 +36,8 @@ struct qcom_sysmon {
struct rpmsg_endpoint *ept; struct rpmsg_endpoint *ept;
struct completion comp; struct completion comp;
struct completion ind_comp;
struct completion shutdown_comp;
struct mutex lock; struct mutex lock;
bool ssr_ack; bool ssr_ack;
...@@ -137,6 +141,7 @@ static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count, ...@@ -137,6 +141,7 @@ static int sysmon_callback(struct rpmsg_device *rpdev, void *data, int count,
} }
#define SSCTL_SHUTDOWN_REQ 0x21 #define SSCTL_SHUTDOWN_REQ 0x21
#define SSCTL_SHUTDOWN_READY_IND 0x21
#define SSCTL_SUBSYS_EVENT_REQ 0x23 #define SSCTL_SUBSYS_EVENT_REQ 0x23
#define SSCTL_MAX_MSG_LEN 7 #define SSCTL_MAX_MSG_LEN 7
...@@ -252,6 +257,29 @@ static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = { ...@@ -252,6 +257,29 @@ static struct qmi_elem_info ssctl_subsys_event_resp_ei[] = {
{} {}
}; };
static struct qmi_elem_info ssctl_shutdown_ind_ei[] = {
{}
};
static void sysmon_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
struct qmi_txn *txn, const void *data)
{
struct qcom_sysmon *sysmon = container_of(qmi, struct qcom_sysmon, qmi);
complete(&sysmon->ind_comp);
}
static struct qmi_msg_handler qmi_indication_handler[] = {
{
.type = QMI_INDICATION,
.msg_id = SSCTL_SHUTDOWN_READY_IND,
.ei = ssctl_shutdown_ind_ei,
.decoded_size = 0,
.fn = sysmon_ind_cb
},
{}
};
/** /**
* ssctl_request_shutdown() - request shutdown via SSCTL QMI service * ssctl_request_shutdown() - request shutdown via SSCTL QMI service
* @sysmon: sysmon context * @sysmon: sysmon context
...@@ -262,6 +290,8 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon) ...@@ -262,6 +290,8 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
struct qmi_txn txn; struct qmi_txn txn;
int ret; int ret;
reinit_completion(&sysmon->ind_comp);
reinit_completion(&sysmon->shutdown_comp);
ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp); ret = qmi_txn_init(&sysmon->qmi, &txn, ssctl_shutdown_resp_ei, &resp);
if (ret < 0) { if (ret < 0) {
dev_err(sysmon->dev, "failed to allocate QMI txn\n"); dev_err(sysmon->dev, "failed to allocate QMI txn\n");
...@@ -283,6 +313,17 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon) ...@@ -283,6 +313,17 @@ static void ssctl_request_shutdown(struct qcom_sysmon *sysmon)
dev_err(sysmon->dev, "shutdown request failed\n"); dev_err(sysmon->dev, "shutdown request failed\n");
else else
dev_dbg(sysmon->dev, "shutdown request completed\n"); dev_dbg(sysmon->dev, "shutdown request completed\n");
if (sysmon->shutdown_irq > 0) {
ret = wait_for_completion_timeout(&sysmon->shutdown_comp,
10 * HZ);
if (!ret) {
ret = try_wait_for_completion(&sysmon->ind_comp);
if (!ret)
dev_err(sysmon->dev,
"timeout waiting for shutdown ack\n");
}
}
} }
/** /**
...@@ -432,6 +473,15 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event, ...@@ -432,6 +473,15 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static irqreturn_t sysmon_shutdown_interrupt(int irq, void *data)
{
struct qcom_sysmon *sysmon = data;
complete(&sysmon->shutdown_comp);
return IRQ_HANDLED;
}
/** /**
* qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc * qcom_add_sysmon_subdev() - create a sysmon subdev for the given remoteproc
* @rproc: rproc context to associate the subdev with * @rproc: rproc context to associate the subdev with
...@@ -449,7 +499,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, ...@@ -449,7 +499,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL); sysmon = kzalloc(sizeof(*sysmon), GFP_KERNEL);
if (!sysmon) if (!sysmon)
return NULL; return ERR_PTR(-ENOMEM);
sysmon->dev = rproc->dev.parent; sysmon->dev = rproc->dev.parent;
sysmon->rproc = rproc; sysmon->rproc = rproc;
...@@ -458,13 +508,37 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, ...@@ -458,13 +508,37 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
sysmon->ssctl_instance = ssctl_instance; sysmon->ssctl_instance = ssctl_instance;
init_completion(&sysmon->comp); init_completion(&sysmon->comp);
init_completion(&sysmon->ind_comp);
init_completion(&sysmon->shutdown_comp);
mutex_init(&sysmon->lock); mutex_init(&sysmon->lock);
ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops, NULL); sysmon->shutdown_irq = of_irq_get_byname(sysmon->dev->of_node,
"shutdown-ack");
if (sysmon->shutdown_irq < 0) {
if (sysmon->shutdown_irq != -ENODATA) {
dev_err(sysmon->dev,
"failed to retrieve shutdown-ack IRQ\n");
return ERR_PTR(sysmon->shutdown_irq);
}
} else {
ret = devm_request_threaded_irq(sysmon->dev,
sysmon->shutdown_irq,
NULL, sysmon_shutdown_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 shutdown-ack", sysmon);
if (ret) {
dev_err(sysmon->dev,
"failed to acquire shutdown-ack IRQ\n");
return ERR_PTR(ret);
}
}
ret = qmi_handle_init(&sysmon->qmi, SSCTL_MAX_MSG_LEN, &ssctl_ops,
qmi_indication_handler);
if (ret < 0) { if (ret < 0) {
dev_err(sysmon->dev, "failed to initialize qmi handle\n"); dev_err(sysmon->dev, "failed to initialize qmi handle\n");
kfree(sysmon); kfree(sysmon);
return NULL; return ERR_PTR(ret);
} }
qmi_add_lookup(&sysmon->qmi, 43, 0, 0); qmi_add_lookup(&sysmon->qmi, 43, 0, 0);
......
...@@ -553,6 +553,10 @@ static int wcnss_probe(struct platform_device *pdev) ...@@ -553,6 +553,10 @@ static int wcnss_probe(struct platform_device *pdev)
qcom_add_smd_subdev(rproc, &wcnss->smd_subdev); qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);
wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID); wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);
if (IS_ERR(wcnss->sysmon)) {
ret = PTR_ERR(wcnss->sysmon);
goto free_rproc;
}
ret = rproc_add(rproc); ret = rproc_add(rproc);
if (ret) if (ret)
...@@ -622,5 +626,5 @@ static void __exit wcnss_exit(void) ...@@ -622,5 +626,5 @@ static void __exit wcnss_exit(void)
} }
module_exit(wcnss_exit); module_exit(wcnss_exit);
MODULE_DESCRIPTION("Qualcomm Peripherial Image Loader for Wireless Subsystem"); MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Wireless Subsystem");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
This diff is collapsed.
...@@ -47,10 +47,23 @@ static struct dentry *rproc_dbg; ...@@ -47,10 +47,23 @@ static struct dentry *rproc_dbg;
static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct rproc_mem_entry *trace = filp->private_data; struct rproc_debug_trace *data = filp->private_data;
int len = strnlen(trace->va, trace->len); struct rproc_mem_entry *trace = &data->trace_mem;
void *va;
char buf[100];
int len;
va = rproc_da_to_va(data->rproc, trace->da, trace->len);
return simple_read_from_buffer(userbuf, count, ppos, trace->va, len); if (!va) {
len = scnprintf(buf, sizeof(buf), "Trace %s not available\n",
trace->name);
va = buf;
} else {
len = strnlen(va, trace->len);
}
return simple_read_from_buffer(userbuf, count, ppos, va, len);
} }
static const struct file_operations trace_rproc_ops = { static const struct file_operations trace_rproc_ops = {
...@@ -155,6 +168,30 @@ static const struct file_operations rproc_recovery_ops = { ...@@ -155,6 +168,30 @@ static const struct file_operations rproc_recovery_ops = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
/* expose the crash trigger via debugfs */
static ssize_t
rproc_crash_write(struct file *filp, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rproc *rproc = filp->private_data;
unsigned int type;
int ret;
ret = kstrtouint_from_user(user_buf, count, 0, &type);
if (ret < 0)
return ret;
rproc_report_crash(rproc, type);
return count;
}
static const struct file_operations rproc_crash_ops = {
.write = rproc_crash_write,
.open = simple_open,
.llseek = generic_file_llseek,
};
/* Expose resource table content via debugfs */ /* Expose resource table content via debugfs */
static int rproc_rsc_table_show(struct seq_file *seq, void *p) static int rproc_rsc_table_show(struct seq_file *seq, void *p)
{ {
...@@ -288,7 +325,7 @@ void rproc_remove_trace_file(struct dentry *tfile) ...@@ -288,7 +325,7 @@ void rproc_remove_trace_file(struct dentry *tfile)
} }
struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
struct rproc_mem_entry *trace) struct rproc_debug_trace *trace)
{ {
struct dentry *tfile; struct dentry *tfile;
...@@ -325,6 +362,8 @@ void rproc_create_debug_dir(struct rproc *rproc) ...@@ -325,6 +362,8 @@ void rproc_create_debug_dir(struct rproc *rproc)
rproc, &rproc_name_ops); rproc, &rproc_name_ops);
debugfs_create_file("recovery", 0400, rproc->dbg_dir, debugfs_create_file("recovery", 0400, rproc->dbg_dir,
rproc, &rproc_recovery_ops); rproc, &rproc_recovery_ops);
debugfs_create_file("crash", 0200, rproc->dbg_dir,
rproc, &rproc_crash_ops);
debugfs_create_file("resource_table", 0400, rproc->dbg_dir, debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
rproc, &rproc_rsc_table_ops); rproc, &rproc_rsc_table_ops);
debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
......
...@@ -25,6 +25,13 @@ ...@@ -25,6 +25,13 @@
struct rproc; struct rproc;
struct rproc_debug_trace {
struct rproc *rproc;
struct dentry *tfile;
struct list_head node;
struct rproc_mem_entry trace_mem;
};
/* from remoteproc_core.c */ /* from remoteproc_core.c */
void rproc_release(struct kref *kref); void rproc_release(struct kref *kref);
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id); irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
...@@ -32,12 +39,12 @@ void rproc_vdev_release(struct kref *ref); ...@@ -32,12 +39,12 @@ void rproc_vdev_release(struct kref *ref);
/* from remoteproc_virtio.c */ /* from remoteproc_virtio.c */
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id); int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id);
void rproc_remove_virtio_dev(struct rproc_vdev *rvdev); int rproc_remove_virtio_dev(struct device *dev, void *data);
/* from remoteproc_debugfs.c */ /* from remoteproc_debugfs.c */
void rproc_remove_trace_file(struct dentry *tfile); void rproc_remove_trace_file(struct dentry *tfile);
struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
struct rproc_mem_entry *trace); struct rproc_debug_trace *trace);
void rproc_delete_debug_dir(struct rproc *rproc); void rproc_delete_debug_dir(struct rproc *rproc);
void rproc_create_debug_dir(struct rproc *rproc); void rproc_create_debug_dir(struct rproc *rproc);
void rproc_init_debugfs(void); void rproc_init_debugfs(void);
...@@ -52,6 +59,7 @@ void rproc_free_vring(struct rproc_vring *rvring); ...@@ -52,6 +59,7 @@ void rproc_free_vring(struct rproc_vring *rvring);
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
phys_addr_t rproc_va_to_pa(void *cpu_addr);
int rproc_trigger_recovery(struct rproc *rproc); int rproc_trigger_recovery(struct rproc *rproc);
int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw); int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
......
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/dma-mapping.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/of_reserved_mem.h>
#include <linux/remoteproc.h> #include <linux/remoteproc.h>
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
...@@ -316,6 +318,8 @@ static void rproc_virtio_dev_release(struct device *dev) ...@@ -316,6 +318,8 @@ static void rproc_virtio_dev_release(struct device *dev)
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct rproc *rproc = vdev_to_rproc(vdev); struct rproc *rproc = vdev_to_rproc(vdev);
kfree(vdev);
kref_put(&rvdev->refcount, rproc_vdev_release); kref_put(&rvdev->refcount, rproc_vdev_release);
put_device(&rproc->dev); put_device(&rproc->dev);
...@@ -333,10 +337,53 @@ static void rproc_virtio_dev_release(struct device *dev) ...@@ -333,10 +337,53 @@ static void rproc_virtio_dev_release(struct device *dev)
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
{ {
struct rproc *rproc = rvdev->rproc; struct rproc *rproc = rvdev->rproc;
struct device *dev = &rproc->dev; struct device *dev = &rvdev->dev;
struct virtio_device *vdev = &rvdev->vdev; struct virtio_device *vdev;
struct rproc_mem_entry *mem;
int ret; int ret;
/* Try to find dedicated vdev buffer carveout */
mem = rproc_find_carveout_by_name(rproc, "vdev%dbuffer", rvdev->index);
if (mem) {
phys_addr_t pa;
if (mem->of_resm_idx != -1) {
struct device_node *np = rproc->dev.parent->of_node;
/* Associate reserved memory to vdev device */
ret = of_reserved_mem_device_init_by_idx(dev, np,
mem->of_resm_idx);
if (ret) {
dev_err(dev, "Can't associate reserved memory\n");
goto out;
}
} else {
if (mem->va) {
dev_warn(dev, "vdev %d buffer already mapped\n",
rvdev->index);
pa = rproc_va_to_pa(mem->va);
} else {
/* Use dma address as carveout no memmapped yet */
pa = (phys_addr_t)mem->dma;
}
/* Associate vdev buffer memory pool to vdev subdev */
ret = dma_declare_coherent_memory(dev, pa,
mem->da,
mem->len);
if (ret < 0) {
dev_err(dev, "Failed to associate buffer\n");
goto out;
}
}
}
/* Allocate virtio device */
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
if (!vdev) {
ret = -ENOMEM;
goto out;
}
vdev->id.device = id, vdev->id.device = id,
vdev->config = &rproc_virtio_config_ops, vdev->config = &rproc_virtio_config_ops,
vdev->dev.parent = dev; vdev->dev.parent = dev;
...@@ -370,11 +417,15 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) ...@@ -370,11 +417,15 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
/** /**
* rproc_remove_virtio_dev() - remove an rproc-induced virtio device * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
* @rvdev: the remote vdev * @dev: the virtio device
* @data: must be null
* *
* This function unregisters an existing virtio device. * This function unregisters an existing virtio device.
*/ */
void rproc_remove_virtio_dev(struct rproc_vdev *rvdev) int rproc_remove_virtio_dev(struct device *dev, void *data)
{ {
unregister_virtio_device(&rvdev->vdev); struct virtio_device *vdev = dev_to_virtio(dev);
unregister_virtio_device(vdev);
return 0;
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_reserved_mem.h> #include <linux/of_reserved_mem.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -91,6 +92,77 @@ static void st_rproc_kick(struct rproc *rproc, int vqid) ...@@ -91,6 +92,77 @@ static void st_rproc_kick(struct rproc *rproc, int vqid)
dev_err(dev, "failed to send message via mbox: %d\n", ret); dev_err(dev, "failed to send message via mbox: %d\n", ret);
} }
static int st_rproc_mem_alloc(struct rproc *rproc,
struct rproc_mem_entry *mem)
{
struct device *dev = rproc->dev.parent;
void *va;
va = ioremap_wc(mem->dma, mem->len);
if (!va) {
dev_err(dev, "Unable to map memory region: %pa+%zx\n",
&mem->dma, mem->len);
return -ENOMEM;
}
/* Update memory entry va */
mem->va = va;
return 0;
}
static int st_rproc_mem_release(struct rproc *rproc,
struct rproc_mem_entry *mem)
{
iounmap(mem->va);
return 0;
}
static int st_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
{
struct device *dev = rproc->dev.parent;
struct device_node *np = dev->of_node;
struct rproc_mem_entry *mem;
struct reserved_mem *rmem;
struct of_phandle_iterator it;
int index = 0;
of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
while (of_phandle_iterator_next(&it) == 0) {
rmem = of_reserved_mem_lookup(it.node);
if (!rmem) {
dev_err(dev, "unable to acquire memory-region\n");
return -EINVAL;
}
/* No need to map vdev buffer */
if (strcmp(it.node->name, "vdev0buffer")) {
/* Register memory region */
mem = rproc_mem_entry_init(dev, NULL,
(dma_addr_t)rmem->base,
rmem->size, rmem->base,
st_rproc_mem_alloc,
st_rproc_mem_release,
it.node->name);
} else {
/* Register reserved memory for vdev buffer allocation */
mem = rproc_of_resm_mem_entry_init(dev, index,
rmem->size,
rmem->base,
it.node->name);
}
if (!mem)
return -ENOMEM;
rproc_add_carveout(rproc, mem);
index++;
}
return rproc_elf_load_rsc_table(rproc, fw);
}
static int st_rproc_start(struct rproc *rproc) static int st_rproc_start(struct rproc *rproc)
{ {
struct st_rproc *ddata = rproc->priv; struct st_rproc *ddata = rproc->priv;
...@@ -158,9 +230,14 @@ static int st_rproc_stop(struct rproc *rproc) ...@@ -158,9 +230,14 @@ static int st_rproc_stop(struct rproc *rproc)
} }
static const struct rproc_ops st_rproc_ops = { static const struct rproc_ops st_rproc_ops = {
.kick = st_rproc_kick, .kick = st_rproc_kick,
.start = st_rproc_start, .start = st_rproc_start,
.stop = st_rproc_stop, .stop = st_rproc_stop,
.parse_fw = st_rproc_parse_fw,
.load = rproc_elf_load_segments,
.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
}; };
/* /*
...@@ -254,12 +331,6 @@ static int st_rproc_parse_dt(struct platform_device *pdev) ...@@ -254,12 +331,6 @@ static int st_rproc_parse_dt(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
err = of_reserved_mem_device_init(dev);
if (err) {
dev_err(dev, "Failed to obtain shared memory\n");
return err;
}
err = clk_prepare(ddata->clk); err = clk_prepare(ddata->clk);
if (err) if (err)
dev_err(dev, "failed to get clock\n"); dev_err(dev, "failed to get clock\n");
...@@ -387,8 +458,6 @@ static int st_rproc_remove(struct platform_device *pdev) ...@@ -387,8 +458,6 @@ static int st_rproc_remove(struct platform_device *pdev)
clk_disable_unprepare(ddata->clk); clk_disable_unprepare(ddata->clk);
of_reserved_mem_device_release(&pdev->dev);
for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++) for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++)
mbox_free_channel(ddata->mbox_chan[i]); mbox_free_channel(ddata->mbox_chan[i]);
......
...@@ -11,21 +11,21 @@ ...@@ -11,21 +11,21 @@
#define pr_fmt(fmt) "%s: " fmt, __func__ #define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/virtio.h> #include <linux/mutex.h>
#include <linux/virtio_ids.h> #include <linux/of_device.h>
#include <linux/virtio_config.h> #include <linux/rpmsg.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/idr.h>
#include <linux/jiffies.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/rpmsg.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include "rpmsg_internal.h" #include "rpmsg_internal.h"
...@@ -912,7 +912,7 @@ static int rpmsg_probe(struct virtio_device *vdev) ...@@ -912,7 +912,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
total_buf_space = vrp->num_bufs * vrp->buf_size; total_buf_space = vrp->num_bufs * vrp->buf_size;
/* allocate coherent memory for the buffers */ /* allocate coherent memory for the buffers */
bufs_va = dma_alloc_coherent(vdev->dev.parent->parent, bufs_va = dma_alloc_coherent(vdev->dev.parent,
total_buf_space, &vrp->bufs_dma, total_buf_space, &vrp->bufs_dma,
GFP_KERNEL); GFP_KERNEL);
if (!bufs_va) { if (!bufs_va) {
...@@ -980,7 +980,7 @@ static int rpmsg_probe(struct virtio_device *vdev) ...@@ -980,7 +980,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
return 0; return 0;
free_coherent: free_coherent:
dma_free_coherent(vdev->dev.parent->parent, total_buf_space, dma_free_coherent(vdev->dev.parent, total_buf_space,
bufs_va, vrp->bufs_dma); bufs_va, vrp->bufs_dma);
vqs_del: vqs_del:
vdev->config->del_vqs(vrp->vdev); vdev->config->del_vqs(vrp->vdev);
...@@ -1015,7 +1015,7 @@ static void rpmsg_remove(struct virtio_device *vdev) ...@@ -1015,7 +1015,7 @@ static void rpmsg_remove(struct virtio_device *vdev)
vdev->config->del_vqs(vrp->vdev); vdev->config->del_vqs(vrp->vdev);
dma_free_coherent(vdev->dev.parent->parent, total_buf_space, dma_free_coherent(vdev->dev.parent, total_buf_space,
vrp->rbufs, vrp->bufs_dma); vrp->rbufs, vrp->bufs_dma);
kfree(vrp); kfree(vrp);
......
...@@ -345,9 +345,9 @@ struct firmware; ...@@ -345,9 +345,9 @@ struct firmware;
* @stop: power off the device * @stop: power off the device
* @kick: kick a virtqueue (virtqueue id given as a parameter) * @kick: kick a virtqueue (virtqueue id given as a parameter)
* @da_to_va: optional platform hook to perform address translations * @da_to_va: optional platform hook to perform address translations
* @load_rsc_table: load resource table from firmware image * @parse_fw: parse firmware to extract information (e.g. resource table)
* @find_loaded_rsc_table: find the loaded resouce table * @find_loaded_rsc_table: find the loaded resouce table
* @load: load firmeware to memory, where the remote processor * @load: load firmware to memory, where the remote processor
* expects to find it * expects to find it
* @sanity_check: sanity check the fw image * @sanity_check: sanity check the fw image
* @get_boot_addr: get boot address to entry point specified in firmware * @get_boot_addr: get boot address to entry point specified in firmware
...@@ -554,11 +554,11 @@ struct rproc_vdev { ...@@ -554,11 +554,11 @@ struct rproc_vdev {
struct kref refcount; struct kref refcount;
struct rproc_subdev subdev; struct rproc_subdev subdev;
struct device dev;
unsigned int id; unsigned int id;
struct list_head node; struct list_head node;
struct rproc *rproc; struct rproc *rproc;
struct virtio_device vdev;
struct rproc_vring vring[RVDEV_NUM_VRINGS]; struct rproc_vring vring[RVDEV_NUM_VRINGS];
u32 rsc_offset; u32 rsc_offset;
u32 index; u32 index;
...@@ -601,7 +601,7 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc, ...@@ -601,7 +601,7 @@ int rproc_coredump_add_custom_segment(struct rproc *rproc,
static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
{ {
return container_of(vdev, struct rproc_vdev, vdev); return container_of(vdev->dev.parent, struct rproc_vdev, dev);
} }
static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment