Skip to content

Commit

Permalink
net: add rpmsg sockets and a userland demo app
Browse files Browse the repository at this point in the history
Warning: this is still completely preliminary and buggy.

It's only here to assist folks who needs this for development.

Signed-off-by: Ohad Ben-Cohen <[email protected]>
  • Loading branch information
ohadbc authored and michalsimek committed Oct 24, 2012
1 parent 66e4e3a commit bb8616d
Show file tree
Hide file tree
Showing 8 changed files with 864 additions and 9 deletions.
82 changes: 74 additions & 8 deletions drivers/rpmsg/virtio_rpmsg_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
* @sendq: wait queue of sending contexts waiting for a tx buffers
* @sleepers: number of senders that are waiting for a tx buffer
* @ns_ept: the bus's name service endpoint
* @id: unique system-wide index id for this vproc
*
* This structure stores the rpmsg state of a given virtio remote processor
* device (there might be several virtio proc devices for each physical
Expand All @@ -68,8 +69,15 @@ struct virtproc_info {
wait_queue_head_t sendq;
atomic_t sleepers;
struct rpmsg_endpoint *ns_ept;
int id;
};

int get_virtproc_id(struct virtproc_info *vrp)
{
return vrp->id;
}
EXPORT_SYMBOL(get_virtproc_id);

/**
* struct rpmsg_channel_info - internal channel info representation
* @name: name of service
Expand Down Expand Up @@ -133,6 +141,16 @@ rpmsg_show_attr(src, src, "0x%x\n");
rpmsg_show_attr(dst, dst, "0x%x\n");
rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");

/*
* The virtio devices we are probed with represent remote processors
* on the system. We call them _virtual_ processors, because every physical
* remote processor might actually have several virtio devices.
*
* The idr below is used to assign each vproc a unique, system-wide, index id.
*/
static struct idr vprocs;
static DEFINE_MUTEX(vprocs_mutex);

/*
* Unique (and free running) index for rpmsg devices.
*
Expand Down Expand Up @@ -499,7 +517,7 @@ static int rpmsg_channel_match(struct device *dev, void *data)
* this function will be used to create both static and dynamic
* channels.
*/
static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
static struct rpmsg_channel *__rpmsg_create_channel(struct virtproc_info *vrp,
struct rpmsg_channel_info *chinfo)
{
struct rpmsg_channel *rpdev;
Expand Down Expand Up @@ -555,7 +573,7 @@ static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
* find an existing channel using its name + address properties,
* and destroy it
*/
static int rpmsg_destroy_channel(struct virtproc_info *vrp,
static int __rpmsg_destroy_channel(struct virtproc_info *vrp,
struct rpmsg_channel_info *chinfo)
{
struct virtio_device *vdev = vrp->vdev;
Expand Down Expand Up @@ -874,6 +892,25 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
wake_up_interruptible(&vrp->sendq);
}

struct rpmsg_channel *rpmsg_create_channel(int vrp_id, const char *name,
int src, int dst)
{
struct rpmsg_channel_info chinfo;
struct virtproc_info *vrp;

strncpy(chinfo.name, name, sizeof(chinfo.name));
chinfo.src = src;
chinfo.dst = dst;

/* TODO we probably want radix tree and fw-induced id numbers ? */
vrp = idr_find(&vprocs, vrp_id);
if (!vrp)
return NULL;

return __rpmsg_create_channel(vrp, &chinfo);
}
EXPORT_SYMBOL(rpmsg_create_channel);

/* invoked when a name service announcement arrives */
static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
void *priv, u32 src)
Expand Down Expand Up @@ -917,13 +954,13 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
chinfo.dst = msg->addr;

if (msg->flags & RPMSG_NS_DESTROY) {
ret = rpmsg_destroy_channel(vrp, &chinfo);
ret = __rpmsg_destroy_channel(vrp, &chinfo);
if (ret)
dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
dev_err(dev, "__rpmsg_destroy_channel err: %d\n", ret);
} else {
newch = rpmsg_create_channel(vrp, &chinfo);
newch = __rpmsg_create_channel(vrp, &chinfo);
if (!newch)
dev_err(dev, "rpmsg_create_channel failed\n");
dev_err(dev, "__rpmsg_create_channel failed\n");
}
}

Expand All @@ -934,7 +971,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
struct virtqueue *vqs[2];
struct virtproc_info *vrp;
void *bufs_va;
int err = 0, i;
int err = 0, i, vproc_id;

vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
if (!vrp)
Expand All @@ -947,10 +984,26 @@ static int rpmsg_probe(struct virtio_device *vdev)
mutex_init(&vrp->tx_lock);
init_waitqueue_head(&vrp->sendq);

if (!idr_pre_get(&vprocs, GFP_KERNEL))
goto free_vrp;

mutex_lock(&vprocs_mutex);

err = idr_get_new(&vprocs, vrp, &vproc_id);

mutex_unlock(&vprocs_mutex);

if (err) {
dev_err(&vdev->dev, "idr_get_new failed: %d\n", err);
goto free_vrp;
}

vrp->id = vproc_id;

/* We expect two virtqueues, rx and tx (and in this order) */
err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names);
if (err)
goto free_vrp;
goto rem_idr;

