Message ID | 1444423685-14717-6-git-send-email-bjorn.andersson@sonymobile.com (mailing list archive) |
---|---|
State | Superseded, archived |
Delegated to: | Andy Gross |
Headers | show |
Hi Bjorn, On 2015/10/10 4:48, Bjorn Andersson wrote: > With the qcom_smd_open_channel() API we allow SMD devices to open > additional SMD channels, to allow implementation of multi-channel SMD > devices - like Bluetooth. > > Channels are opened from the same edge as the calling SMD device is tied > to. > > Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > --- > > Changes since v1: > - New patch > > drivers/soc/qcom/smd.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/soc/qcom/smd.h | 4 +++ > 2 files changed, 79 insertions(+) > > diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c > index 4c55708aac50..3257ba488d3d 100644 > --- a/drivers/soc/qcom/smd.c > +++ b/drivers/soc/qcom/smd.c > @@ -129,6 +129,8 @@ struct qcom_smd_edge { > > unsigned smem_available; > > + wait_queue_head_t new_channel_event; > + > struct work_struct scan_work; > struct work_struct state_work; > }; > @@ -1042,6 +1044,76 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv) > } > EXPORT_SYMBOL(qcom_smd_driver_unregister); > > +static struct qcom_smd_channel * > +qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name) > +{ > + struct qcom_smd_channel *channel; > + struct qcom_smd_channel *ret = NULL; > + unsigned state; > + > + read_lock(&edge->channels_lock); > + list_for_each_entry(channel, &edge->channels, list) { > + if (strcmp(channel->name, name)) > + continue; > + > + state = GET_RX_CHANNEL_INFO(channel, state); > + if (state != SMD_CHANNEL_OPENING && > + state != SMD_CHANNEL_OPENED) > + continue; > + > + ret = channel; > + break; > + } > + read_unlock(&edge->channels_lock); > + > + return ret; > +} > + > +/** > + * qcom_smd_open_channel() - claim additional channels on the same edge > + * @sdev: smd_device handle > + * @name: channel name > + * @cb: callback method to use for incoming data > + * > + * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't > + * ready. > + */ > +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, > + const char *name, > + qcom_smd_cb_t cb) > +{ > + struct qcom_smd_channel *channel; > + struct qcom_smd_edge *edge = sdev->channel->edge; > + int ret; > + > + /* Wait up to HZ for the channel to appear */ > + ret = wait_event_interruptible_timeout(edge->new_channel_event, > + (channel = qcom_smd_find_channel(edge, name)) != NULL, > + HZ); > + if (!ret) > + return ERR_PTR(-ETIMEDOUT); > + > + if (channel->state != SMD_CHANNEL_CLOSED) { > + dev_err(&sdev->dev, "channel %s is busy\n", channel->name); > + return ERR_PTR(-EBUSY); > + } > + > + channel->qsdev = sdev; > + ret = qcom_smd_channel_open(channel, cb); > + if (ret) { > + channel->qsdev = NULL; > + return ERR_PTR(ret); > + } > + > + /* > + * Append the list of channel to the channels associated with the sdev > + */ > + list_add_tail(&channel->dev_list, &sdev->channel->dev_list); > + > + return channel; > +} > +EXPORT_SYMBOL(qcom_smd_open_channel); > + Do we need qcom_smd_close_channel API here? Regards Yin, Fengwei > /* > * Allocate the qcom_smd_channel object for a newly found smd channel, > * retrieving and validating the smem items involved. > @@ -1178,6 +1250,8 @@ static void qcom_channel_scan_worker(struct work_struct *work) > > dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); > set_bit(i, edge->allocated[tbl]); > + > + wake_up_interruptible(&edge->new_channel_event); > } > } > > @@ -1340,6 +1414,7 @@ static int qcom_smd_probe(struct platform_device *pdev) > for_each_available_child_of_node(pdev->dev.of_node, node) { > edge = &smd->edges[i++]; > edge->smd = smd; > + init_waitqueue_head(&edge->new_channel_event); > > ret = qcom_smd_parse_edge(&pdev->dev, node, edge); > if (ret) > diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h > index 65a64fcdb1aa..bd51c8a9d807 100644 > --- a/include/linux/soc/qcom/smd.h > +++ b/include/linux/soc/qcom/smd.h > @@ -56,4 +56,8 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv); > > int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); > > +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, > + const char *name, > + qcom_smd_cb_t cb); > + > #endif > -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed 14 Oct 08:09 PDT 2015, yfw wrote: > Hi Bjorn, > > On 2015/10/10 4:48, Bjorn Andersson wrote: > > With the qcom_smd_open_channel() API we allow SMD devices to open > > additional SMD channels, to allow implementation of multi-channel SMD > > devices - like Bluetooth. > > > > Channels are opened from the same edge as the calling SMD device is tied > > to. > > [..] > > +/** > > + * qcom_smd_open_channel() - claim additional channels on the same edge > > + * @sdev: smd_device handle > > + * @name: channel name > > + * @cb: callback method to use for incoming data > > + * > > + * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't > > + * ready. > > + */ > > +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, > > + const char *name, > > + qcom_smd_cb_t cb) > > +{ > > + struct qcom_smd_channel *channel; > > + struct qcom_smd_edge *edge = sdev->channel->edge; > > + int ret; > > + > > + /* Wait up to HZ for the channel to appear */ > > + ret = wait_event_interruptible_timeout(edge->new_channel_event, > > + (channel = qcom_smd_find_channel(edge, name)) != NULL, > > + HZ); > > + if (!ret) > > + return ERR_PTR(-ETIMEDOUT); > > + > > + if (channel->state != SMD_CHANNEL_CLOSED) { > > + dev_err(&sdev->dev, "channel %s is busy\n", channel->name); > > + return ERR_PTR(-EBUSY); > > + } > > + > > + channel->qsdev = sdev; > > + ret = qcom_smd_channel_open(channel, cb); > > + if (ret) { > > + channel->qsdev = NULL; > > + return ERR_PTR(ret); > > + } > > + > > + /* > > + * Append the list of channel to the channels associated with the sdev > > + */ > > + list_add_tail(&channel->dev_list, &sdev->channel->dev_list); > > + > > + return channel; > > +} > > +EXPORT_SYMBOL(qcom_smd_open_channel); > > + > Do we need qcom_smd_close_channel API here? > On success the channel is associated with the qcom_smd_device, which tears down all associated channels on destruction. I have not yet seen any reason for decoupling the life cycle of a channel further from the device (in most cases it's very must 1:1). But I will update the comment above to clarify this fact, thanks! Regards, Bjorn -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index 4c55708aac50..3257ba488d3d 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -129,6 +129,8 @@ struct qcom_smd_edge { unsigned smem_available; + wait_queue_head_t new_channel_event; + struct work_struct scan_work; struct work_struct state_work; }; @@ -1042,6 +1044,76 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv) } EXPORT_SYMBOL(qcom_smd_driver_unregister); +static struct qcom_smd_channel * +qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name) +{ + struct qcom_smd_channel *channel; + struct qcom_smd_channel *ret = NULL; + unsigned state; + + read_lock(&edge->channels_lock); + list_for_each_entry(channel, &edge->channels, list) { + if (strcmp(channel->name, name)) + continue; + + state = GET_RX_CHANNEL_INFO(channel, state); + if (state != SMD_CHANNEL_OPENING && + state != SMD_CHANNEL_OPENED) + continue; + + ret = channel; + break; + } + read_unlock(&edge->channels_lock); + + return ret; +} + +/** + * qcom_smd_open_channel() - claim additional channels on the same edge + * @sdev: smd_device handle + * @name: channel name + * @cb: callback method to use for incoming data + * + * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't + * ready. + */ +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, + const char *name, + qcom_smd_cb_t cb) +{ + struct qcom_smd_channel *channel; + struct qcom_smd_edge *edge = sdev->channel->edge; + int ret; + + /* Wait up to HZ for the channel to appear */ + ret = wait_event_interruptible_timeout(edge->new_channel_event, + (channel = qcom_smd_find_channel(edge, name)) != NULL, + HZ); + if (!ret) + return ERR_PTR(-ETIMEDOUT); + + if (channel->state != SMD_CHANNEL_CLOSED) { + dev_err(&sdev->dev, "channel %s is busy\n", channel->name); + return ERR_PTR(-EBUSY); + } + + channel->qsdev = sdev; + ret = qcom_smd_channel_open(channel, cb); + if (ret) { + channel->qsdev = NULL; + return ERR_PTR(ret); + } + + /* + * Append the list of channel to the channels associated with the sdev + */ + list_add_tail(&channel->dev_list, &sdev->channel->dev_list); + + return channel; +} +EXPORT_SYMBOL(qcom_smd_open_channel); + /* * Allocate the qcom_smd_channel object for a newly found smd channel, * retrieving and validating the smem items involved. @@ -1178,6 +1250,8 @@ static void qcom_channel_scan_worker(struct work_struct *work) dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); set_bit(i, edge->allocated[tbl]); + + wake_up_interruptible(&edge->new_channel_event); } } @@ -1340,6 +1414,7 @@ static int qcom_smd_probe(struct platform_device *pdev) for_each_available_child_of_node(pdev->dev.of_node, node) { edge = &smd->edges[i++]; edge->smd = smd; + init_waitqueue_head(&edge->new_channel_event); ret = qcom_smd_parse_edge(&pdev->dev, node, edge); if (ret) diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h index 65a64fcdb1aa..bd51c8a9d807 100644 --- a/include/linux/soc/qcom/smd.h +++ b/include/linux/soc/qcom/smd.h @@ -56,4 +56,8 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv); int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, + const char *name, + qcom_smd_cb_t cb); + #endif
With the qcom_smd_open_channel() API we allow SMD devices to open additional SMD channels, to allow implementation of multi-channel SMD devices - like Bluetooth. Channels are opened from the same edge as the calling SMD device is tied to. Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> --- Changes since v1: - New patch drivers/soc/qcom/smd.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/smd.h | 4 +++ 2 files changed, 79 insertions(+)