ipc: wcd-dsp-glink: move wdsp ipc to rpmsg
Add support for wdsp communication over rpmsg to enable
inter process communication between application processor
and codec DSP.
Change-Id: I6679e9d8b104bbd41e19bbf788a41129dc97da88
Signed-off-by: Vidyakumar Athota <vathota@codeaurora.org>
diff --git a/ipc/wcd-dsp-glink.c b/ipc/wcd-dsp-glink.c
index 400fd06..04df026 100644
--- a/ipc/wcd-dsp-glink.c
+++ b/ipc/wcd-dsp-glink.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,34 +13,33 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/list.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
+#include <linux/of_device.h>
#include <linux/vmalloc.h>
-#include <soc/qcom/glink.h>
+#include <linux/rpmsg.h>
#include "sound/wcd-dsp-glink.h"
#define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink"
#define WDSP_MAX_WRITE_SIZE (256 * 1024)
#define WDSP_MAX_READ_SIZE (4 * 1024)
-#define WDSP_MAX_NO_OF_INTENTS (20)
-#define WDSP_MAX_NO_OF_CHANNELS (10)
#define WDSP_WRITE_PKT_SIZE (sizeof(struct wdsp_write_pkt))
-#define WDSP_REG_PKT_SIZE (sizeof(struct wdsp_reg_pkt))
#define WDSP_CMD_PKT_SIZE (sizeof(struct wdsp_cmd_pkt))
-#define WDSP_CH_CFG_SIZE (sizeof(struct wdsp_glink_ch_cfg))
#define MINOR_NUMBER_COUNT 1
-#define WDSP_EDGE "wdsp"
#define RESP_QUEUE_SIZE 3
-#define QOS_PKT_SIZE 1024
#define TIMEOUT_MS 1000
+enum wdsp_ch_state {
+ WDSP_CH_DISCONNECTED,
+ WDSP_CH_CONNECTED,
+};
+
struct wdsp_glink_dev {
struct class *cls;
struct device *dev;
@@ -48,7 +47,7 @@
dev_t dev_num;
};
-struct wdsp_glink_rsp_que {
+struct wdsp_rsp_que {
/* Size of valid data in buffer */
u32 buf_size;
@@ -56,687 +55,230 @@
u8 buf[WDSP_MAX_READ_SIZE];
};
-struct wdsp_glink_tx_buf {
+struct wdsp_ch {
+ struct wdsp_glink_priv *wpriv;
+ /* rpmsg handle */
+ void *handle;
+ /* Channel states like connect, disconnect */
+ int ch_state;
+ char ch_name[RPMSG_NAME_SIZE];
+ spinlock_t ch_lock;
+};
+
+struct wdsp_tx_buf {
struct work_struct tx_work;
- struct work_struct free_tx_work;
/* Glink channel information */
- struct wdsp_glink_ch *ch;
+ struct wdsp_ch *ch;
/* Tx buffer to send to glink */
u8 buf[0];
};
-struct wdsp_glink_ch {
- struct wdsp_glink_priv *wpriv;
-
- /* Glink channel handle */
- void *handle;
-
- /* Channel states like connect, disconnect */
- int channel_state;
- struct mutex mutex;
-
- /* To free up the channel memory */
- bool free_mem;
-
- /* Glink local channel open work */
- struct work_struct lcl_ch_open_wrk;
-
- /* Glink local channel close work */
- struct work_struct lcl_ch_cls_wrk;
-
- /* Wait for ch connect state before sending any command */
- wait_queue_head_t ch_connect_wait;
-
- /*
- * Glink channel configuration. This has to be the last
- * member of the strucuture as it has variable size
- */
- struct wdsp_glink_ch_cfg ch_cfg;
-};
-
-struct wdsp_glink_state {
- /* Glink link state information */
- enum glink_link_state link_state;
- void *handle;
-};
-
struct wdsp_glink_priv {
/* Respone buffer related */
u8 rsp_cnt;
- struct wdsp_glink_rsp_que rsp[RESP_QUEUE_SIZE];
+ struct wdsp_rsp_que rsp[RESP_QUEUE_SIZE];
struct completion rsp_complete;
- struct mutex rsp_mutex;
+ spinlock_t rsp_lock;
/* Glink channel related */
- struct mutex glink_mutex;
- struct wdsp_glink_state glink_state;
- struct wdsp_glink_ch **ch;
- u8 no_of_channels;
- struct work_struct ch_open_cls_wrk;
+ int no_of_channels;
+ struct wdsp_ch **ch;
struct workqueue_struct *work_queue;
+ /* Wait for all channels state before sending any command */
+ wait_queue_head_t ch_state_wait;
- wait_queue_head_t link_state_wait;
-
+ struct wdsp_glink_dev *wdev;
struct device *dev;
};
+static struct wdsp_glink_priv *wpriv;
-static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch);
-static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch);
-
-/*
- * wdsp_glink_free_tx_buf_work - Work function to free tx pkt
- * work: Work structure
- */
-static void wdsp_glink_free_tx_buf_work(struct work_struct *work)
-{
- struct wdsp_glink_tx_buf *tx_buf;
-
- tx_buf = container_of(work, struct wdsp_glink_tx_buf,
- free_tx_work);
- vfree(tx_buf);
-}
-
-/*
- * wdsp_glink_free_tx_buf - Function to free tx buffer
- * priv: Pointer to the channel
- * pkt_priv: Pointer to the tx buffer
- */
-static void wdsp_glink_free_tx_buf(const void *priv, const void *pkt_priv)
-{
- struct wdsp_glink_tx_buf *tx_buf = (struct wdsp_glink_tx_buf *)pkt_priv;
- struct wdsp_glink_priv *wpriv;
- struct wdsp_glink_ch *ch;
-
- if (!priv) {
- pr_err("%s: Invalid priv\n", __func__);
- return;
- }
- if (!tx_buf) {
- pr_err("%s: Invalid tx_buf\n", __func__);
- return;
- }
-
- ch = (struct wdsp_glink_ch *)priv;
- wpriv = ch->wpriv;
- /* Work queue to free tx pkt */
- INIT_WORK(&tx_buf->free_tx_work, wdsp_glink_free_tx_buf_work);
- queue_work(wpriv->work_queue, &tx_buf->free_tx_work);
-}
-
-/*
- * wdsp_glink_notify_rx - Glink notify rx callback for responses
- * handle: Opaque Channel handle returned by GLink
- * priv: Private pointer to the channel
- * pkt_priv: Private pointer to the packet
- * ptr: Pointer to the Rx data
- * size: Size of the Rx data
- */
-static void wdsp_glink_notify_rx(void *handle, const void *priv,
- const void *pkt_priv, const void *ptr,
- size_t size)
-{
- u8 *rx_buf;
- u8 rsp_cnt;
- struct wdsp_glink_ch *ch;
- struct wdsp_glink_priv *wpriv;
-
- if (!ptr || !priv) {
- pr_err("%s: Invalid parameters\n", __func__);
- return;
- }
-
- ch = (struct wdsp_glink_ch *)priv;
- wpriv = ch->wpriv;
- rx_buf = (u8 *)ptr;
- if (size > WDSP_MAX_READ_SIZE) {
- dev_err(wpriv->dev, "%s: Size %zd is greater than allowed %d\n",
- __func__, size, WDSP_MAX_READ_SIZE);
- size = WDSP_MAX_READ_SIZE;
- }
-
- mutex_lock(&wpriv->rsp_mutex);
- rsp_cnt = wpriv->rsp_cnt;
- if (rsp_cnt >= RESP_QUEUE_SIZE) {
- dev_err(wpriv->dev, "%s: Resp Queue is Full\n", __func__);
- rsp_cnt = 0;
- }
- dev_dbg(wpriv->dev, "%s: copy into buffer %d\n", __func__, rsp_cnt);
-
- memcpy(wpriv->rsp[rsp_cnt].buf, rx_buf, size);
- wpriv->rsp[rsp_cnt].buf_size = size;
- wpriv->rsp_cnt = ++rsp_cnt;
- mutex_unlock(&wpriv->rsp_mutex);
-
- glink_rx_done(handle, ptr, true);
- complete(&wpriv->rsp_complete);
-}
-
-/*
- * wdsp_glink_notify_tx_done - Glink notify tx done callback to
- * free tx buffer
- * handle: Opaque Channel handle returned by GLink
- * priv: Private pointer to the channel
- * pkt_priv: Private pointer to the packet
- * ptr: Pointer to the Tx data
- */
-static void wdsp_glink_notify_tx_done(void *handle, const void *priv,
- const void *pkt_priv, const void *ptr)
-{
- wdsp_glink_free_tx_buf(priv, pkt_priv);
-}
-/*
- * wdsp_glink_notify_tx_abort - Glink notify tx abort callback to
- * free tx buffer
- * handle: Opaque Channel handle returned by GLink
- * priv: Private pointer to the channel
- * pkt_priv: Private pointer to the packet
- */
-static void wdsp_glink_notify_tx_abort(void *handle, const void *priv,
- const void *pkt_priv)
-{
- wdsp_glink_free_tx_buf(priv, pkt_priv);
-}
-
-/*
- * wdsp_glink_notify_rx_intent_req - Glink notify rx intent request callback
- * to queue buffer to receive from remote client
- * handle: Opaque channel handle returned by GLink
- * priv: Private pointer to the channel
- * req_size: Size of intent to be queued
- */
-static bool wdsp_glink_notify_rx_intent_req(void *handle, const void *priv,
- size_t req_size)
-{
- struct wdsp_glink_priv *wpriv;
- struct wdsp_glink_ch *ch;
- int rc = 0;
- bool ret = false;
-
- if (!priv) {
- pr_err("%s: Invalid priv\n", __func__);
- goto done;
- }
- if (req_size > WDSP_MAX_READ_SIZE) {
- pr_err("%s: Invalid req_size %zd\n", __func__, req_size);
- goto done;
- }
-
- ch = (struct wdsp_glink_ch *)priv;
- wpriv = ch->wpriv;
-
- dev_dbg(wpriv->dev, "%s: intent size %zd requested for ch name %s",
- __func__, req_size, ch->ch_cfg.name);
-
- mutex_lock(&ch->mutex);
- rc = glink_queue_rx_intent(ch->handle, ch, req_size);
- if (rc < 0) {
- dev_err(wpriv->dev, "%s: Failed to queue rx intent, rc = %d\n",
- __func__, rc);
- mutex_unlock(&ch->mutex);
- goto done;
- }
- mutex_unlock(&ch->mutex);
- ret = true;
-
-done:
- return ret;
-}
-
-/*
- * wdsp_glink_lcl_ch_open_wrk - Work function to open channel again
- * when local disconnect event happens
- * work: Work structure
- */
-static void wdsp_glink_lcl_ch_open_wrk(struct work_struct *work)
-{
- struct wdsp_glink_ch *ch;
-
- ch = container_of(work, struct wdsp_glink_ch,
- lcl_ch_open_wrk);
-
- wdsp_glink_open_ch(ch);
-}
-
-/*
- * wdsp_glink_lcl_ch_cls_wrk - Work function to close channel locally
- * when remote disconnect event happens
- * work: Work structure
- */
-static void wdsp_glink_lcl_ch_cls_wrk(struct work_struct *work)
-{
- struct wdsp_glink_ch *ch;
-
- ch = container_of(work, struct wdsp_glink_ch,
- lcl_ch_cls_wrk);
-
- wdsp_glink_close_ch(ch);
-}
-
-/*
- * wdsp_glink_notify_state - Glink channel state information event callback
- * handle: Opaque Channel handle returned by GLink
- * priv: Private pointer to the channel
- * event: channel state event
- */
-static void wdsp_glink_notify_state(void *handle, const void *priv,
- unsigned int event)
-{
- struct wdsp_glink_priv *wpriv;
- struct wdsp_glink_ch *ch;
- int i, ret = 0;
-
- if (!priv) {
- pr_err("%s: Invalid priv\n", __func__);
- return;
- }
-
- ch = (struct wdsp_glink_ch *)priv;
- wpriv = ch->wpriv;
-
- mutex_lock(&ch->mutex);
- ch->channel_state = event;
- if (event == GLINK_CONNECTED) {
- dev_dbg(wpriv->dev, "%s: glink channel: %s connected\n",
- __func__, ch->ch_cfg.name);
-
- for (i = 0; i < ch->ch_cfg.no_of_intents; i++) {
- dev_dbg(wpriv->dev, "%s: intent_size = %d\n", __func__,
- ch->ch_cfg.intents_size[i]);
- ret = glink_queue_rx_intent(ch->handle, ch,
- ch->ch_cfg.intents_size[i]);
- if (ret < 0)
- dev_warn(wpriv->dev, "%s: Failed to queue intent %d of size %d\n",
- __func__, i,
- ch->ch_cfg.intents_size[i]);
- }
-
- ret = glink_qos_latency(ch->handle, ch->ch_cfg.latency_in_us,
- QOS_PKT_SIZE);
- if (ret < 0)
- dev_warn(wpriv->dev, "%s: Failed to request qos %d for ch %s\n",
- __func__, ch->ch_cfg.latency_in_us,
- ch->ch_cfg.name);
-
- wake_up(&ch->ch_connect_wait);
- mutex_unlock(&ch->mutex);
- } else if (event == GLINK_LOCAL_DISCONNECTED) {
- /*
- * Don't use dev_dbg here as dev may not be valid if channel
- * closed from driver close.
- */
- pr_debug("%s: channel: %s disconnected locally\n",
- __func__, ch->ch_cfg.name);
- mutex_unlock(&ch->mutex);
-
- if (ch->free_mem) {
- kfree(ch);
- ch = NULL;
- }
- } else if (event == GLINK_REMOTE_DISCONNECTED) {
- dev_dbg(wpriv->dev, "%s: remote channel: %s disconnected remotely\n",
- __func__, ch->ch_cfg.name);
- mutex_unlock(&ch->mutex);
- /*
- * If remote disconnect happens, local side also has
- * to close the channel as per glink design in a
- * separate work_queue.
- */
- queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk);
- }
-}
-
-/*
- * wdsp_glink_close_ch - Internal function to close glink channel
- * ch: Glink Channel structure.
- */
-static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch)
-{
- struct wdsp_glink_priv *wpriv = ch->wpriv;
- int ret = 0;
-
- mutex_lock(&wpriv->glink_mutex);
- if (ch->handle) {
- ret = glink_close(ch->handle);
- if (ret < 0) {
- dev_err(wpriv->dev, "%s: glink_close is failed, ret = %d\n",
- __func__, ret);
- } else {
- ch->handle = NULL;
- dev_dbg(wpriv->dev, "%s: ch %s is closed\n", __func__,
- ch->ch_cfg.name);
- }
- } else {
- dev_dbg(wpriv->dev, "%s: ch %s is already closed\n", __func__,
- ch->ch_cfg.name);
- }
- mutex_unlock(&wpriv->glink_mutex);
-
-
- return ret;
-}
-
-/*
- * wdsp_glink_open_ch - Internal function to open glink channel
- * ch: Glink Channel structure.
- */
-static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch)
-{
- struct wdsp_glink_priv *wpriv = ch->wpriv;
- struct glink_open_config open_cfg;
- int ret = 0;
-
- mutex_lock(&wpriv->glink_mutex);
- if (!ch->handle) {
- memset(&open_cfg, 0, sizeof(open_cfg));
- open_cfg.options = GLINK_OPT_INITIAL_XPORT;
- open_cfg.edge = WDSP_EDGE;
- open_cfg.notify_rx = wdsp_glink_notify_rx;
- open_cfg.notify_tx_done = wdsp_glink_notify_tx_done;
- open_cfg.notify_tx_abort = wdsp_glink_notify_tx_abort;
- open_cfg.notify_state = wdsp_glink_notify_state;
- open_cfg.notify_rx_intent_req = wdsp_glink_notify_rx_intent_req;
- open_cfg.priv = ch;
- open_cfg.name = ch->ch_cfg.name;
-
- dev_dbg(wpriv->dev, "%s: ch->ch_cfg.name = %s, latency_in_us = %d, intents = %d\n",
- __func__, ch->ch_cfg.name, ch->ch_cfg.latency_in_us,
- ch->ch_cfg.no_of_intents);
-
- ch->handle = glink_open(&open_cfg);
- if (IS_ERR_OR_NULL(ch->handle)) {
- dev_err(wpriv->dev, "%s: glink_open failed for ch %s\n",
- __func__, ch->ch_cfg.name);
- ch->handle = NULL;
- ret = -EINVAL;
- }
- } else {
- dev_err(wpriv->dev, "%s: ch %s is already opened\n", __func__,
- ch->ch_cfg.name);
- }
- mutex_unlock(&wpriv->glink_mutex);
-
- return ret;
-}
-
-/*
- * wdsp_glink_close_all_ch - Internal function to close all glink channels
- * wpriv: Wdsp_glink private structure
- */
-static void wdsp_glink_close_all_ch(struct wdsp_glink_priv *wpriv)
+static struct wdsp_ch *wdsp_get_ch(char *ch_name)
{
int i;
- for (i = 0; i < wpriv->no_of_channels; i++)
- if (wpriv->ch && wpriv->ch[i])
- wdsp_glink_close_ch(wpriv->ch[i]);
-}
-
-/*
- * wdsp_glink_open_all_ch - Internal function to open all glink channels
- * wpriv: Wdsp_glink private structure
- */
-static int wdsp_glink_open_all_ch(struct wdsp_glink_priv *wpriv)
-{
- int ret = 0, i, j;
-
for (i = 0; i < wpriv->no_of_channels; i++) {
- if (wpriv->ch && wpriv->ch[i]) {
- ret = wdsp_glink_open_ch(wpriv->ch[i]);
- if (ret < 0)
- goto err_open;
- }
+ if (!strcmp(ch_name, wpriv->ch[i]->ch_name))
+ return wpriv->ch[i];
}
- goto done;
-
-err_open:
- for (j = 0; j < i; j++)
- if (wpriv->ch[i])
- wdsp_glink_close_ch(wpriv->ch[j]);
-
-done:
- return ret;
+ return NULL;
}
/*
- * wdsp_glink_ch_open_wq - Work function to open glink channels
- * work: Work structure
+ * wdsp_rpmsg_callback - Rpmsg callback for responses
+ * rpdev: Rpmsg device structure
+ * data: Pointer to the Rx data
+ * len: Size of the Rx data
+ * priv: Private pointer to the channel
+ * addr: Address variable
+ * Returns 0 on success and an appropriate error value on failure
*/
-static void wdsp_glink_ch_open_cls_wrk(struct work_struct *work)
+static int wdsp_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr__unused)
{
+ struct wdsp_ch *ch = dev_get_drvdata(&rpdev->dev);
struct wdsp_glink_priv *wpriv;
+ unsigned long flags;
+ u8 *rx_buf;
+ u8 rsp_cnt = 0;
- wpriv = container_of(work, struct wdsp_glink_priv,
- ch_open_cls_wrk);
-
- if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
- dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_DOWN\n",
- __func__);
-
- wdsp_glink_close_all_ch(wpriv);
- } else if (wpriv->glink_state.link_state == GLINK_LINK_STATE_UP) {
- dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_UP\n",
- __func__);
-
- wdsp_glink_open_all_ch(wpriv);
+ if (!ch || !data) {
+ pr_err("%s: Invalid ch or data\n", __func__);
+ return -EINVAL;
}
+
+ wpriv = ch->wpriv;
+ rx_buf = (u8 *)data;
+ if (len > WDSP_MAX_READ_SIZE) {
+ dev_info_ratelimited(wpriv->dev, "%s: Size %d is greater than allowed %d\n",
+ __func__, len, WDSP_MAX_READ_SIZE);
+ len = WDSP_MAX_READ_SIZE;
+ }
+ dev_dbg_ratelimited(wpriv->dev, "%s: copy into buffer %d\n", __func__,
+ wpriv->rsp_cnt);
+
+ if (wpriv->rsp_cnt >= RESP_QUEUE_SIZE) {
+ dev_info_ratelimited(wpriv->dev, "%s: Resp Queue is Full\n",
+ __func__);
+ rsp_cnt = 0;
+ }
+ spin_lock_irqsave(&wpriv->rsp_lock, flags);
+ rsp_cnt = wpriv->rsp_cnt;
+ memcpy(wpriv->rsp[rsp_cnt].buf, rx_buf, len);
+ wpriv->rsp[rsp_cnt].buf_size = len;
+ wpriv->rsp_cnt = ++rsp_cnt;
+ spin_unlock_irqrestore(&wpriv->rsp_lock, flags);
+
+ complete(&wpriv->rsp_complete);
+
+ return 0;
}
/*
- * wdsp_glink_link_state_cb - Glink link state callback to inform
- * about link states
- * cb_info: Glink link state callback information structure
- * priv: Private structure of link state passed while register
+ * wdsp_rpmsg_probe - Rpmsg channel probe function
+ * rpdev: Rpmsg device structure
+ * Returns 0 on success and an appropriate error value on failure
*/
-static void wdsp_glink_link_state_cb(struct glink_link_state_cb_info *cb_info,
- void *priv)
+static int wdsp_rpmsg_probe(struct rpmsg_device *rpdev)
{
- struct wdsp_glink_priv *wpriv;
+ struct wdsp_ch *ch;
- if (!cb_info || !priv) {
- pr_err("%s: Invalid parameters\n", __func__);
+ ch = wdsp_get_ch(rpdev->id.name);
+ if (!ch) {
+ dev_err(&rpdev->dev, "%s, Invalid Channel [%s]\n",
+ __func__, rpdev->id.name);
+ return -EINVAL;
+ }
+
+ dev_dbg(&rpdev->dev, "%s: Channel[%s] state[Up]\n",
+ __func__, rpdev->id.name);
+
+ spin_lock(&ch->ch_lock);
+ ch->handle = rpdev;
+ ch->ch_state = WDSP_CH_CONNECTED;
+ spin_unlock(&ch->ch_lock);
+ dev_set_drvdata(&rpdev->dev, ch);
+ wake_up(&wpriv->ch_state_wait);
+
+ return 0;
+}
+
+/*
+ * wdsp_rpmsg_remove - Rpmsg channel remove function
+ * rpdev: Rpmsg device structure
+ */
+static void wdsp_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct wdsp_ch *ch = dev_get_drvdata(&rpdev->dev);
+
+ if (!ch) {
+ dev_err(&rpdev->dev, "%s: Invalid ch\n", __func__);
return;
}
- wpriv = (struct wdsp_glink_priv *)priv;
-
- mutex_lock(&wpriv->glink_mutex);
- wpriv->glink_state.link_state = cb_info->link_state;
- wake_up(&wpriv->link_state_wait);
- mutex_unlock(&wpriv->glink_mutex);
-
- queue_work(wpriv->work_queue, &wpriv->ch_open_cls_wrk);
+ dev_dbg(&rpdev->dev, "%s: Channel[%s] state[Down]\n",
+ __func__, rpdev->id.name);
+ spin_lock(&ch->ch_lock);
+ ch->handle = NULL;
+ ch->ch_state = WDSP_CH_DISCONNECTED;
+ spin_unlock(&ch->ch_lock);
+ dev_set_drvdata(&rpdev->dev, NULL);
}
-/*
- * wdsp_glink_ch_info_init- Internal function to allocate channel memory
- * and register with glink
- * wpriv: Wdsp_glink private structure.
- * pkt: Glink registration packet contains glink channel information.
- * pkt_size: Size of the pkt.
- */
-static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
- struct wdsp_reg_pkt *pkt, size_t pkt_size)
+static bool wdsp_is_ch_connected(struct wdsp_glink_priv *wpriv)
{
- int ret = 0, i, j;
- struct glink_link_info link_info;
- struct wdsp_glink_ch_cfg *ch_cfg;
- struct wdsp_glink_ch **ch;
- u8 no_of_channels;
- u8 *payload;
- u32 ch_size, ch_cfg_size;
- size_t size = WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE;
+ int i;
- mutex_lock(&wpriv->glink_mutex);
- if (wpriv->ch) {
- dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n",
- __func__);
- ret = -EINVAL;
- goto done;
- }
- payload = (u8 *)pkt->payload;
- no_of_channels = pkt->no_of_channels;
-
- if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
- dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
- __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
- ret = -EINVAL;
- goto done;
- }
- ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
- GFP_ATOMIC);
- if (!ch) {
- ret = -ENOMEM;
- goto done;
- }
- wpriv->ch = ch;
- wpriv->no_of_channels = no_of_channels;
-
- for (i = 0; i < no_of_channels; i++) {
- ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
-
- size += WDSP_CH_CFG_SIZE;
- if (size > pkt_size) {
- dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
- __func__, size, pkt_size);
- ret = -EINVAL;
- goto err_ch_mem;
+ for (i = 0; i < wpriv->no_of_channels; i++) {
+ spin_lock(&wpriv->ch[i]->ch_lock);
+ if (wpriv->ch[i]->ch_state != WDSP_CH_CONNECTED) {
+ spin_unlock(&wpriv->ch[i]->ch_lock);
+ return false;
}
- if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
- dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
- __func__, ch_cfg->no_of_intents);
- ret = -EINVAL;
- goto err_ch_mem;
- }
- size += (sizeof(u32) * ch_cfg->no_of_intents);
- if (size > pkt_size) {
- dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
- __func__, size, pkt_size);
- ret = -EINVAL;
- goto err_ch_mem;
- }
-
- ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
- (sizeof(u32) * ch_cfg->no_of_intents);
- ch_size = sizeof(struct wdsp_glink_ch) +
- (sizeof(u32) * ch_cfg->no_of_intents);
-
- dev_dbg(wpriv->dev, "%s: channels: %d ch_cfg_size: %d, size: %zd, pkt_size: %zd",
- __func__, no_of_channels, ch_cfg_size, size, pkt_size);
-
- ch[i] = kzalloc(ch_size, GFP_KERNEL);
- if (!ch[i]) {
- ret = -ENOMEM;
- goto err_ch_mem;
- }
- ch[i]->channel_state = GLINK_LOCAL_DISCONNECTED;
- memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size);
- payload += ch_cfg_size;
-
- /* check ch name is valid string or not */
- for (j = 0; j < WDSP_CH_NAME_MAX_LEN; j++) {
- if (ch[i]->ch_cfg.name[j] == '\0')
- break;
- }
-
- if (j == WDSP_CH_NAME_MAX_LEN) {
- dev_err_ratelimited(wpriv->dev, "%s: Wrong channel name\n",
- __func__);
- kfree(ch[i]);
- ch[i] = NULL;
- ret = -EINVAL;
- goto err_ch_mem;
- }
-
- mutex_init(&ch[i]->mutex);
- ch[i]->wpriv = wpriv;
- INIT_WORK(&ch[i]->lcl_ch_open_wrk, wdsp_glink_lcl_ch_open_wrk);
- INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk);
- init_waitqueue_head(&ch[i]->ch_connect_wait);
+ spin_unlock(&wpriv->ch[i]->ch_lock);
}
+ return true;
+}
- INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk);
+static int wdsp_wait_for_all_ch_connect(struct wdsp_glink_priv *wpriv)
+{
+ int ret;
- /* Register glink link_state notification */
- link_info.glink_link_state_notif_cb = wdsp_glink_link_state_cb;
- link_info.transport = NULL;
- link_info.edge = WDSP_EDGE;
-
- wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
- wpriv->glink_state.handle = glink_register_link_state_cb(&link_info,
- wpriv);
- if (!wpriv->glink_state.handle) {
- dev_err(wpriv->dev, "%s: Unable to register wdsp link state\n",
- __func__);
- ret = -EINVAL;
- goto err_ch_mem;
+ ret = wait_event_timeout(wpriv->ch_state_wait,
+ wdsp_is_ch_connected(wpriv),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ dev_err_ratelimited(wpriv->dev, "%s: All channels are not connected\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ goto err;
}
- goto done;
+ ret = 0;
-err_ch_mem:
- for (j = 0; j < i; j++) {
- mutex_destroy(&ch[j]->mutex);
- kfree(wpriv->ch[j]);
- wpriv->ch[j] = NULL;
- }
- kfree(wpriv->ch);
- wpriv->ch = NULL;
- wpriv->no_of_channels = 0;
-
-done:
- mutex_unlock(&wpriv->glink_mutex);
+err:
return ret;
}
/*
- * wdsp_glink_tx_buf_work - Work queue function to send tx buffer to glink
+ * wdsp_tx_buf_work - Work queue function to send tx buffer to glink
* work: Work structure
*/
-static void wdsp_glink_tx_buf_work(struct work_struct *work)
+static void wdsp_tx_buf_work(struct work_struct *work)
{
struct wdsp_glink_priv *wpriv;
- struct wdsp_glink_ch *ch;
- struct wdsp_glink_tx_buf *tx_buf;
+ struct wdsp_ch *ch;
+ struct wdsp_tx_buf *tx_buf;
struct wdsp_write_pkt *wpkt;
struct wdsp_cmd_pkt *cpkt;
int ret = 0;
+ struct rpmsg_device *rpdev = NULL;
- tx_buf = container_of(work, struct wdsp_glink_tx_buf,
+ tx_buf = container_of(work, struct wdsp_tx_buf,
tx_work);
ch = tx_buf->ch;
wpriv = ch->wpriv;
wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
+
dev_dbg(wpriv->dev, "%s: ch name = %s, payload size = %d\n",
__func__, cpkt->ch_name, cpkt->payload_size);
- mutex_lock(&tx_buf->ch->mutex);
- if (ch->channel_state == GLINK_CONNECTED) {
- mutex_unlock(&tx_buf->ch->mutex);
- ret = glink_tx(ch->handle, tx_buf,
- cpkt->payload, cpkt->payload_size,
- GLINK_TX_REQ_INTENT);
- if (ret < 0) {
- dev_err(wpriv->dev, "%s: glink tx failed, ret = %d\n",
+ spin_lock(&ch->ch_lock);
+ rpdev = ch->handle;
+ if (rpdev || ch->ch_state == WDSP_CH_CONNECTED) {
+ spin_unlock(&ch->ch_lock);
+ ret = rpmsg_send(rpdev->ept, cpkt->payload,
+ cpkt->payload_size);
+ if (ret < 0)
+ dev_err(wpriv->dev, "%s: rpmsg send failed, ret = %d\n",
__func__, ret);
- /*
- * If glink_tx() is failed then free tx_buf here as
- * there won't be any tx_done notification to
- * free the buffer.
- */
- vfree(tx_buf);
- }
} else {
- mutex_unlock(&tx_buf->ch->mutex);
+ spin_unlock(&ch->ch_lock);
dev_err(wpriv->dev, "%s: channel %s is not in connected state\n",
- __func__, ch->ch_cfg.name);
- /*
- * Free tx_buf here as there won't be any tx_done
- * notification in this case also.
- */
- vfree(tx_buf);
+ __func__, ch->ch_name);
}
+ vfree(tx_buf);
}
/*
@@ -745,19 +287,20 @@
* buf: Pointer to the userspace buffer
* count: Number bytes to read from the file
* ppos: Pointer to the position into the file
+ * Returns 0 on success and an appropriate error value on failure
*/
static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int ret = 0, ret1 = 0;
- struct wdsp_glink_rsp_que *rsp;
+ struct wdsp_rsp_que *read_rsp = NULL;
struct wdsp_glink_priv *wpriv;
+ unsigned long flags;
wpriv = (struct wdsp_glink_priv *)file->private_data;
if (!wpriv) {
pr_err("%s: Invalid private data\n", __func__);
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
if (count > WDSP_MAX_READ_SIZE) {
@@ -766,35 +309,42 @@
count = WDSP_MAX_READ_SIZE;
}
/*
- * Complete signal has given from glink rx notification callback
+ * Complete signal has given from gwdsp_rpmsg_callback()
* or from flush API. Also use interruptible wait_for_completion API
* to allow the system to go in suspend.
*/
ret = wait_for_completion_interruptible(&wpriv->rsp_complete);
- if (ret)
- goto done;
+ if (ret < 0)
+ return ret;
- mutex_lock(&wpriv->rsp_mutex);
+ read_rsp = kzalloc(sizeof(struct wdsp_rsp_que), GFP_KERNEL);
+ if (!read_rsp)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&wpriv->rsp_lock, flags);
if (wpriv->rsp_cnt) {
wpriv->rsp_cnt--;
dev_dbg(wpriv->dev, "%s: read from buffer %d\n",
__func__, wpriv->rsp_cnt);
- rsp = &wpriv->rsp[wpriv->rsp_cnt];
- if (count < rsp->buf_size) {
- ret1 = copy_to_user(buf, &rsp->buf, count);
+ memcpy(read_rsp, &wpriv->rsp[wpriv->rsp_cnt],
+ sizeof(struct wdsp_rsp_que));
+ spin_unlock_irqrestore(&wpriv->rsp_lock, flags);
+
+ if (count < read_rsp->buf_size) {
+ ret1 = copy_to_user(buf, read_rsp->buf, count);
/* Return the number of bytes copied */
ret = count;
} else {
- ret1 = copy_to_user(buf, &rsp->buf, rsp->buf_size);
+ ret1 = copy_to_user(buf, read_rsp->buf,
+ read_rsp->buf_size);
/* Return the number of bytes copied */
- ret = rsp->buf_size;
+ ret = read_rsp->buf_size;
}
if (ret1) {
- mutex_unlock(&wpriv->rsp_mutex);
dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n",
- __func__, ret);
+ __func__, ret);
ret = -EFAULT;
goto done;
}
@@ -805,11 +355,12 @@
*/
dev_dbg(wpriv->dev, "%s: resp count = %d\n", __func__,
wpriv->rsp_cnt);
+ spin_unlock_irqrestore(&wpriv->rsp_lock, flags);
ret = -EINVAL;
}
- mutex_unlock(&wpriv->rsp_mutex);
done:
+ kfree(read_rsp);
return ret;
}
@@ -819,6 +370,7 @@
* buf: Pointer to the userspace buffer
* count: Number bytes to read from the file
* ppos: Pointer to the position into the file
+ * Returns 0 on success and an appropriate error value on failure
*/
static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
@@ -826,7 +378,7 @@
int ret = 0, i, tx_buf_size;
struct wdsp_write_pkt *wpkt;
struct wdsp_cmd_pkt *cpkt;
- struct wdsp_glink_tx_buf *tx_buf;
+ struct wdsp_tx_buf *tx_buf;
struct wdsp_glink_priv *wpriv;
size_t pkt_max_size;
@@ -847,7 +399,7 @@
dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
- tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
+ tx_buf_size = count + sizeof(struct wdsp_tx_buf);
tx_buf = vzalloc(tx_buf_size);
if (!tx_buf) {
ret = -ENOMEM;
@@ -865,33 +417,14 @@
wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
switch (wpkt->pkt_type) {
case WDSP_REG_PKT:
- if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
- WDSP_CH_CFG_SIZE)) {
- dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
- __func__, count);
- ret = -EINVAL;
- goto free_buf;
- }
- ret = wdsp_glink_ch_info_init(wpriv,
- (struct wdsp_reg_pkt *)wpkt->payload,
- count);
- if (ret < 0)
- dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n",
- __func__, ret);
+ /* Keep this case to support backward compatibility */
vfree(tx_buf);
break;
case WDSP_READY_PKT:
- ret = wait_event_timeout(wpriv->link_state_wait,
- (wpriv->glink_state.link_state ==
- GLINK_LINK_STATE_UP),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n",
- __func__);
- ret = -ETIMEDOUT;
- goto free_buf;
- }
- ret = 0;
+ ret = wdsp_wait_for_all_ch_connect(wpriv);
+ if (ret < 0)
+ dev_err_ratelimited(wpriv->dev, "%s: Channels not in connected state\n",
+ __func__);
vfree(tx_buf);
break;
case WDSP_CMD_PKT:
@@ -901,16 +434,6 @@
ret = -EINVAL;
goto free_buf;
}
- mutex_lock(&wpriv->glink_mutex);
- if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
- mutex_unlock(&wpriv->glink_mutex);
- dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n",
- __func__);
-
- ret = -ENETRESET;
- goto free_buf;
- }
- mutex_unlock(&wpriv->glink_mutex);
cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
pkt_max_size = sizeof(struct wdsp_write_pkt) +
sizeof(struct wdsp_cmd_pkt) +
@@ -922,15 +445,13 @@
goto free_buf;
}
for (i = 0; i < wpriv->no_of_channels; i++) {
- if (wpriv->ch && wpriv->ch[i] &&
- (!strcmp(cpkt->ch_name,
- wpriv->ch[i]->ch_cfg.name))) {
+ if (!strcmp(cpkt->ch_name, wpriv->ch[i]->ch_name)) {
tx_buf->ch = wpriv->ch[i];
break;
}
}
if (!tx_buf->ch) {
- dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Failed to get channel\n",
__func__);
ret = -EINVAL;
goto free_buf;
@@ -938,20 +459,17 @@
dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n",
__func__, cpkt->ch_name, pkt_max_size);
- ret = wait_event_timeout(tx_buf->ch->ch_connect_wait,
- (tx_buf->ch->channel_state ==
- GLINK_CONNECTED),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
- __func__, tx_buf->ch->ch_cfg.name,
- tx_buf->ch->channel_state);
- ret = -ETIMEDOUT;
+ spin_lock(&tx_buf->ch->ch_lock);
+ if (tx_buf->ch->ch_state != WDSP_CH_CONNECTED) {
+ spin_unlock(&tx_buf->ch->ch_lock);
+ ret = -ENETRESET;
+ dev_err_ratelimited(wpriv->dev, "%s: Channels are not in connected state\n",
+ __func__);
goto free_buf;
}
- ret = 0;
+ spin_unlock(&tx_buf->ch->ch_lock);
- INIT_WORK(&tx_buf->tx_work, wdsp_glink_tx_buf_work);
+ INIT_WORK(&tx_buf->tx_work, wdsp_tx_buf_work);
queue_work(wpriv->work_queue, &tx_buf->tx_work);
break;
default:
@@ -974,54 +492,22 @@
* wdsp_glink_open - Open API to initialize private data
* inode: Pointer to the inode structure
* file: Pointer to the file structure
+ * Returns 0 on success and an appropriate error value on failure
*/
static int wdsp_glink_open(struct inode *inode, struct file *file)
{
- int ret = 0;
- struct wdsp_glink_priv *wpriv;
- struct wdsp_glink_dev *wdev;
- if (!inode->i_cdev) {
- pr_err("%s: cdev is NULL\n", __func__);
- ret = -EINVAL;
- goto done;
- }
- wdev = container_of(inode->i_cdev, struct wdsp_glink_dev, cdev);
-
- wpriv = kzalloc(sizeof(struct wdsp_glink_priv), GFP_KERNEL);
- if (!wpriv) {
- ret = -ENOMEM;
- goto done;
- }
- wpriv->dev = wdev->dev;
- wpriv->work_queue = create_singlethread_workqueue("wdsp_glink_wq");
- if (!wpriv->work_queue) {
- dev_err(wpriv->dev, "%s: Error creating wdsp_glink_wq\n",
- __func__);
- ret = -EINVAL;
- goto err_wq;
- }
-
- wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
- init_completion(&wpriv->rsp_complete);
- init_waitqueue_head(&wpriv->link_state_wait);
- mutex_init(&wpriv->rsp_mutex);
- mutex_init(&wpriv->glink_mutex);
+ pr_debug("%s: wpriv = %pK\n", __func__, wpriv);
file->private_data = wpriv;
- goto done;
-
-err_wq:
- kfree(wpriv);
-
-done:
- return ret;
+ return 0;
}
/*
* wdsp_glink_flush - Flush API to unblock read.
* file: Pointer to the file structure
* id: Lock owner ID
+ * Returns 0 on success and an appropriate error value on failure
*/
static int wdsp_glink_flush(struct file *file, fl_owner_t id)
{
@@ -1047,56 +533,115 @@
*
* inode: Pointer to the inode structure
* file: Pointer to the file structure
+ * Returns 0 on success and an appropriate error value on failure
*/
static int wdsp_glink_release(struct inode *inode, struct file *file)
{
- int i, ret = 0;
- struct wdsp_glink_priv *wpriv;
-
- wpriv = (struct wdsp_glink_priv *)file->private_data;
- if (!wpriv) {
- pr_err("%s: Invalid private data\n", __func__);
- ret = -EINVAL;
- goto done;
- }
-
- if (wpriv->glink_state.handle)
- glink_unregister_link_state_cb(wpriv->glink_state.handle);
-
- flush_workqueue(wpriv->work_queue);
- destroy_workqueue(wpriv->work_queue);
-
- /*
- * Clean up glink channel memory in channel state
- * callback only if close channels are called from here.
- */
- if (wpriv->ch) {
- for (i = 0; i < wpriv->no_of_channels; i++) {
- if (wpriv->ch[i]) {
- wpriv->ch[i]->free_mem = true;
- /*
- * Channel handle NULL means channel is already
- * closed. Free the channel memory here itself.
- */
- if (!wpriv->ch[i]->handle) {
- kfree(wpriv->ch[i]);
- wpriv->ch[i] = NULL;
- } else {
- wdsp_glink_close_ch(wpriv->ch[i]);
- }
- }
- }
-
- kfree(wpriv->ch);
- wpriv->ch = NULL;
- }
-
- mutex_destroy(&wpriv->glink_mutex);
- mutex_destroy(&wpriv->rsp_mutex);
- kfree(wpriv);
+ pr_debug("%s: file->private_data = %pK\n", __func__,
+ file->private_data);
file->private_data = NULL;
-done:
+ return 0;
+}
+
+static struct rpmsg_driver wdsp_rpmsg_driver = {
+ .probe = wdsp_rpmsg_probe,
+ .remove = wdsp_rpmsg_remove,
+ .callback = wdsp_rpmsg_callback,
+ /* Update this dynamically before register_rpmsg() */
+ .id_table = NULL,
+ .drv = {
+ .name = "wdsp_rpmsg",
+ },
+};
+
+static int wdsp_register_rpmsg(struct platform_device *pdev,
+ struct wdsp_glink_dev *wdev)
+{
+ int ret = 0;
+ int i, no_of_channels;
+ struct rpmsg_device_id *wdsp_rpmsg_id_table, *id_table;
+ const char *ch_name = NULL;
+
+ wpriv = devm_kzalloc(&pdev->dev,
+ sizeof(struct wdsp_glink_priv), GFP_KERNEL);
+ if (!wpriv)
+ return -ENOMEM;
+
+ no_of_channels = of_property_count_strings(pdev->dev.of_node,
+ "qcom,wdsp_channles");
+ if (no_of_channels < 0) {
+ dev_err(&pdev->dev, "%s: channel name parse error %d\n",
+ __func__, no_of_channels);
+ return -EINVAL;
+ }
+
+ wpriv->ch = devm_kzalloc(&pdev->dev,
+ (sizeof(struct wdsp_glink_priv *) * no_of_channels),
+ GFP_KERNEL);
+ if (!wpriv->ch)
+ return -ENOMEM;
+
+ for (i = 0; i < no_of_channels; i++) {
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,wdsp-channels", i,
+ &ch_name);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: channel name parse error %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+ wpriv->ch[i] = devm_kzalloc(&pdev->dev,
+ sizeof(struct wdsp_glink_priv),
+ GFP_KERNEL);
+ if (!wpriv->ch[i])
+ return -ENOMEM;
+
+ strlcpy(wpriv->ch[i]->ch_name, ch_name, RPMSG_NAME_SIZE);
+ wpriv->ch[i]->wpriv = wpriv;
+ spin_lock_init(&wpriv->ch[i]->ch_lock);
+ }
+ init_waitqueue_head(&wpriv->ch_state_wait);
+ init_completion(&wpriv->rsp_complete);
+ spin_lock_init(&wpriv->rsp_lock);
+
+ wpriv->wdev = wdev;
+ wpriv->dev = wdev->dev;
+ wpriv->work_queue = create_singlethread_workqueue("wdsp_glink_wq");
+ if (!wpriv->work_queue) {
+ dev_err(&pdev->dev, "%s: Error creating wdsp_glink_wq\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ wdsp_rpmsg_id_table = devm_kzalloc(&pdev->dev,
+ (sizeof(struct rpmsg_device_id) *
+ (no_of_channels + 1)),
+ GFP_KERNEL);
+ if (!wdsp_rpmsg_id_table) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ wpriv->no_of_channels = no_of_channels;
+ id_table = wdsp_rpmsg_id_table;
+ for (i = 0; i < no_of_channels; i++) {
+ strlcpy(id_table->name, wpriv->ch[i]->ch_name,
+ RPMSG_NAME_SIZE);
+ id_table++;
+ }
+ wdsp_rpmsg_driver.id_table = wdsp_rpmsg_id_table;
+ ret = register_rpmsg_driver(&wdsp_rpmsg_driver);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Rpmsg driver register failed, err = %d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ destroy_workqueue(wpriv->work_queue);
return ret;
}
@@ -1109,10 +654,6 @@
.release = wdsp_glink_release,
};
-/*
- * wdsp_glink_probe - Driver probe to expose char device
- * pdev: Pointer to device tree data.
- */
static int wdsp_glink_probe(struct platform_device *pdev)
{
int ret;
@@ -1156,7 +697,15 @@
__func__, ret);
goto err_cdev_add;
}
- platform_set_drvdata(pdev, wdev);
+
+ ret = wdsp_register_rpmsg(pdev, wdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Failed to register with rpmsg, err = %d\n",
+ __func__, ret);
+ goto err_cdev_add;
+ }
+ platform_set_drvdata(pdev, wpriv);
+
goto done;
err_cdev_add:
@@ -1169,28 +718,25 @@
unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
err_chrdev:
- devm_kfree(&pdev->dev, wdev);
-
done:
return ret;
}
-/*
- * wdsp_glink_remove - Driver remove to handle cleanup
- * pdev: Pointer to device tree data.
- */
static int wdsp_glink_remove(struct platform_device *pdev)
{
- struct wdsp_glink_dev *wdev = platform_get_drvdata(pdev);
+ struct wdsp_glink_priv *wpriv = platform_get_drvdata(pdev);
- if (wdev) {
- cdev_del(&wdev->cdev);
- device_destroy(wdev->cls, wdev->dev_num);
- class_destroy(wdev->cls);
- unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
- devm_kfree(&pdev->dev, wdev);
- } else {
- dev_err(&pdev->dev, "%s: Invalid device data\n", __func__);
+ unregister_rpmsg_driver(&wdsp_rpmsg_driver);
+
+ if (wpriv) {
+ flush_workqueue(wpriv->work_queue);
+ destroy_workqueue(wpriv->work_queue);
+ if (wpriv->wdev) {
+ cdev_del(&wpriv->wdev->cdev);
+ device_destroy(wpriv->wdev->cls, wpriv->wdev->dev_num);
+ class_destroy(wpriv->wdev->cls);
+ unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
+ }
}
return 0;