| .. | .. |
|---|
| 11 | 11 | |
|---|
| 12 | 12 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
|---|
| 13 | 13 | |
|---|
| 14 | | -#include <linux/kernel.h> |
|---|
| 15 | | -#include <linux/module.h> |
|---|
| 16 | | -#include <linux/virtio.h> |
|---|
| 17 | | -#include <linux/virtio_ids.h> |
|---|
| 18 | | -#include <linux/virtio_config.h> |
|---|
| 19 | | -#include <linux/scatterlist.h> |
|---|
| 20 | 14 | #include <linux/dma-mapping.h> |
|---|
| 21 | | -#include <linux/slab.h> |
|---|
| 22 | 15 | #include <linux/idr.h> |
|---|
| 23 | 16 | #include <linux/jiffies.h> |
|---|
| 24 | | -#include <linux/sched.h> |
|---|
| 25 | | -#include <linux/wait.h> |
|---|
| 26 | | -#include <linux/rpmsg.h> |
|---|
| 17 | +#include <linux/kernel.h> |
|---|
| 18 | +#include <linux/module.h> |
|---|
| 27 | 19 | #include <linux/mutex.h> |
|---|
| 28 | 20 | #include <linux/of_device.h> |
|---|
| 21 | +#include <linux/rpmsg.h> |
|---|
| 22 | +#include <linux/scatterlist.h> |
|---|
| 23 | +#include <linux/slab.h> |
|---|
| 24 | +#include <linux/sched.h> |
|---|
| 25 | +#include <linux/virtio.h> |
|---|
| 26 | +#include <linux/virtio_byteorder.h> |
|---|
| 27 | +#include <linux/virtio_ids.h> |
|---|
| 28 | +#include <linux/virtio_config.h> |
|---|
| 29 | +#include <linux/wait.h> |
|---|
| 29 | 30 | |
|---|
| 30 | 31 | #include "rpmsg_internal.h" |
|---|
| 31 | 32 | |
|---|
| .. | .. |
|---|
| 84 | 85 | * Every message sent(/received) on the rpmsg bus begins with this header. |
|---|
| 85 | 86 | */ |
|---|
| 86 | 87 | struct rpmsg_hdr { |
|---|
| 87 | | - u32 src; |
|---|
| 88 | | - u32 dst; |
|---|
| 89 | | - u32 reserved; |
|---|
| 90 | | - u16 len; |
|---|
| 91 | | - u16 flags; |
|---|
| 92 | | - u8 data[0]; |
|---|
| 88 | + __virtio32 src; |
|---|
| 89 | + __virtio32 dst; |
|---|
| 90 | + __virtio32 reserved; |
|---|
| 91 | + __virtio16 len; |
|---|
| 92 | + __virtio16 flags; |
|---|
| 93 | + u8 data[]; |
|---|
| 93 | 94 | } __packed; |
|---|
| 94 | 95 | |
|---|
| 95 | 96 | /** |
|---|
| .. | .. |
|---|
| 106 | 107 | */ |
|---|
| 107 | 108 | struct rpmsg_ns_msg { |
|---|
| 108 | 109 | char name[RPMSG_NAME_SIZE]; |
|---|
| 109 | | - u32 addr; |
|---|
| 110 | | - u32 flags; |
|---|
| 110 | + __virtio32 addr; |
|---|
| 111 | + __virtio32 flags; |
|---|
| 111 | 112 | } __packed; |
|---|
| 112 | 113 | |
|---|
| 113 | 114 | /** |
|---|
| .. | .. |
|---|
| 122 | 123 | }; |
|---|
| 123 | 124 | |
|---|
| 124 | 125 | /** |
|---|
| 125 | | - * @vrp: the remote processor this channel belongs to |
|---|
| 126 | + * struct virtio_rpmsg_channel - rpmsg channel descriptor |
|---|
| 127 | + * @rpdev: the rpmsg channel device |
|---|
| 128 | + * @vrp: the virtio remote processor device this channel belongs to |
|---|
| 129 | + * |
|---|
| 130 | + * This structure stores the channel that links the rpmsg device to the virtio |
|---|
| 131 | + * remote processor device. |
|---|
| 126 | 132 | */ |
|---|
| 127 | 133 | struct virtio_rpmsg_channel { |
|---|
| 128 | 134 | struct rpmsg_device rpdev; |
|---|
| .. | .. |
|---|
| 175 | 181 | int len, u32 dst); |
|---|
| 176 | 182 | static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, |
|---|
| 177 | 183 | u32 dst, void *data, int len); |
|---|
| 184 | +static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept); |
|---|
| 178 | 185 | |
|---|
| 179 | 186 | static const struct rpmsg_endpoint_ops virtio_endpoint_ops = { |
|---|
| 180 | 187 | .destroy_ept = virtio_rpmsg_destroy_ept, |
|---|
| .. | .. |
|---|
| 184 | 191 | .trysend = virtio_rpmsg_trysend, |
|---|
| 185 | 192 | .trysendto = virtio_rpmsg_trysendto, |
|---|
| 186 | 193 | .trysend_offchannel = virtio_rpmsg_trysend_offchannel, |
|---|
| 194 | + .get_mtu = virtio_rpmsg_get_mtu, |
|---|
| 187 | 195 | }; |
|---|
| 188 | 196 | |
|---|
| 189 | 197 | /** |
|---|
| .. | .. |
|---|
| 335 | 343 | struct rpmsg_ns_msg nsm; |
|---|
| 336 | 344 | |
|---|
| 337 | 345 | strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE); |
|---|
| 338 | | - nsm.addr = rpdev->ept->addr; |
|---|
| 339 | | - nsm.flags = RPMSG_NS_CREATE; |
|---|
| 346 | + nsm.addr = cpu_to_virtio32(vrp->vdev, rpdev->ept->addr); |
|---|
| 347 | + nsm.flags = cpu_to_virtio32(vrp->vdev, RPMSG_NS_CREATE); |
|---|
| 340 | 348 | |
|---|
| 341 | 349 | err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR); |
|---|
| 342 | 350 | if (err) |
|---|
| .. | .. |
|---|
| 359 | 367 | struct rpmsg_ns_msg nsm; |
|---|
| 360 | 368 | |
|---|
| 361 | 369 | strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE); |
|---|
| 362 | | - nsm.addr = rpdev->ept->addr; |
|---|
| 363 | | - nsm.flags = RPMSG_NS_DESTROY; |
|---|
| 370 | + nsm.addr = cpu_to_virtio32(vrp->vdev, rpdev->ept->addr); |
|---|
| 371 | + nsm.flags = cpu_to_virtio32(vrp->vdev, RPMSG_NS_DESTROY); |
|---|
| 364 | 372 | |
|---|
| 365 | 373 | err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR); |
|---|
| 366 | 374 | if (err) |
|---|
| .. | .. |
|---|
| 612 | 620 | } |
|---|
| 613 | 621 | } |
|---|
| 614 | 622 | |
|---|
| 615 | | - msg->len = len; |
|---|
| 623 | + msg->len = cpu_to_virtio16(vrp->vdev, len); |
|---|
| 616 | 624 | msg->flags = 0; |
|---|
| 617 | | - msg->src = src; |
|---|
| 618 | | - msg->dst = dst; |
|---|
| 625 | + msg->src = cpu_to_virtio32(vrp->vdev, src); |
|---|
| 626 | + msg->dst = cpu_to_virtio32(vrp->vdev, dst); |
|---|
| 619 | 627 | msg->reserved = 0; |
|---|
| 620 | 628 | memcpy(msg->data, data, len); |
|---|
| 621 | 629 | |
|---|
| 622 | 630 | dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n", |
|---|
| 623 | | - msg->src, msg->dst, msg->len, msg->flags, msg->reserved); |
|---|
| 631 | + src, dst, len, msg->flags, msg->reserved); |
|---|
| 624 | 632 | #if defined(CONFIG_DYNAMIC_DEBUG) |
|---|
| 625 | 633 | dynamic_hex_dump("rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1, |
|---|
| 626 | | - msg, sizeof(*msg) + msg->len, true); |
|---|
| 634 | + msg, sizeof(*msg) + len, true); |
|---|
| 627 | 635 | #endif |
|---|
| 628 | 636 | |
|---|
| 629 | 637 | rpmsg_sg_init(&sg, msg, sizeof(*msg) + len); |
|---|
| .. | .. |
|---|
| 699 | 707 | return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); |
|---|
| 700 | 708 | } |
|---|
| 701 | 709 | |
|---|
| 710 | +static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept) |
|---|
| 711 | +{ |
|---|
| 712 | + struct rpmsg_device *rpdev = ept->rpdev; |
|---|
| 713 | + struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); |
|---|
| 714 | + |
|---|
| 715 | + return vch->vrp->buf_size - sizeof(struct rpmsg_hdr); |
|---|
| 716 | +} |
|---|
| 717 | + |
|---|
| 702 | 718 | static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, |
|---|
| 703 | 719 | struct rpmsg_hdr *msg, unsigned int len) |
|---|
| 704 | 720 | { |
|---|
| 705 | 721 | struct rpmsg_endpoint *ept; |
|---|
| 706 | 722 | struct scatterlist sg; |
|---|
| 723 | + unsigned int msg_len = virtio16_to_cpu(vrp->vdev, msg->len); |
|---|
| 707 | 724 | int err; |
|---|
| 708 | 725 | |
|---|
| 709 | 726 | dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n", |
|---|
| 710 | | - msg->src, msg->dst, msg->len, msg->flags, msg->reserved); |
|---|
| 727 | + virtio32_to_cpu(vrp->vdev, msg->src), |
|---|
| 728 | + virtio32_to_cpu(vrp->vdev, msg->dst), msg_len, |
|---|
| 729 | + virtio16_to_cpu(vrp->vdev, msg->flags), |
|---|
| 730 | + virtio32_to_cpu(vrp->vdev, msg->reserved)); |
|---|
| 711 | 731 | #if defined(CONFIG_DYNAMIC_DEBUG) |
|---|
| 712 | 732 | dynamic_hex_dump("rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1, |
|---|
| 713 | | - msg, sizeof(*msg) + msg->len, true); |
|---|
| 733 | + msg, sizeof(*msg) + msg_len, true); |
|---|
| 714 | 734 | #endif |
|---|
| 715 | 735 | |
|---|
| 716 | 736 | /* |
|---|
| .. | .. |
|---|
| 718 | 738 | * the reported payload length. |
|---|
| 719 | 739 | */ |
|---|
| 720 | 740 | if (len > vrp->buf_size || |
|---|
| 721 | | - msg->len > (len - sizeof(struct rpmsg_hdr))) { |
|---|
| 722 | | - dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len); |
|---|
| 741 | + msg_len > (len - sizeof(struct rpmsg_hdr))) { |
|---|
| 742 | + dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg_len); |
|---|
| 723 | 743 | return -EINVAL; |
|---|
| 724 | 744 | } |
|---|
| 725 | 745 | |
|---|
| 726 | 746 | /* use the dst addr to fetch the callback of the appropriate user */ |
|---|
| 727 | 747 | mutex_lock(&vrp->endpoints_lock); |
|---|
| 728 | 748 | |
|---|
| 729 | | - ept = idr_find(&vrp->endpoints, msg->dst); |
|---|
| 749 | + ept = idr_find(&vrp->endpoints, virtio32_to_cpu(vrp->vdev, msg->dst)); |
|---|
| 730 | 750 | |
|---|
| 731 | 751 | /* let's make sure no one deallocates ept while we use it */ |
|---|
| 732 | 752 | if (ept) |
|---|
| .. | .. |
|---|
| 739 | 759 | mutex_lock(&ept->cb_lock); |
|---|
| 740 | 760 | |
|---|
| 741 | 761 | if (ept->cb) |
|---|
| 742 | | - ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, |
|---|
| 743 | | - msg->src); |
|---|
| 762 | + ept->cb(ept->rpdev, msg->data, msg_len, ept->priv, |
|---|
| 763 | + virtio32_to_cpu(vrp->vdev, msg->src)); |
|---|
| 744 | 764 | |
|---|
| 745 | 765 | mutex_unlock(&ept->cb_lock); |
|---|
| 746 | 766 | |
|---|
| .. | .. |
|---|
| 846 | 866 | /* don't trust the remote processor for null terminating the name */ |
|---|
| 847 | 867 | msg->name[RPMSG_NAME_SIZE - 1] = '\0'; |
|---|
| 848 | 868 | |
|---|
| 849 | | - dev_info(dev, "%sing channel %s addr 0x%x\n", |
|---|
| 850 | | - msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat", |
|---|
| 851 | | - msg->name, msg->addr); |
|---|
| 852 | | - |
|---|
| 853 | 869 | strncpy(chinfo.name, msg->name, sizeof(chinfo.name)); |
|---|
| 854 | 870 | chinfo.src = RPMSG_ADDR_ANY; |
|---|
| 855 | | - chinfo.dst = msg->addr; |
|---|
| 871 | + chinfo.dst = virtio32_to_cpu(vrp->vdev, msg->addr); |
|---|
| 856 | 872 | |
|---|
| 857 | | - if (msg->flags & RPMSG_NS_DESTROY) { |
|---|
| 873 | + dev_info(dev, "%sing channel %s addr 0x%x\n", |
|---|
| 874 | + virtio32_to_cpu(vrp->vdev, msg->flags) & RPMSG_NS_DESTROY ? |
|---|
| 875 | + "destroy" : "creat", msg->name, chinfo.dst); |
|---|
| 876 | + |
|---|
| 877 | + if (virtio32_to_cpu(vrp->vdev, msg->flags) & RPMSG_NS_DESTROY) { |
|---|
| 858 | 878 | ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo); |
|---|
| 859 | 879 | if (ret) |
|---|
| 860 | 880 | dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret); |
|---|
| .. | .. |
|---|
| 920 | 940 | goto vqs_del; |
|---|
| 921 | 941 | } |
|---|
| 922 | 942 | |
|---|
| 923 | | - dev_dbg(&vdev->dev, "buffers: va %p, dma %pad\n", |
|---|
| 943 | + dev_dbg(&vdev->dev, "buffers: va %pK, dma %pad\n", |
|---|
| 924 | 944 | bufs_va, &vrp->bufs_dma); |
|---|
| 925 | 945 | |
|---|
| 926 | 946 | /* half of the buffers is dedicated for RX */ |
|---|