root/drivers/rpmsg/qcom_glink_smem.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. glink_smem_rx_avail
  2. glink_smem_rx_peak
  3. glink_smem_rx_advance
  4. glink_smem_tx_avail
  5. glink_smem_tx_write_one
  6. glink_smem_tx_write
  7. qcom_glink_smem_release
  8. qcom_glink_smem_register
  9. qcom_glink_smem_unregister

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2016, Linaro Ltd
   4  */
   5 
   6 #include <linux/io.h>
   7 #include <linux/module.h>
   8 #include <linux/of.h>
   9 #include <linux/of_address.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/slab.h>
  14 #include <linux/rpmsg.h>
  15 #include <linux/idr.h>
  16 #include <linux/circ_buf.h>
  17 #include <linux/soc/qcom/smem.h>
  18 #include <linux/sizes.h>
  19 #include <linux/delay.h>
  20 #include <linux/regmap.h>
  21 #include <linux/workqueue.h>
  22 #include <linux/list.h>
  23 
  24 #include <linux/rpmsg/qcom_glink.h>
  25 
  26 #include "qcom_glink_native.h"
  27 
  28 #define FIFO_FULL_RESERVE 8
  29 #define FIFO_ALIGNMENT 8
  30 #define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
  31 
  32 #define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR       478
  33 #define SMEM_GLINK_NATIVE_XPRT_FIFO_0           479
  34 #define SMEM_GLINK_NATIVE_XPRT_FIFO_1           480
  35 
  36 struct glink_smem_pipe {
  37         struct qcom_glink_pipe native;
  38 
  39         __le32 *tail;
  40         __le32 *head;
  41 
  42         void *fifo;
  43 
  44         int remote_pid;
  45 };
  46 
  47 #define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
  48 
  49 static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
  50 {
  51         struct glink_smem_pipe *pipe = to_smem_pipe(np);
  52         size_t len;
  53         void *fifo;
  54         u32 head;
  55         u32 tail;
  56 
  57         if (!pipe->fifo) {
  58                 fifo = qcom_smem_get(pipe->remote_pid,
  59                                      SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
  60                 if (IS_ERR(fifo)) {
  61                         pr_err("failed to acquire RX fifo handle: %ld\n",
  62                                PTR_ERR(fifo));
  63                         return 0;
  64                 }
  65 
  66                 pipe->fifo = fifo;
  67                 pipe->native.length = len;
  68         }
  69 
  70         head = le32_to_cpu(*pipe->head);
  71         tail = le32_to_cpu(*pipe->tail);
  72 
  73         if (head < tail)
  74                 return pipe->native.length - tail + head;
  75         else
  76                 return head - tail;
  77 }
  78 
  79 static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
  80                                void *data, unsigned int offset, size_t count)
  81 {
  82         struct glink_smem_pipe *pipe = to_smem_pipe(np);
  83         size_t len;
  84         u32 tail;
  85 
  86         tail = le32_to_cpu(*pipe->tail);
  87         tail += offset;
  88         if (tail >= pipe->native.length)
  89                 tail -= pipe->native.length;
  90 
  91         len = min_t(size_t, count, pipe->native.length - tail);
  92         if (len)
  93                 memcpy_fromio(data, pipe->fifo + tail, len);
  94 
  95         if (len != count)
  96                 memcpy_fromio(data + len, pipe->fifo, (count - len));
  97 }
  98 
  99 static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
 100                                   size_t count)
 101 {
 102         struct glink_smem_pipe *pipe = to_smem_pipe(np);
 103         u32 tail;
 104 
 105         tail = le32_to_cpu(*pipe->tail);
 106 
 107         tail += count;
 108         if (tail >= pipe->native.length)
 109                 tail -= pipe->native.length;
 110 
 111         *pipe->tail = cpu_to_le32(tail);
 112 }
 113 
 114 static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
 115 {
 116         struct glink_smem_pipe *pipe = to_smem_pipe(np);
 117         u32 head;
 118         u32 tail;
 119         u32 avail;
 120 
 121         head = le32_to_cpu(*pipe->head);
 122         tail = le32_to_cpu(*pipe->tail);
 123 
 124         if (tail <= head)
 125                 avail = pipe->native.length - head + tail;
 126         else
 127                 avail = tail - head;
 128 
 129         if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
 130                 avail = 0;
 131         else
 132                 avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
 133 
 134         return avail;
 135 }
 136 
 137 static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
 138                                             unsigned int head,
 139                                             const void *data, size_t count)
 140 {
 141         size_t len;
 142 
 143         len = min_t(size_t, count, pipe->native.length - head);
 144         if (len)
 145                 memcpy(pipe->fifo + head, data, len);
 146 
 147         if (len != count)
 148                 memcpy(pipe->fifo, data + len, count - len);
 149 
 150         head += count;
 151         if (head >= pipe->native.length)
 152                 head -= pipe->native.length;
 153 
 154         return head;
 155 }
 156 
 157 static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
 158                                 const void *hdr, size_t hlen,
 159                                 const void *data, size_t dlen)
 160 {
 161         struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
 162         unsigned int head;
 163 
 164         head = le32_to_cpu(*pipe->head);
 165 
 166         head = glink_smem_tx_write_one(pipe, head, hdr, hlen);
 167         head = glink_smem_tx_write_one(pipe, head, data, dlen);
 168 
 169         /* Ensure head is always aligned to 8 bytes */
 170         head = ALIGN(head, 8);
 171         if (head >= pipe->native.length)
 172                 head -= pipe->native.length;
 173 
 174         /* Ensure ordering of fifo and head update */
 175         wmb();
 176 
 177         *pipe->head = cpu_to_le32(head);
 178 }
 179 
 180 static void qcom_glink_smem_release(struct device *dev)
 181 {
 182         kfree(dev);
 183 }
 184 
 185 struct qcom_glink *qcom_glink_smem_register(struct device *parent,
 186                                             struct device_node *node)
 187 {
 188         struct glink_smem_pipe *rx_pipe;
 189         struct glink_smem_pipe *tx_pipe;
 190         struct qcom_glink *glink;
 191         struct device *dev;
 192         u32 remote_pid;
 193         __le32 *descs;
 194         size_t size;
 195         int ret;
 196 
 197         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 198         if (!dev)
 199                 return ERR_PTR(-ENOMEM);
 200 
 201         dev->parent = parent;
 202         dev->of_node = node;
 203         dev->release = qcom_glink_smem_release;
 204         dev_set_name(dev, "%s:%pOFn", dev_name(parent->parent), node);
 205         ret = device_register(dev);
 206         if (ret) {
 207                 pr_err("failed to register glink edge\n");
 208                 put_device(dev);
 209                 return ERR_PTR(ret);
 210         }
 211 
 212         ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
 213                                    &remote_pid);
 214         if (ret) {
 215                 dev_err(dev, "failed to parse qcom,remote-pid\n");
 216                 goto err_put_dev;
 217         }
 218 
 219         rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
 220         tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
 221         if (!rx_pipe || !tx_pipe) {
 222                 ret = -ENOMEM;
 223                 goto err_put_dev;
 224         }
 225 
 226         ret = qcom_smem_alloc(remote_pid,
 227                               SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32);
 228         if (ret && ret != -EEXIST) {
 229                 dev_err(dev, "failed to allocate glink descriptors\n");
 230                 goto err_put_dev;
 231         }
 232 
 233         descs = qcom_smem_get(remote_pid,
 234                               SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
 235         if (IS_ERR(descs)) {
 236                 dev_err(dev, "failed to acquire xprt descriptor\n");
 237                 ret = PTR_ERR(descs);
 238                 goto err_put_dev;
 239         }
 240 
 241         if (size != 32) {
 242                 dev_err(dev, "glink descriptor of invalid size\n");
 243                 ret = -EINVAL;
 244                 goto err_put_dev;
 245         }
 246 
 247         tx_pipe->tail = &descs[0];
 248         tx_pipe->head = &descs[1];
 249         rx_pipe->tail = &descs[2];
 250         rx_pipe->head = &descs[3];
 251 
 252         ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
 253                               SZ_16K);
 254         if (ret && ret != -EEXIST) {
 255                 dev_err(dev, "failed to allocate TX fifo\n");
 256                 goto err_put_dev;
 257         }
 258 
 259         tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
 260                                       &tx_pipe->native.length);
 261         if (IS_ERR(tx_pipe->fifo)) {
 262                 dev_err(dev, "failed to acquire TX fifo\n");
 263                 ret = PTR_ERR(tx_pipe->fifo);
 264                 goto err_put_dev;
 265         }
 266 
 267         rx_pipe->native.avail = glink_smem_rx_avail;
 268         rx_pipe->native.peak = glink_smem_rx_peak;
 269         rx_pipe->native.advance = glink_smem_rx_advance;
 270         rx_pipe->remote_pid = remote_pid;
 271 
 272         tx_pipe->native.avail = glink_smem_tx_avail;
 273         tx_pipe->native.write = glink_smem_tx_write;
 274         tx_pipe->remote_pid = remote_pid;
 275 
 276         *rx_pipe->tail = 0;
 277         *tx_pipe->head = 0;
 278 
 279         glink = qcom_glink_native_probe(dev,
 280                                         GLINK_FEATURE_INTENT_REUSE,
 281                                         &rx_pipe->native, &tx_pipe->native,
 282                                         false);
 283         if (IS_ERR(glink)) {
 284                 ret = PTR_ERR(glink);
 285                 goto err_put_dev;
 286         }
 287 
 288         return glink;
 289 
 290 err_put_dev:
 291         device_unregister(dev);
 292 
 293         return ERR_PTR(ret);
 294 }
 295 EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
 296 
 297 void qcom_glink_smem_unregister(struct qcom_glink *glink)
 298 {
 299         qcom_glink_native_remove(glink);
 300         qcom_glink_native_unregister(glink);
 301 }
 302 EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
 303 
 304 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
 305 MODULE_DESCRIPTION("Qualcomm GLINK SMEM driver");
 306 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */