author | Dan Murphy <DMurphy@ti.com> | |
Sat, 30 May 2015 17:15:54 +0000 (12:15 -0500) | ||
committer | Dan Murphy <DMurphy@ti.com> | |
Sat, 30 May 2015 17:15:54 +0000 (12:15 -0500) |
TI-Feature: rpmsg
TI-Tree: git://git.ti.com/rpmsg/rpmsg.git
TI-Branch: rpmsg-ti-linux-3.14.y
* 'rpmsg-ti-linux-3.14.y' of git://git.ti.com/rpmsg/rpmsg:
samples/rpmsg: add support for multiple instances
Revert "ARM: OMAP: DRA7: change IPU1 clk domain to SWSUP for proper boot"
ARM: OMAP2+: use separate IOMMU pdata to fix DRA7 IPU1 boot
iommu/omap: fix boot issue on remoteprocs with AMMU/Unicache
iommu/omap: add pdata ops for setting powerdomain constraint
ARM: dts: OMAP5: Fix the standby info for IPU & DSP
remoteproc/omap: revise the comment about standby in _suspend
remoteproc/pruss: fix pruss_init return on error
remoteproc/pruss: lower the trace level in pru_rproc_mbox_callback
remoteproc/omap: fix a minor typo in a trace message
remoteproc/omap: add support for runtime auto-suspend/resume
Signed-off-by: Dan Murphy <DMurphy@ti.com>
TI-Tree: git://git.ti.com/rpmsg/rpmsg.git
TI-Branch: rpmsg-ti-linux-3.14.y
* 'rpmsg-ti-linux-3.14.y' of git://git.ti.com/rpmsg/rpmsg:
samples/rpmsg: add support for multiple instances
Revert "ARM: OMAP: DRA7: change IPU1 clk domain to SWSUP for proper boot"
ARM: OMAP2+: use separate IOMMU pdata to fix DRA7 IPU1 boot
iommu/omap: fix boot issue on remoteprocs with AMMU/Unicache
iommu/omap: add pdata ops for setting powerdomain constraint
ARM: dts: OMAP5: Fix the standby info for IPU & DSP
remoteproc/omap: revise the comment about standby in _suspend
remoteproc/pruss: fix pruss_init return on error
remoteproc/pruss: lower the trace level in pru_rproc_mbox_callback
remoteproc/omap: fix a minor typo in a trace message
remoteproc/omap: add support for runtime auto-suspend/resume
Signed-off-by: Dan Murphy <DMurphy@ti.com>
index 57409887c920bf2d1d2607f095adc64de5308582..941c097156c2ac78da277c0212c3a95d14a9f504 100644 (file)
compatible = "ti,omap4-iommu";
reg = <0x4a066000 0x100>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
- ti,rproc-standby-info = <0x4a004420>;
ti,hwmods = "mmu_dsp";
};
reg = <0x55082000 0x100>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mmu_ipu";
- ti,rproc-standby-info = <0x4a008920>;
ti,iommu-bus-err-back;
};
ti,hwmods = "dsp";
iommus = <&mmu_dsp>;
mboxes = <&mailbox &mbox_dsp>;
+ ti,rproc-standby-info = <0x4a004420>;
status = "disabled";
};
ti,hwmods = "ipu";
iommus = <&mmu_ipu>;
mboxes = <&mailbox &mbox_ipu>;
+ ti,rproc-standby-info = <0x4a008920>;
status = "disabled";
};
diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c
index 50859fc3beb9448f5a25466b4e8be03e030b1322..6070f9d5c2e914405e9281dedb8d5cd37c851232 100644 (file)
.dep_bit = DRA7XX_IPU1_STATDEP_SHIFT,
.wkdep_srcs = ipu1_wkup_sleep_deps,
.sleepdep_srcs = ipu1_wkup_sleep_deps,
- .flags = CLKDM_CAN_SWSUP,
+ .flags = CLKDM_CAN_HWSUP_SWSUP,
};
static struct clockdomain ipu2_7xx_clkdm = {
index d6803a41034c1b4f3b1dc2af8aee64f7af8067b3..346860ce040b373a2f0d7f428f421d7b42c8cd35 100644 (file)
#include "soc.h"
#include "omap_hwmod.h"
#include "omap_device.h"
+#include "powerdomain.h"
+
+int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
+ u8 *pwrst)
+{
+ struct powerdomain *pwrdm;
+ struct omap_device *od;
+ u8 next_pwrst;
+
+ od = to_omap_device(pdev);
+ if (!od)
+ return -ENODEV;
+
+ if (od->hwmods_cnt != 1)
+ return -EINVAL;
+
+ pwrdm = omap_hwmod_get_pwrdm(od->hwmods[0]);
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (request)
+ *pwrst = pwrdm_read_next_pwrst(pwrdm);
+
+ if (*pwrst > PWRDM_POWER_RET)
+ return 0;
+
+ next_pwrst = request ? PWRDM_POWER_ON : *pwrst;
+
+ return pwrdm_set_next_pwrst(pwrdm, next_pwrst);
+}
static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused)
{
index 58ecb52e1ae54109b005fc1b59d0128c4c400a30..b9c8348671440234baffaf9abc949826abfea7ab 100644 (file)
struct of_dev_auxdata omap_auxdata_lookup[];
static struct twl4030_gpio_platform_data twl_gpio_auxdata;
+#if IS_ENABLED(CONFIG_OMAP_IOMMU)
+int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
+ u8 *pwrst);
+#else
+static inline int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev,
+ bool request, u8 *pwrst)
+{
+ return 0;
+}
+#endif
+
#if IS_ENABLED(CONFIG_WL12XX)
static struct wl12xx_platform_data wl12xx __initdata;
.device_idle = omap_device_idle,
};
+static struct iommu_platform_data dra7_ipu1_iommu_pdata = {
+ .reset_name = "mmu_cache",
+ .assert_reset = omap_device_assert_hardreset,
+ .deassert_reset = omap_device_deassert_hardreset,
+ .device_enable = omap_device_enable,
+ .device_idle = omap_device_idle,
+ .set_pwrdm_constraint = omap_iommu_set_pwrdm_constraint,
+};
+
static struct omap_rproc_pdata dra7_dsp1_pdata = {
.device_enable = omap_rproc_device_enable,
.device_shutdown = omap_rproc_device_shutdown,
OF_DEV_AUXDATA("ti,dra7-iommu", 0x55082000, "55082000.mmu",
&omap4_iommu_pdata),
OF_DEV_AUXDATA("ti,dra7-iommu", 0x58882000, "58882000.mmu",
- &omap4_iommu_pdata),
+ &dra7_ipu1_iommu_pdata),
OF_DEV_AUXDATA("ti,dra7-rproc-ipu", 0x55020000, "55020000.ipu",
&omap4_ipu_pdata),
OF_DEV_AUXDATA("ti,dra7-rproc-ipu", 0x58820000, "58820000.ipu",
index 17b7890616b2ce105eacdaea0fb84f72591bb8ce..1b2c3ac2fe0d2f08db681403f111092fb2acde49 100644 (file)
struct platform_device *pdev = to_platform_device(dev);
struct iommu_platform_data *pdata = dev_get_platdata(dev);
struct omap_iommu *obj = to_iommu(dev);
+ int ret;
/* save the TLBs only during suspend, and not for power down */
if (obj->domain && obj->iopgd)
if (pdata && pdata->assert_reset)
pdata->assert_reset(pdev, pdata->reset_name);
+ if (pdata && pdata->set_pwrdm_constraint) {
+ ret = pdata->set_pwrdm_constraint(pdev, false, &obj->pwrst);
+ if (ret) {
+ dev_warn(dev, "pwrdm_constraint failed to be reset, status = %d\n",
+ ret);
+ }
+ }
+
return 0;
}
struct omap_iommu *obj = to_iommu(dev);
int ret = 0;
+ if (pdata && pdata->set_pwrdm_constraint) {
+ ret = pdata->set_pwrdm_constraint(pdev, true, &obj->pwrst);
+ if (ret) {
+ dev_warn(dev, "pwrdm_constraint failed to be set, status = %d\n",
+ ret);
+ }
+ }
+
if (pdata && pdata->deassert_reset) {
ret = pdata->deassert_reset(pdev, pdata->reset_name);
if (ret) {
index 4278aa36b77065ac726f2b1892426cc9b6ff89c7..5d76c0844a82c2a21a64d838803bea0eb82f3c9b 100644 (file)
int has_bus_err_back;
u32 id;
+
+ u8 pwrst;
};
struct cr_regs {
index ee3b551c7b180c1c0af732a1d88c82517d56750a..d4a0e0d9f475bbf3ebfed94b1eb063efb54ef66e 100644 (file)
#include <linux/mailbox_client.h>
#include <linux/omap-mailbox.h>
#include <linux/omap-iommu.h>
+#include <linux/pm_runtime.h>
#include <linux/platform_data/remoteproc-omap.h>
#include "omap_remoteproc.h"
#include "remoteproc_internal.h"
+/* default auto-suspend delay (ms) */
+#define DEFAULT_AUTOSUSPEND_DELAY 10000
+
/**
* struct omap_rproc_timers_info - timers for the omap rproc
* @odt: timer pointer
* @num_timers: number of rproc timer(s)
* @num_wd_timers: number of rproc watchdog timers
* @timers: timer(s) info used by rproc
+ * @autosuspend_delay: auto-suspend delay value to be used for runtime pm
+ * @need_resume: if true a resume is needed in the system resume callback
* @rproc: rproc handle
* @pm_comp: completion primitive to sync for suspend response
* @standby_addr: kernel address of the register having module standby status
int num_timers;
int num_wd_timers;
struct omap_rproc_timers_info *timers;
+ int autosuspend_delay;
+ bool need_resume;
struct rproc *rproc;
struct completion pm_comp;
void __iomem *standby_addr;
* struct omap_rproc_fw_data - firmware data for the omap remote processor
* @device_name: device name of the remote processor
* @fw_name: firmware name to use
+ * @autosuspend_delay: custom auto-suspend delay value in milliseconds
*/
struct omap_rproc_fw_data {
const char *device_name;
const char *fw_name;
+ int autosuspend_delay;
};
/**
struct device *dev = rproc->dev.parent;
int ret;
+ /* wake up the rproc before kicking it */
+ ret = pm_runtime_get_sync(dev);
+ if (WARN_ON(ret < 0)) {
+ dev_err(dev, "pm_runtime_get_sync() failed during kick, ret = %d\n",
+ ret);
+ pm_runtime_put_noidle(dev);
+ return;
+ }
+
/* send the index of the triggered virtqueue in the mailbox payload */
ret = mbox_send_message(oproc->mbox, (void *)vqid);
if (ret < 0)
- dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret);
+ dev_err(dev, "mbox_send_message failed: %d\n", ret);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
/*
goto reset_timers;
}
+ /*
+ * remote processor is up, so update the runtime pm status and
+ * enable the auto-suspend. The device usage count is incremented
+ * manually for balancing it for auto-suspend
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_autosuspend_delay(dev, oproc->autosuspend_delay);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
return 0;
reset_timers:
struct omap_rproc *oproc = rproc->priv;
int ret;
+ /*
+ * cancel any possible scheduled runtime suspend by incrementing
+ * the device usage count, and resuming the device. The remoteproc
+ * also needs to be woken up if suspended, to avoid the remoteproc
+ * OS to continue to remember any context that it has saved, and
+ * avoid potential issues in misindentifying a subsequent device
+ * reboot as a power restore boot
+ */
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
ret = pdata->device_shutdown(pdev);
if (ret)
- return ret;
+ goto out;
ret = omap_rproc_disable_timers(pdev, true);
if (ret)
- return ret;
+ goto enable_device;
mbox_free_channel(oproc->mbox);
+ /*
+ * update the runtime pm states and status now that the remoteproc
+ * has stopped
+ */
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
return 0;
+
+enable_device:
+ pdata->device_enable(pdev);
+out:
+ /* schedule the next auto-suspend */
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+
}
static struct rproc_ops omap_rproc_ops = {
/* 1 sec is long enough time to let the remoteproc side suspend the device */
#define DEF_SUSPEND_TIMEOUT 1000
-static int _omap_rproc_suspend(struct rproc *rproc)
+static int _suspend(struct rproc *rproc, bool auto_suspend)
{
struct device *dev = rproc->dev.parent;
struct platform_device *pdev = to_platform_device(dev);
struct omap_rproc *oproc = rproc->priv;
unsigned long to = msecs_to_jiffies(DEF_SUSPEND_TIMEOUT);
unsigned long ta = jiffies + to;
+ u32 suspend_msg = auto_suspend ?
+ RP_MBOX_SUSPEND_AUTO : RP_MBOX_SUSPEND_SYSTEM;
int ret;
reinit_completion(&oproc->pm_comp);
oproc->suspend_acked = false;
- ret = mbox_send_message(oproc->mbox, (void *)RP_MBOX_SUSPEND_SYSTEM);
+ ret = mbox_send_message(oproc->mbox, (void *)suspend_msg);
if (ret < 0) {
dev_err(dev, "PM mbox_send_message failed: %d\n", ret);
return ret;
return -EBUSY;
/*
- * XXX: The remoteproc side is returning the ACK message before saving
- * the context, because the context saving is performed within a
- * SYS/BIOS function, and it cannot have any inter-dependencies against
- * the IPC layer. Revisit this when SYS/BIOS can be improved to send an
- * ACK using a BIOS-independent function hook. However, we can know that
- * the remote processor has completed saving the context once the module
- * reached STANDBY state (after saving the context, the SYS/BIOS
- * executes the appropriate target-specific WFI instruction).
+ * The remoteproc side is returning the ACK message before saving the
+ * context, because the context saving is performed within a SYS/BIOS
+ * function, and it cannot have any inter-dependencies against the IPC
+ * layer. Also, as the SYS/BIOS needs to preserve properly the processor
+ * register set, sending this ACK or signalling the completion of the
+ * context save through a shared memory variable can never be the
+ * absolute last thing to be executed on the remoteproc side, and the
+ * MPU cannot use the ACK message as a sync point to put the remoteproc
+ * into reset. The only way to ensure that the remote processor has
+ * completed saving the context is to check that the module has reached
+ * STANDBY state (after saving the context, the SYS/BIOS executes the
+ * appropriate target-specific WFI instruction causing the module to
+ * enter STANDBY).
*/
while (!_is_rproc_in_standby(oproc)) {
if (time_after(jiffies, ta))
goto enable_device;
}
- ret = omap_iommu_domain_suspend(rproc->domain, false);
+ ret = omap_iommu_domain_suspend(rproc->domain, auto_suspend);
if (ret) {
dev_err(dev, "iommu domain suspend failed %d\n", ret);
goto enable_timers;
return ret;
}
-static int _omap_rproc_resume(struct rproc *rproc)
+static int _omap_rproc_suspend(struct rproc *rproc, bool auto_suspend)
+{
+ struct omap_rproc *oproc = rproc->priv;
+
+ /*
+ * do not even attempt suspend if the remote processor is not
+ * idled for auto-suspend
+ */
+ if (auto_suspend && !_is_rproc_in_standby(oproc))
+ return -EBUSY;
+
+ return _suspend(rproc, auto_suspend);
+}
+
+static int _omap_rproc_resume(struct rproc *rproc, bool auto_suspend)
{
struct device *dev = rproc->dev.parent;
struct platform_device *pdev = to_platform_device(dev);
struct omap_rproc_pdata *pdata = dev_get_platdata(dev);
int ret;
- ret = omap_iommu_domain_resume(rproc->domain, false);
+ ret = omap_iommu_domain_resume(rproc->domain, auto_suspend);
if (ret) {
dev_err(dev, "omap_iommu resume failed %d\n", ret);
goto out;
disable_timers:
omap_rproc_disable_timers(pdev, false);
suspend_iommu:
- omap_iommu_domain_suspend(rproc->domain, false);
+ omap_iommu_domain_suspend(rproc->domain, auto_suspend);
out:
return ret;
}
{
struct platform_device *pdev = to_platform_device(dev);
struct rproc *rproc = platform_get_drvdata(pdev);
+ struct omap_rproc *oproc = rproc->priv;
int ret = 0;
mutex_lock(&rproc->lock);
goto out;
}
- ret = _omap_rproc_suspend(rproc);
+ ret = _omap_rproc_suspend(rproc, false);
if (ret) {
dev_err(dev, "suspend failed %d\n", ret);
goto out;
}
+ /*
+ * remoteproc is running at the time of system suspend, so remember
+ * it so as to wake it up during system resume
+ */
+ oproc->need_resume = 1;
rproc->state = RPROC_SUSPENDED;
+
+ /*
+ * update the runtime pm status to be suspended, without decrementing
+ * the device usage count
+ */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
out:
mutex_unlock(&rproc->lock);
return ret;
{
struct platform_device *pdev = to_platform_device(dev);
struct rproc *rproc = platform_get_drvdata(pdev);
+ struct omap_rproc *oproc = rproc->priv;
int ret = 0;
mutex_lock(&rproc->lock);
goto out;
}
- ret = _omap_rproc_resume(rproc);
+ /*
+ * remoteproc was auto-suspended at the time of system suspend,
+ * so no need to wake-up the processor (leave it in suspended
+ * state, will be woken up during a subsequent runtime_resume)
+ */
+ if (!oproc->need_resume)
+ goto out;
+
+ ret = _omap_rproc_resume(rproc, false);
if (ret) {
dev_err(dev, "resume failed %d\n", ret);
goto out;
}
+ oproc->need_resume = false;
rproc->state = RPROC_RUNNING;
+
+ /*
+ * update the runtime pm status to be active, without incrementing
+ * the device usage count
+ */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_mark_last_busy(dev);
out:
mutex_unlock(&rproc->lock);
return ret;
}
+
+static int omap_rproc_runtime_suspend(struct device *dev)
+{
+ struct rproc *rproc = dev_get_drvdata(dev);
+ int ret;
+
+ if (WARN_ON(rproc->state != RPROC_RUNNING)) {
+ dev_err(dev, "rproc cannot be runtime suspended when not running!\n");
+ return -EBUSY;
+ }
+
+ ret = _omap_rproc_suspend(rproc, true);
+ if (ret)
+ goto abort;
+
+ rproc->state = RPROC_SUSPENDED;
+ return 0;
+
+abort:
+ pm_runtime_mark_last_busy(dev);
+ return ret;
+}
+
+static int omap_rproc_runtime_resume(struct device *dev)
+{
+ struct rproc *rproc = dev_get_drvdata(dev);
+ int ret;
+
+ if (WARN_ON(rproc->state != RPROC_SUSPENDED)) {
+ dev_err(dev, "rproc cannot be runtime resumed if not suspended!\n");
+ return -EBUSY;
+ }
+
+ ret = _omap_rproc_resume(rproc, true);
+ if (ret) {
+ dev_err(dev, "runtime resume failed %d\n", ret);
+ return ret;
+ }
+
+ rproc->state = RPROC_RUNNING;
+ return 0;
+}
#endif /* CONFIG_PM */
static const struct omap_rproc_fw_data omap4_dsp_fw_data = {
};
MODULE_DEVICE_TABLE(of, omap_rproc_of_match);
+static int omap_rproc_get_autosuspend_delay(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct omap_rproc_fw_data *data;
+ const struct of_device_id *match;
+ int delay = -EINVAL;
+
+ match = of_match_device(omap_rproc_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ data = match->data;
+
+ if (!of_device_is_compatible(np, "ti,dra7-rproc-dsp") &&
+ !of_device_is_compatible(np, "ti,dra7-rproc-ipu")) {
+ delay = data->autosuspend_delay;
+ goto out;
+ }
+
+ for (; data && data->device_name; data++) {
+ if (!strcmp(dev_name(&pdev->dev), data->device_name)) {
+ delay = data->autosuspend_delay;
+ break;
+ }
+ }
+
+out:
+ return (delay > 0) ? delay : DEFAULT_AUTOSUSPEND_DELAY;
+}
+
static const char *omap_rproc_get_firmware(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
return -ENODEV;
}
+ /*
+ * self-manage the ordering dependencies between omap_device_enable/idle
+ * and omap_device_assert/deassert_hardreset API during runtime suspend
+ * and resume, rather than relying on the order in omap_device layer.
+ */
+ if (pdev->dev.pm_domain) {
+ dev_dbg(&pdev->dev, "device pm_domain is being reset for this remoteproc device\n");
+ pdev->dev.pm_domain = NULL;
+ }
+
if (!pdata || !pdata->device_enable || !pdata->device_shutdown) {
dev_err(&pdev->dev, "platform data is either missing or incomplete\n");
return -ENODEV;
}
init_completion(&oproc->pm_comp);
+ oproc->autosuspend_delay = omap_rproc_get_autosuspend_delay(pdev);
+ if (oproc->autosuspend_delay < 0)
+ goto free_rproc;
ret = of_property_read_u32(np, "ti,rproc-standby-info", &standby_addr);
if (ret || !standby_addr)
static const struct dev_pm_ops omap_rproc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_rproc_suspend, omap_rproc_resume)
+ SET_RUNTIME_PM_OPS(omap_rproc_runtime_suspend,
+ omap_rproc_runtime_resume, NULL)
};
static struct platform_driver omap_rproc_driver = {
index 78d5806292bee31107398cfcfa74283fcbf02050..3e374a06562cf58ec7e0404c3c1ebd3ecdff56fa 100644 (file)
/* msg contains the index of the triggered vring */
if (rproc_vq_interrupt(pru->rproc, msg) == IRQ_NONE)
- dev_err(dev, "no message was found in vqid %d\n", msg);
+ dev_dbg(dev, "no message was found in vqid %d\n", msg);
}
/* kick a virtqueue */
platform_driver_unregister(&pruss_driver);
}
- return 0;
+ return ret;
}
module_init(pruss_init);
index 8aec9172822cbbea6fb1069d6fa9a84b7238342c..f5b08ec6c1b4b2092583a56d115b3d9a3f358c40 100644 (file)
int (*deassert_reset)(struct platform_device *pdev, const char *name);
int (*device_enable)(struct platform_device *pdev);
int (*device_idle)(struct platform_device *pdev);
+ int (*set_pwrdm_constraint)(struct platform_device *pdev, bool request,
+ u8 *pwrst);
};
index 59b13440813d59da2f4fd7869e960da29739c3b9..f950302af90543496beac3d360579eae2f2429b8 100644 (file)
#define MSG "hello world!"
#define MSG_LIMIT 100
+struct instance_data {
+ int rx_count;
+};
+
static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
void *priv, u32 src)
{
int ret;
- static int rx_count;
+ struct instance_data *idata = dev_get_drvdata(&rpdev->dev);
- dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
+ dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n",
+ ++idata->rx_count, src);
print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
data, len, true);
/* samples should not live forever */
- if (rx_count >= MSG_LIMIT) {
+ if (idata->rx_count >= MSG_LIMIT) {
dev_info(&rpdev->dev, "goodbye!\n");
return;
}
static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
{
int ret;
+ struct instance_data *idata;
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
rpdev->src, rpdev->dst);
+ idata = devm_kzalloc(&rpdev->dev, sizeof(*idata), GFP_KERNEL);
+ if (!idata) {
+ dev_err(&rpdev->dev, "channel data memory allocation failed\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(&rpdev->dev, idata);
+
/* send a message to our remote processor */
ret = rpmsg_send(rpdev, MSG, strlen(MSG));
if (ret) {