Lines Matching +full:channel +full:-

1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
27 * The Qualcomm Shared Memory communication solution provides point-to-point
30 * Each channel consists of a control item (channel info) and a ring buffer
31 * pair. The channel info carry information related to channel state, flow
37 * Upon creating a new channel the remote processor allocates channel info and
39 * interrupt is sent to the other end of the channel and a scan for new
40 * channels should be done. A channel never goes away, it will only change
44 * channel by setting the state of its end of the channel to "opening" and
46 * consume the channel. Upon finding a consumer we finish the handshake and the
47 * channel is up.
49 * Upon closing a channel, the remote processor will update the state of its
50 * end of the channel and signal us, we will then unregister any attached
51 * device and close our end of the channel.
53 * Devices attached to a channel can use the qcom_smd_send function to push
54 * data to the channel, this is done by copying the data into the tx ring
55 * buffer, updating the pointers in the channel info and signaling the remote
59 * receiving the interrupt we check the channel info for new data and delivers
76 * smd channel entries.
96 * struct qcom_smd_edge - representing a remote processor
107 * @mbox_chan: apcs ipc mailbox channel handle
111 * @smem_available: last available amount of smem triggering a channel scan
112 * @new_channel_event: wait queue for new channel events
148 * SMD channel states.
177 * struct qcom_smd_channel - smd channel struct
178 * @edge: qcom_smd_edge this channel is living on
180 * @registered: flag to indicate if the channel is registered
181 * @name: name of the channel
182 * @state: local state of the channel
183 * @remote_state: remote state of the channel
185 * @info: byte aligned outgoing/incoming channel info
186 * @info_word: word aligned outgoing/incoming channel info
187 * @tx_lock: lock to make writes to the channel mutually exclusive
193 * @cb: callback function registered for this channel
275 #define GET_RX_CHANNEL_FLAG(channel, param) \ argument
277 BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
278 channel->info_word ? \
279 le32_to_cpu(channel->info_word->rx.param) : \
280 channel->info->rx.param; \
283 #define GET_RX_CHANNEL_INFO(channel, param) \ argument
285 BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
286 le32_to_cpu(channel->info_word ? \
287 channel->info_word->rx.param : \
288 channel->info->rx.param); \
291 #define SET_RX_CHANNEL_FLAG(channel, param, value) \ argument
293 BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
294 if (channel->info_word) \
295 channel->info_word->rx.param = cpu_to_le32(value); \
297 channel->info->rx.param = value; \
300 #define SET_RX_CHANNEL_INFO(channel, param, value) \ argument
302 BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
303 if (channel->info_word) \
304 channel->info_word->rx.param = cpu_to_le32(value); \
306 channel->info->rx.param = cpu_to_le32(value); \
309 #define GET_TX_CHANNEL_FLAG(channel, param) \ argument
311 BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
312 channel->info_word ? \
313 le32_to_cpu(channel->info_word->tx.param) : \
314 channel->info->tx.param; \
317 #define GET_TX_CHANNEL_INFO(channel, param) \ argument
319 BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
320 le32_to_cpu(channel->info_word ? \
321 channel->info_word->tx.param : \
322 channel->info->tx.param); \
325 #define SET_TX_CHANNEL_FLAG(channel, param, value) \ argument
327 BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
328 if (channel->info_word) \
329 channel->info_word->tx.param = cpu_to_le32(value); \
331 channel->info->tx.param = value; \
334 #define SET_TX_CHANNEL_INFO(channel, param, value) \ argument
336 BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
337 if (channel->info_word) \
338 channel->info_word->tx.param = cpu_to_le32(value); \
340 channel->info->tx.param = cpu_to_le32(value); \
344 * struct qcom_smd_alloc_entry - channel allocation entry
345 * @name: channel name
346 * @cid: channel index
347 * @flags: channel flags and edge id
348 * @ref_count: reference count of the channel
368 * Signal the remote processor associated with 'channel'.
370 static void qcom_smd_signal_channel(struct qcom_smd_channel *channel) in qcom_smd_signal_channel() argument
372 struct qcom_smd_edge *edge = channel->edge; in qcom_smd_signal_channel()
374 if (edge->mbox_chan) { in qcom_smd_signal_channel()
380 mbox_send_message(edge->mbox_chan, NULL); in qcom_smd_signal_channel()
381 mbox_client_txdone(edge->mbox_chan, 0); in qcom_smd_signal_channel()
383 regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); in qcom_smd_signal_channel()
388 * Initialize the tx channel info
390 static void qcom_smd_channel_reset(struct qcom_smd_channel *channel) in qcom_smd_channel_reset() argument
392 SET_TX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); in qcom_smd_channel_reset()
393 SET_TX_CHANNEL_FLAG(channel, fDSR, 0); in qcom_smd_channel_reset()
394 SET_TX_CHANNEL_FLAG(channel, fCTS, 0); in qcom_smd_channel_reset()
395 SET_TX_CHANNEL_FLAG(channel, fCD, 0); in qcom_smd_channel_reset()
396 SET_TX_CHANNEL_FLAG(channel, fRI, 0); in qcom_smd_channel_reset()
397 SET_TX_CHANNEL_FLAG(channel, fHEAD, 0); in qcom_smd_channel_reset()
398 SET_TX_CHANNEL_FLAG(channel, fTAIL, 0); in qcom_smd_channel_reset()
399 SET_TX_CHANNEL_FLAG(channel, fSTATE, 1); in qcom_smd_channel_reset()
400 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); in qcom_smd_channel_reset()
401 SET_TX_CHANNEL_INFO(channel, head, 0); in qcom_smd_channel_reset()
402 SET_RX_CHANNEL_INFO(channel, tail, 0); in qcom_smd_channel_reset()
404 qcom_smd_signal_channel(channel); in qcom_smd_channel_reset()
406 channel->state = SMD_CHANNEL_CLOSED; in qcom_smd_channel_reset()
407 channel->pkt_size = 0; in qcom_smd_channel_reset()
411 * Set the callback for a channel, with appropriate locking
413 static void qcom_smd_channel_set_callback(struct qcom_smd_channel *channel, in qcom_smd_channel_set_callback() argument
416 struct rpmsg_endpoint *ept = &channel->qsept->ept; in qcom_smd_channel_set_callback()
419 spin_lock_irqsave(&channel->recv_lock, flags); in qcom_smd_channel_set_callback()
420 ept->cb = cb; in qcom_smd_channel_set_callback()
421 spin_unlock_irqrestore(&channel->recv_lock, flags); in qcom_smd_channel_set_callback()
427 static size_t qcom_smd_channel_get_rx_avail(struct qcom_smd_channel *channel) in qcom_smd_channel_get_rx_avail() argument
432 head = GET_RX_CHANNEL_INFO(channel, head); in qcom_smd_channel_get_rx_avail()
433 tail = GET_RX_CHANNEL_INFO(channel, tail); in qcom_smd_channel_get_rx_avail()
435 return (head - tail) & (channel->fifo_size - 1); in qcom_smd_channel_get_rx_avail()
439 * Set tx channel state and inform the remote processor
441 static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel, in qcom_smd_channel_set_state() argument
444 struct qcom_smd_edge *edge = channel->edge; in qcom_smd_channel_set_state()
447 if (channel->state == state) in qcom_smd_channel_set_state()
450 dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state); in qcom_smd_channel_set_state()
452 SET_TX_CHANNEL_FLAG(channel, fDSR, is_open); in qcom_smd_channel_set_state()
453 SET_TX_CHANNEL_FLAG(channel, fCTS, is_open); in qcom_smd_channel_set_state()
454 SET_TX_CHANNEL_FLAG(channel, fCD, is_open); in qcom_smd_channel_set_state()
456 SET_TX_CHANNEL_INFO(channel, state, state); in qcom_smd_channel_set_state()
457 SET_TX_CHANNEL_FLAG(channel, fSTATE, 1); in qcom_smd_channel_set_state()
459 channel->state = state; in qcom_smd_channel_set_state()
460 qcom_smd_signal_channel(channel); in qcom_smd_channel_set_state()
497 static size_t qcom_smd_channel_peek(struct qcom_smd_channel *channel, in qcom_smd_channel_peek() argument
504 word_aligned = channel->info_word; in qcom_smd_channel_peek()
505 tail = GET_RX_CHANNEL_INFO(channel, tail); in qcom_smd_channel_peek()
507 len = min_t(size_t, count, channel->fifo_size - tail); in qcom_smd_channel_peek()
510 channel->rx_fifo + tail, in qcom_smd_channel_peek()
517 channel->rx_fifo, in qcom_smd_channel_peek()
518 count - len, in qcom_smd_channel_peek()
528 static void qcom_smd_channel_advance(struct qcom_smd_channel *channel, in qcom_smd_channel_advance() argument
533 tail = GET_RX_CHANNEL_INFO(channel, tail); in qcom_smd_channel_advance()
535 tail &= (channel->fifo_size - 1); in qcom_smd_channel_advance()
536 SET_RX_CHANNEL_INFO(channel, tail, tail); in qcom_smd_channel_advance()
542 static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel) in qcom_smd_channel_recv_single() argument
544 struct rpmsg_endpoint *ept = &channel->qsept->ept; in qcom_smd_channel_recv_single()
550 tail = GET_RX_CHANNEL_INFO(channel, tail); in qcom_smd_channel_recv_single()
553 if (tail + channel->pkt_size >= channel->fifo_size) { in qcom_smd_channel_recv_single()
554 ptr = channel->bounce_buffer; in qcom_smd_channel_recv_single()
555 len = qcom_smd_channel_peek(channel, ptr, channel->pkt_size); in qcom_smd_channel_recv_single()
557 ptr = channel->rx_fifo + tail; in qcom_smd_channel_recv_single()
558 len = channel->pkt_size; in qcom_smd_channel_recv_single()
561 ret = ept->cb(ept->rpdev, ptr, len, ept->priv, RPMSG_ADDR_ANY); in qcom_smd_channel_recv_single()
566 qcom_smd_channel_advance(channel, len); in qcom_smd_channel_recv_single()
568 channel->pkt_size = 0; in qcom_smd_channel_recv_single()
574 * Per channel interrupt handling
576 static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel) in qcom_smd_channel_intr() argument
585 remote_state = GET_RX_CHANNEL_INFO(channel, state); in qcom_smd_channel_intr()
586 if (remote_state != channel->remote_state) { in qcom_smd_channel_intr()
587 channel->remote_state = remote_state; in qcom_smd_channel_intr()
590 wake_up_interruptible_all(&channel->state_change_event); in qcom_smd_channel_intr()
593 SET_RX_CHANNEL_FLAG(channel, fSTATE, 0); in qcom_smd_channel_intr()
596 if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) in qcom_smd_channel_intr()
597 wake_up_interruptible_all(&channel->fblockread_event); in qcom_smd_channel_intr()
599 /* Don't consume any data until we've opened the channel */ in qcom_smd_channel_intr()
600 if (channel->state != SMD_CHANNEL_OPENED) in qcom_smd_channel_intr()
604 SET_RX_CHANNEL_FLAG(channel, fHEAD, 0); in qcom_smd_channel_intr()
608 avail = qcom_smd_channel_get_rx_avail(channel); in qcom_smd_channel_intr()
610 if (!channel->pkt_size && avail >= SMD_PACKET_HEADER_LEN) { in qcom_smd_channel_intr()
611 qcom_smd_channel_peek(channel, &pktlen, sizeof(pktlen)); in qcom_smd_channel_intr()
612 qcom_smd_channel_advance(channel, SMD_PACKET_HEADER_LEN); in qcom_smd_channel_intr()
613 channel->pkt_size = le32_to_cpu(pktlen); in qcom_smd_channel_intr()
614 } else if (channel->pkt_size && avail >= channel->pkt_size) { in qcom_smd_channel_intr()
615 ret = qcom_smd_channel_recv_single(channel); in qcom_smd_channel_intr()
624 SET_RX_CHANNEL_FLAG(channel, fTAIL, 1); in qcom_smd_channel_intr()
627 if (!GET_RX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) { in qcom_smd_channel_intr()
628 /* Ensure ordering of channel info updates */ in qcom_smd_channel_intr()
631 qcom_smd_signal_channel(channel); in qcom_smd_channel_intr()
640 * channel info updates or when new channels are created.
645 struct qcom_smd_channel *channel; in qcom_smd_edge_intr() local
653 spin_lock(&edge->channels_lock); in qcom_smd_edge_intr()
654 list_for_each_entry(channel, &edge->channels, list) { in qcom_smd_edge_intr()
655 spin_lock(&channel->recv_lock); in qcom_smd_edge_intr()
656 kick_state |= qcom_smd_channel_intr(channel); in qcom_smd_edge_intr()
657 spin_unlock(&channel->recv_lock); in qcom_smd_edge_intr()
659 spin_unlock(&edge->channels_lock); in qcom_smd_edge_intr()
662 * Creating a new channel requires allocating an smem entry, so we only in qcom_smd_edge_intr()
666 available = qcom_smem_get_free_space(edge->remote_pid); in qcom_smd_edge_intr()
667 if (available != edge->smem_available) { in qcom_smd_edge_intr()
668 edge->smem_available = available; in qcom_smd_edge_intr()
673 schedule_work(&edge->scan_work); in qcom_smd_edge_intr()
675 schedule_work(&edge->state_work); in qcom_smd_edge_intr()
683 static size_t qcom_smd_get_tx_avail(struct qcom_smd_channel *channel) in qcom_smd_get_tx_avail() argument
687 unsigned mask = channel->fifo_size - 1; in qcom_smd_get_tx_avail()
689 head = GET_TX_CHANNEL_INFO(channel, head); in qcom_smd_get_tx_avail()
690 tail = GET_TX_CHANNEL_INFO(channel, tail); in qcom_smd_get_tx_avail()
692 return mask - ((head - tail) & mask); in qcom_smd_get_tx_avail()
696 * Write count bytes of data into channel, possibly wrapping in the ring buffer
698 static int qcom_smd_write_fifo(struct qcom_smd_channel *channel, in qcom_smd_write_fifo() argument
706 word_aligned = channel->info_word; in qcom_smd_write_fifo()
707 head = GET_TX_CHANNEL_INFO(channel, head); in qcom_smd_write_fifo()
709 len = min_t(size_t, count, channel->fifo_size - head); in qcom_smd_write_fifo()
711 smd_copy_to_fifo(channel->tx_fifo + head, in qcom_smd_write_fifo()
718 smd_copy_to_fifo(channel->tx_fifo, in qcom_smd_write_fifo()
720 count - len, in qcom_smd_write_fifo()
725 head &= (channel->fifo_size - 1); in qcom_smd_write_fifo()
726 SET_TX_CHANNEL_INFO(channel, head, head); in qcom_smd_write_fifo()
732 * __qcom_smd_send - write data to smd channel
733 * @channel: channel handle
738 * This is a blocking write of len bytes into the channel's tx ring buffer and
743 static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, in __qcom_smd_send() argument
752 if (channel->info_word && len % 4) in __qcom_smd_send()
753 return -EINVAL; in __qcom_smd_send()
756 if (tlen >= channel->fifo_size) in __qcom_smd_send()
757 return -EINVAL; in __qcom_smd_send()
763 spin_lock_irqsave(&channel->tx_lock, flags); in __qcom_smd_send()
765 while (qcom_smd_get_tx_avail(channel) < tlen && in __qcom_smd_send()
766 channel->state == SMD_CHANNEL_OPENED) { in __qcom_smd_send()
768 ret = -EAGAIN; in __qcom_smd_send()
772 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); in __qcom_smd_send()
775 spin_unlock_irqrestore(&channel->tx_lock, flags); in __qcom_smd_send()
777 ret = wait_event_interruptible(channel->fblockread_event, in __qcom_smd_send()
778 qcom_smd_get_tx_avail(channel) >= tlen || in __qcom_smd_send()
779 channel->state != SMD_CHANNEL_OPENED); in __qcom_smd_send()
783 spin_lock_irqsave(&channel->tx_lock, flags); in __qcom_smd_send()
785 SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); in __qcom_smd_send()
788 /* Fail if the channel was closed */ in __qcom_smd_send()
789 if (channel->state != SMD_CHANNEL_OPENED) { in __qcom_smd_send()
790 ret = -EPIPE; in __qcom_smd_send()
794 SET_TX_CHANNEL_FLAG(channel, fTAIL, 0); in __qcom_smd_send()
796 qcom_smd_write_fifo(channel, hdr, sizeof(hdr)); in __qcom_smd_send()
797 qcom_smd_write_fifo(channel, data, len); in __qcom_smd_send()
799 SET_TX_CHANNEL_FLAG(channel, fHEAD, 1); in __qcom_smd_send()
801 /* Ensure ordering of channel info updates */ in __qcom_smd_send()
804 qcom_smd_signal_channel(channel); in __qcom_smd_send()
807 spin_unlock_irqrestore(&channel->tx_lock, flags); in __qcom_smd_send()
813 * Helper for opening a channel
815 static int qcom_smd_channel_open(struct qcom_smd_channel *channel, in qcom_smd_channel_open() argument
818 struct qcom_smd_edge *edge = channel->edge; in qcom_smd_channel_open()
825 bb_size = min(channel->fifo_size, SZ_4K); in qcom_smd_channel_open()
826 channel->bounce_buffer = kmalloc(bb_size, GFP_KERNEL); in qcom_smd_channel_open()
827 if (!channel->bounce_buffer) in qcom_smd_channel_open()
828 return -ENOMEM; in qcom_smd_channel_open()
830 qcom_smd_channel_set_callback(channel, cb); in qcom_smd_channel_open()
831 qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING); in qcom_smd_channel_open()
834 ret = wait_event_interruptible_timeout(channel->state_change_event, in qcom_smd_channel_open()
835 channel->remote_state == SMD_CHANNEL_OPENING || in qcom_smd_channel_open()
836 channel->remote_state == SMD_CHANNEL_OPENED, in qcom_smd_channel_open()
839 dev_err(&edge->dev, "remote side did not enter opening state\n"); in qcom_smd_channel_open()
843 qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED); in qcom_smd_channel_open()
846 ret = wait_event_interruptible_timeout(channel->state_change_event, in qcom_smd_channel_open()
847 channel->remote_state == SMD_CHANNEL_OPENED, in qcom_smd_channel_open()
850 dev_err(&edge->dev, "remote side did not enter open state\n"); in qcom_smd_channel_open()
857 qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); in qcom_smd_channel_open()
858 return -ETIMEDOUT; in qcom_smd_channel_open()
862 * Helper for closing and resetting a channel
864 static void qcom_smd_channel_close(struct qcom_smd_channel *channel) in qcom_smd_channel_close() argument
866 qcom_smd_channel_set_callback(channel, NULL); in qcom_smd_channel_close()
868 kfree(channel->bounce_buffer); in qcom_smd_channel_close()
869 channel->bounce_buffer = NULL; in qcom_smd_channel_close()
871 qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); in qcom_smd_channel_close()
872 qcom_smd_channel_reset(channel); in qcom_smd_channel_close()
878 struct qcom_smd_channel *channel; in qcom_smd_find_channel() local
882 spin_lock_irqsave(&edge->channels_lock, flags); in qcom_smd_find_channel()
883 list_for_each_entry(channel, &edge->channels, list) { in qcom_smd_find_channel()
884 if (!strcmp(channel->name, name)) { in qcom_smd_find_channel()
885 ret = channel; in qcom_smd_find_channel()
889 spin_unlock_irqrestore(&edge->channels_lock, flags); in qcom_smd_find_channel()
906 struct qcom_smd_channel *channel; in qcom_smd_create_ept() local
908 struct qcom_smd_edge *edge = qsdev->edge; in qcom_smd_create_ept()
913 /* Wait up to HZ for the channel to appear */ in qcom_smd_create_ept()
914 ret = wait_event_interruptible_timeout(edge->new_channel_event, in qcom_smd_create_ept()
915 (channel = qcom_smd_find_channel(edge, name)) != NULL, in qcom_smd_create_ept()
920 if (channel->state != SMD_CHANNEL_CLOSED) { in qcom_smd_create_ept()
921 dev_err(&rpdev->dev, "channel %s is busy\n", channel->name); in qcom_smd_create_ept()
929 ept = &qsept->ept; in qcom_smd_create_ept()
931 kref_init(&ept->refcount); in qcom_smd_create_ept()
933 ept->rpdev = rpdev; in qcom_smd_create_ept()
934 ept->cb = cb; in qcom_smd_create_ept()
935 ept->priv = priv; in qcom_smd_create_ept()
936 ept->ops = &qcom_smd_endpoint_ops; in qcom_smd_create_ept()
938 channel->qsept = qsept; in qcom_smd_create_ept()
939 qsept->qsch = channel; in qcom_smd_create_ept()
941 ret = qcom_smd_channel_open(channel, cb); in qcom_smd_create_ept()
948 channel->qsept = NULL; in qcom_smd_create_ept()
949 kref_put(&ept->refcount, __ept_release); in qcom_smd_create_ept()
956 struct qcom_smd_channel *ch = qsept->qsch; in qcom_smd_destroy_ept()
959 ch->qsept = NULL; in qcom_smd_destroy_ept()
960 kref_put(&ept->refcount, __ept_release); in qcom_smd_destroy_ept()
967 return __qcom_smd_send(qsept->qsch, data, len, true); in qcom_smd_send()
974 return __qcom_smd_send(qsept->qsch, data, len, false); in qcom_smd_trysend()
981 return __qcom_smd_send(qsept->qsch, data, len, true); in qcom_smd_sendto()
988 return __qcom_smd_send(qsept->qsch, data, len, false); in qcom_smd_trysendto()
995 struct qcom_smd_channel *channel = qsept->qsch; in qcom_smd_poll() local
998 poll_wait(filp, &channel->fblockread_event, wait); in qcom_smd_poll()
1000 if (qcom_smd_get_tx_avail(channel) > 20) in qcom_smd_poll()
1007 * Finds the device_node for the smd child interested in this channel.
1010 const char *channel) in qcom_smd_match_channel() argument
1018 key = "qcom,smd-channels"; in qcom_smd_match_channel()
1023 if (strcmp(name, channel) == 0) in qcom_smd_match_channel()
1032 struct qcom_smd_endpoint *qept = to_smd_endpoint(rpdev->ept); in qcom_smd_announce_create()
1033 struct qcom_smd_channel *channel = qept->qsch; in qcom_smd_announce_create() local
1037 spin_lock_irqsave(&channel->recv_lock, flags); in qcom_smd_announce_create()
1038 kick_state = qcom_smd_channel_intr(channel); in qcom_smd_announce_create()
1039 spin_unlock_irqrestore(&channel->recv_lock, flags); in qcom_smd_announce_create()
1042 schedule_work(&channel->edge->state_work); in qcom_smd_announce_create()
1070 * Create a smd client device for channel that is being opened.
1072 static int qcom_smd_create_device(struct qcom_smd_channel *channel) in qcom_smd_create_device() argument
1076 struct qcom_smd_edge *edge = channel->edge; in qcom_smd_create_device()
1078 dev_dbg(&edge->dev, "registering '%s'\n", channel->name); in qcom_smd_create_device()
1082 return -ENOMEM; in qcom_smd_create_device()
1085 qsdev->edge = edge; in qcom_smd_create_device()
1088 qsdev->rpdev.ops = &qcom_smd_device_ops; in qcom_smd_create_device()
1091 rpdev = &qsdev->rpdev; in qcom_smd_create_device()
1092 strscpy_pad(rpdev->id.name, channel->name, RPMSG_NAME_SIZE); in qcom_smd_create_device()
1093 rpdev->src = RPMSG_ADDR_ANY; in qcom_smd_create_device()
1094 rpdev->dst = RPMSG_ADDR_ANY; in qcom_smd_create_device()
1096 rpdev->dev.of_node = qcom_smd_match_channel(edge->of_node, channel->name); in qcom_smd_create_device()
1097 rpdev->dev.parent = &edge->dev; in qcom_smd_create_device()
1098 rpdev->dev.release = qcom_smd_release_device; in qcom_smd_create_device()
1109 return -ENOMEM; in qcom_smd_create_chrdev()
1111 qsdev->edge = edge; in qcom_smd_create_chrdev()
1112 qsdev->rpdev.ops = &qcom_smd_device_ops; in qcom_smd_create_chrdev()
1113 qsdev->rpdev.dev.parent = &edge->dev; in qcom_smd_create_chrdev()
1114 qsdev->rpdev.dev.release = qcom_smd_release_device; in qcom_smd_create_chrdev()
1116 return rpmsg_ctrldev_register_device(&qsdev->rpdev); in qcom_smd_create_chrdev()
1120 * Allocate the qcom_smd_channel object for a newly found smd channel,
1128 struct qcom_smd_channel *channel; in qcom_smd_create_channel() local
1135 channel = kzalloc(sizeof(*channel), GFP_KERNEL); in qcom_smd_create_channel()
1136 if (!channel) in qcom_smd_create_channel()
1137 return ERR_PTR(-ENOMEM); in qcom_smd_create_channel()
1139 channel->edge = edge; in qcom_smd_create_channel()
1140 channel->name = kstrdup(name, GFP_KERNEL); in qcom_smd_create_channel()
1141 if (!channel->name) { in qcom_smd_create_channel()
1142 ret = -ENOMEM; in qcom_smd_create_channel()
1146 spin_lock_init(&channel->tx_lock); in qcom_smd_create_channel()
1147 spin_lock_init(&channel->recv_lock); in qcom_smd_create_channel()
1148 init_waitqueue_head(&channel->fblockread_event); in qcom_smd_create_channel()
1149 init_waitqueue_head(&channel->state_change_event); in qcom_smd_create_channel()
1151 info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size); in qcom_smd_create_channel()
1158 * Use the size of the item to figure out which channel info struct to in qcom_smd_create_channel()
1162 channel->info_word = info; in qcom_smd_create_channel()
1164 channel->info = info; in qcom_smd_create_channel()
1166 dev_err(&edge->dev, in qcom_smd_create_channel()
1167 "channel info of size %zu not supported\n", info_size); in qcom_smd_create_channel()
1168 ret = -EINVAL; in qcom_smd_create_channel()
1172 fifo_base = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_size); in qcom_smd_create_channel()
1178 /* The channel consist of a rx and tx fifo of equal size */ in qcom_smd_create_channel()
1181 dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", in qcom_smd_create_channel()
1184 channel->tx_fifo = fifo_base; in qcom_smd_create_channel()
1185 channel->rx_fifo = fifo_base + fifo_size; in qcom_smd_create_channel()
1186 channel->fifo_size = fifo_size; in qcom_smd_create_channel()
1188 qcom_smd_channel_reset(channel); in qcom_smd_create_channel()
1190 return channel; in qcom_smd_create_channel()
1193 kfree(channel->name); in qcom_smd_create_channel()
1195 kfree(channel); in qcom_smd_create_channel()
1210 struct qcom_smd_channel *channel; in qcom_channel_scan_worker() local
1219 alloc_tbl = qcom_smem_get(edge->remote_pid, in qcom_channel_scan_worker()
1226 eflags = le32_to_cpu(entry->flags); in qcom_channel_scan_worker()
1227 if (test_bit(i, edge->allocated[tbl])) in qcom_channel_scan_worker()
1230 if (entry->ref_count == 0) in qcom_channel_scan_worker()
1233 if (!entry->name[0]) in qcom_channel_scan_worker()
1239 if ((eflags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id) in qcom_channel_scan_worker()
1242 cid = le32_to_cpu(entry->cid); in qcom_channel_scan_worker()
1246 channel = qcom_smd_create_channel(edge, info_id, fifo_id, entry->name); in qcom_channel_scan_worker()
1247 if (IS_ERR(channel)) in qcom_channel_scan_worker()
1250 spin_lock_irqsave(&edge->channels_lock, flags); in qcom_channel_scan_worker()
1251 list_add(&channel->list, &edge->channels); in qcom_channel_scan_worker()
1252 spin_unlock_irqrestore(&edge->channels_lock, flags); in qcom_channel_scan_worker()
1254 dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name); in qcom_channel_scan_worker()
1255 set_bit(i, edge->allocated[tbl]); in qcom_channel_scan_worker()
1257 wake_up_interruptible_all(&edge->new_channel_event); in qcom_channel_scan_worker()
1261 schedule_work(&edge->state_work); in qcom_channel_scan_worker()
1269 * LOCKING: edge->channels_lock only needs to cover the list operations, as the
1274 struct qcom_smd_channel *channel; in qcom_channel_state_worker() local
1283 * Register a device for any closed channel where the remote processor in qcom_channel_state_worker()
1284 * is showing interest in opening the channel. in qcom_channel_state_worker()
1286 spin_lock_irqsave(&edge->channels_lock, flags); in qcom_channel_state_worker()
1287 list_for_each_entry(channel, &edge->channels, list) { in qcom_channel_state_worker()
1288 if (channel->state != SMD_CHANNEL_CLOSED) in qcom_channel_state_worker()
1295 remote_state = GET_RX_CHANNEL_INFO(channel, state); in qcom_channel_state_worker()
1298 strcmp(channel->name, "rpm_requests")) in qcom_channel_state_worker()
1301 if (channel->registered) in qcom_channel_state_worker()
1304 spin_unlock_irqrestore(&edge->channels_lock, flags); in qcom_channel_state_worker()
1305 qcom_smd_create_device(channel); in qcom_channel_state_worker()
1306 spin_lock_irqsave(&edge->channels_lock, flags); in qcom_channel_state_worker()
1307 channel->registered = true; in qcom_channel_state_worker()
1311 * Unregister the device for any channel that is opened where the in qcom_channel_state_worker()
1312 * remote processor is closing the channel. in qcom_channel_state_worker()
1314 list_for_each_entry(channel, &edge->channels, list) { in qcom_channel_state_worker()
1315 if (channel->state != SMD_CHANNEL_OPENING && in qcom_channel_state_worker()
1316 channel->state != SMD_CHANNEL_OPENED) in qcom_channel_state_worker()
1319 remote_state = GET_RX_CHANNEL_INFO(channel, state); in qcom_channel_state_worker()
1324 spin_unlock_irqrestore(&edge->channels_lock, flags); in qcom_channel_state_worker()
1326 strscpy_pad(chinfo.name, channel->name, sizeof(chinfo.name)); in qcom_channel_state_worker()
1329 rpmsg_unregister_device(&edge->dev, &chinfo); in qcom_channel_state_worker()
1330 channel->registered = false; in qcom_channel_state_worker()
1331 spin_lock_irqsave(&edge->channels_lock, flags); in qcom_channel_state_worker()
1333 spin_unlock_irqrestore(&edge->channels_lock, flags); in qcom_channel_state_worker()
1348 INIT_LIST_HEAD(&edge->channels); in qcom_smd_parse_edge()
1349 spin_lock_init(&edge->channels_lock); in qcom_smd_parse_edge()
1351 INIT_WORK(&edge->scan_work, qcom_channel_scan_worker); in qcom_smd_parse_edge()
1352 INIT_WORK(&edge->state_work, qcom_channel_state_worker); in qcom_smd_parse_edge()
1354 edge->of_node = of_node_get(node); in qcom_smd_parse_edge()
1356 key = "qcom,smd-edge"; in qcom_smd_parse_edge()
1357 ret = of_property_read_u32(node, key, &edge->edge_id); in qcom_smd_parse_edge()
1363 edge->remote_pid = QCOM_SMEM_HOST_ANY; in qcom_smd_parse_edge()
1364 key = "qcom,remote-pid"; in qcom_smd_parse_edge()
1365 of_property_read_u32(node, key, &edge->remote_pid); in qcom_smd_parse_edge()
1367 edge->mbox_client.dev = dev; in qcom_smd_parse_edge()
1368 edge->mbox_client.knows_txdone = true; in qcom_smd_parse_edge()
1369 edge->mbox_chan = mbox_request_channel(&edge->mbox_client, 0); in qcom_smd_parse_edge()
1370 if (IS_ERR(edge->mbox_chan)) { in qcom_smd_parse_edge()
1371 if (PTR_ERR(edge->mbox_chan) != -ENODEV) { in qcom_smd_parse_edge()
1372 ret = PTR_ERR(edge->mbox_chan); in qcom_smd_parse_edge()
1376 edge->mbox_chan = NULL; in qcom_smd_parse_edge()
1381 ret = -ENODEV; in qcom_smd_parse_edge()
1385 edge->ipc_regmap = syscon_node_to_regmap(syscon_np); in qcom_smd_parse_edge()
1387 if (IS_ERR(edge->ipc_regmap)) { in qcom_smd_parse_edge()
1388 ret = PTR_ERR(edge->ipc_regmap); in qcom_smd_parse_edge()
1393 ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset); in qcom_smd_parse_edge()
1399 ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit); in qcom_smd_parse_edge()
1406 ret = of_property_read_string(node, "label", &edge->name); in qcom_smd_parse_edge()
1408 edge->name = node->name; in qcom_smd_parse_edge()
1413 ret = -EINVAL; in qcom_smd_parse_edge()
1419 node->name, edge); in qcom_smd_parse_edge()
1425 edge->irq = irq; in qcom_smd_parse_edge()
1431 edge->of_node = NULL; in qcom_smd_parse_edge()
1438 * Reset the state of each associated channel and free the edge context.
1442 struct qcom_smd_channel *channel, *tmp; in qcom_smd_edge_release() local
1445 list_for_each_entry_safe(channel, tmp, &edge->channels, list) { in qcom_smd_edge_release()
1446 list_del(&channel->list); in qcom_smd_edge_release()
1447 kfree(channel->name); in qcom_smd_edge_release()
1448 kfree(channel); in qcom_smd_edge_release()
1459 return sprintf(buf, "%s\n", edge->name); in rpmsg_name_show()
1470 * qcom_smd_register_edge() - register an edge based on an device_node
1483 return ERR_PTR(-EPROBE_DEFER); in qcom_smd_register_edge()
1487 return ERR_PTR(-ENOMEM); in qcom_smd_register_edge()
1489 init_waitqueue_head(&edge->new_channel_event); in qcom_smd_register_edge()
1491 edge->dev.parent = parent; in qcom_smd_register_edge()
1492 edge->dev.release = qcom_smd_edge_release; in qcom_smd_register_edge()
1493 edge->dev.of_node = node; in qcom_smd_register_edge()
1494 edge->dev.groups = qcom_smd_edge_groups; in qcom_smd_register_edge()
1495 dev_set_name(&edge->dev, "%s:%pOFn", dev_name(parent), node); in qcom_smd_register_edge()
1496 ret = device_register(&edge->dev); in qcom_smd_register_edge()
1499 put_device(&edge->dev); in qcom_smd_register_edge()
1503 ret = qcom_smd_parse_edge(&edge->dev, node, edge); in qcom_smd_register_edge()
1505 dev_err(&edge->dev, "failed to parse smd edge\n"); in qcom_smd_register_edge()
1511 dev_err(&edge->dev, "failed to register chrdev for edge\n"); in qcom_smd_register_edge()
1515 schedule_work(&edge->scan_work); in qcom_smd_register_edge()
1520 if (!IS_ERR_OR_NULL(edge->mbox_chan)) in qcom_smd_register_edge()
1521 mbox_free_channel(edge->mbox_chan); in qcom_smd_register_edge()
1523 device_unregister(&edge->dev); in qcom_smd_register_edge()
1536 * qcom_smd_unregister_edge() - release an edge and its children
1543 disable_irq(edge->irq); in qcom_smd_unregister_edge()
1544 cancel_work_sync(&edge->scan_work); in qcom_smd_unregister_edge()
1545 cancel_work_sync(&edge->state_work); in qcom_smd_unregister_edge()
1547 ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device); in qcom_smd_unregister_edge()
1549 dev_warn(&edge->dev, "can't remove smd device: %d\n", ret); in qcom_smd_unregister_edge()
1551 mbox_free_channel(edge->mbox_chan); in qcom_smd_unregister_edge()
1552 device_unregister(&edge->dev); in qcom_smd_unregister_edge()
1561 return -EPROBE_DEFER; in qcom_smd_probe()
1563 for_each_available_child_of_node(pdev->dev.of_node, node) in qcom_smd_probe()
1564 qcom_smd_register_edge(&pdev->dev, node); in qcom_smd_probe()
1588 device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge); in qcom_smd_remove()
1601 .name = "qcom-smd",