vrp->rvq = vqs[0];
vrp->svq = vqs[1];
Expand Down Expand Up @@ -1012,6 +1065,10 @@ static int rpmsg_probe(struct virtio_device *vdev)
bufs_va, vrp->bufs_dma);
vqs_del:
vdev->config->del_vqs(vrp->vdev);
rem_idr:
mutex_lock(&vprocs_mutex);
idr_remove(&vprocs, vproc_id);
mutex_unlock(&vprocs_mutex);
free_vrp:
kfree(vrp);
return err;
Expand Down Expand Up @@ -1046,6 +1103,10 @@ static void __devexit rpmsg_remove(struct virtio_device *vdev)
dma_free_coherent(vdev->dev.parent->parent, RPMSG_TOTAL_BUF_SPACE,
vrp->rbufs, vrp->bufs_dma);

mutex_lock(&vprocs_mutex);
idr_remove(&vprocs, vrp->id);
mutex_unlock(&vprocs_mutex);

kfree(vrp);
}

Expand All @@ -1072,6 +1133,8 @@ static int __init rpmsg_init(void)
{
int ret;

idr_init(&vprocs);

ret = bus_register(&rpmsg_bus);
if (ret) {
pr_err("failed to register rpmsg bus: %d\n", ret);
Expand All @@ -1092,6 +1155,9 @@ static void __exit rpmsg_fini(void)
{
unregister_virtio_driver(&virtio_ipc_driver);
bus_unregister(&rpmsg_bus);

idr_remove_all(&vprocs);
idr_destroy(&vprocs);
}
module_exit(rpmsg_fini);

Expand Down
4 changes: 4 additions & 0 deletions include/linux/rpmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,8 @@ int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
}

int get_virtproc_id(struct virtproc_info *vrp);
struct rpmsg_channel *rpmsg_create_channel(int vrp_id, const char *name,
int src, int dst);

#endif /* _LINUX_RPMSG_H */
5 changes: 4 additions & 1 deletion include/linux/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ struct ucred {
#define AF_CAIF 37 /* CAIF sockets */
#define AF_ALG 38 /* Algorithm sockets */
#define AF_NFC 39 /* NFC sockets */
#define AF_MAX 40 /* For now.. */
#define AF_RPMSG 40 /* Remote-processor messaging */
#define AF_MAX 41 /* For now.. */

/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
Expand Down Expand Up @@ -238,6 +239,7 @@ struct ucred {
#define PF_CAIF AF_CAIF
#define PF_ALG AF_ALG
#define PF_NFC AF_NFC
#define PF_RPMSG AF_RPMSG
#define PF_MAX AF_MAX

/* Maximum queue length specifiable by listen. */
Expand Down Expand Up @@ -313,6 +315,7 @@ struct ucred {
#define SOL_IUCV 277
#define SOL_CAIF 278
#define SOL_ALG 279
#define SOL_RPMSG 280

/* IPX options */
#define IPX_TYPE 1
Expand Down
58 changes: 58 additions & 0 deletions include/net/rpmsg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Remote processor messaging sockets
*
* Copyright (C) 2011 Texas Instruments, Inc
*
* Ohad Ben-Cohen <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

#ifndef __NET_RPMSG_H
#define __NET_RPMSG_H

#include <linux/types.h>
#include <linux/socket.h>

/* user space needs this */
#ifndef AF_RPMSG
#define AF_RPMSG 40
#define PF_RPMSG AF_RPMSG
#endif

/* Connection and socket states */
enum {
RPMSG_CONNECTED = 1, /* wait_for_packet() wants this... */
RPMSG_OPEN,
RPMSG_LISTENING,
RPMSG_CLOSED,
};

struct sockaddr_rpmsg {
sa_family_t family;
__u32 vproc_id;
__u32 addr;
};

#define RPMSG_LOCALHOST ((__u32) ~0UL)

#ifdef __KERNEL__

#include <net/sock.h>
#include <linux/rpmsg.h>

struct rpmsg_socket {
struct sock sk;
struct rpmsg_channel *rpdev;
bool unregister_rpdev;
};

#endif /* __KERNEL__ */
#endif /* __NET_RPMSG_H */
1 change: 1 addition & 0 deletions net/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ obj-$(CONFIG_CEPH_LIB) += ceph/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NFC) += nfc/
obj-$(CONFIG_OPENVSWITCH) += openvswitch/
obj-$(CONFIG_RPMSG) += rpmsg/
1 change: 1 addition & 0 deletions net/rpmsg/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
obj-$(CONFIG_RPMSG) += rpmsg_proto.o
Loading

0 comments on commit bb8616d

Please sign in to comment.