net/mlx5: Fix race between PCI error handlers and health work
[cascardo/linux.git] / drivers / rpmsg / virtio_rpmsg_bus.c
index 31cd526..3090b0d 100644 (file)
@@ -75,6 +75,70 @@ struct virtproc_info {
        struct rpmsg_endpoint *ns_ept;
 };
 
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS      0 /* RP supports name service notifications */
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+struct rpmsg_hdr {
+       u32 src;
+       u32 dst;
+       u32 reserved;
+       u16 len;
+       u16 flags;
+       u8 data[0];
+} __packed;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+       char name[RPMSG_NAME_SIZE];
+       u32 addr;
+       u32 flags;
+} __packed;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+       RPMSG_NS_CREATE         = 0,
+       RPMSG_NS_DESTROY        = 1,
+};
+
+/**
+ * @vrp: the remote processor this channel belongs to
+ */
+struct virtio_rpmsg_channel {
+       struct rpmsg_device rpdev;
+
+       struct virtproc_info *vrp;
+};
+
+#define to_virtio_rpmsg_channel(_rpdev) \
+       container_of(_rpdev, struct virtio_rpmsg_channel, rpdev)
+
 /*
  * We're allocating buffers of 512 bytes each for communications. The
  * number of buffers will be computed from the number of buffers supported
@@ -204,7 +268,9 @@ static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev
                                                      void *priv,
                                                      struct rpmsg_channel_info chinfo)
 {
-       return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, chinfo.src);
+       struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+
+       return __rpmsg_create_ept(vch->vrp, rpdev, cb, priv, chinfo.src);
 }
 
 /**
@@ -235,12 +301,15 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
 
 static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
 {
-       __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+       struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(ept->rpdev);
+
+       __rpmsg_destroy_ept(vch->vrp, ept);
 }
 
 static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
 {
-       struct virtproc_info *vrp = rpdev->vrp;
+       struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+       struct virtproc_info *vrp = vch->vrp;
        struct device *dev = &rpdev->dev;
        int err = 0;
 
@@ -263,7 +332,8 @@ static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
 
 static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev)
 {
-       struct virtproc_info *vrp = rpdev->vrp;
+       struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+       struct virtproc_info *vrp = vch->vrp;
        struct device *dev = &rpdev->dev;
        int err = 0;
 
@@ -298,6 +368,7 @@ static const struct rpmsg_device_ops virtio_rpmsg_ops = {
 static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
                                                 struct rpmsg_channel_info *chinfo)
 {
+       struct virtio_rpmsg_channel *vch;
        struct rpmsg_device *rpdev;
        struct device *tmp, *dev = &vrp->vdev->dev;
        int ret;
@@ -312,11 +383,18 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp,
                return NULL;
        }
 
-       rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
-       if (!rpdev)
+       vch = kzalloc(sizeof(*vch), GFP_KERNEL);
+       if (!vch)
                return NULL;
 
-       rpdev->vrp = vrp;
+       /* Link the channel to our vrp */
+       vch->vrp = vrp;
+
+       /* Assign callbacks for rpmsg_channel */
+       vch->rpdev.ops = &virtio_rpmsg_ops;
+
+       /* Assign public information to the rpmsg_device */
+       rpdev = &vch->rpdev;
        rpdev->src = chinfo->src;
        rpdev->dst = chinfo->dst;
        rpdev->ops = &virtio_rpmsg_ops;
@@ -455,7 +533,8 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
                                     u32 src, u32 dst,
                                     void *data, int len, bool wait)
 {
-       struct virtproc_info *vrp = rpdev->vrp;
+       struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+       struct virtproc_info *vrp = vch->vrp;
        struct device *dev = &rpdev->dev;
        struct scatterlist sg;
        struct rpmsg_hdr *msg;
@@ -712,8 +791,8 @@ static void rpmsg_xmit_done(struct virtqueue *svq)
 }
 
 /* invoked when a name service announcement arrives */
-static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
-                       void *priv, u32 src)
+static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
+                      void *priv, u32 src)
 {
        struct rpmsg_ns_msg *msg = data;
        struct rpmsg_device *newch;
@@ -729,7 +808,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
 
        if (len != sizeof(*msg)) {
                dev_err(dev, "malformed ns msg (%d)\n", len);
-               return;
+               return -EINVAL;
        }
 
        /*
@@ -740,7 +819,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
         */
        if (rpdev) {
                dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
-               return;
+               return -EINVAL;
        }
 
        /* don't trust the remote processor for null terminating the name */
@@ -763,6 +842,8 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
                if (!newch)
                        dev_err(dev, "rpmsg_create_channel failed\n");
        }
+
+       return 0;
 }
 
 static int rpmsg_probe(struct virtio_device *vdev)