Merge tag 'bitmap-for-6.9' of https://github.com/norov/linux
[linux-2.6-microblaze.git] / drivers / rpmsg / qcom_glink_smem.c
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/of_irq.h>
11 #include <linux/interrupt.h>
12 #include <linux/platform_device.h>
13 #include <linux/mailbox_client.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/slab.h>
16 #include <linux/rpmsg.h>
17 #include <linux/idr.h>
18 #include <linux/circ_buf.h>
19 #include <linux/soc/qcom/smem.h>
20 #include <linux/sizes.h>
21 #include <linux/delay.h>
22 #include <linux/regmap.h>
23 #include <linux/workqueue.h>
24 #include <linux/list.h>
25
26 #include <linux/rpmsg/qcom_glink.h>
27
28 #include "qcom_glink_native.h"
29
30 #define FIFO_FULL_RESERVE 8
31 #define FIFO_ALIGNMENT 8
32 #define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
33
34 #define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR       478
35 #define SMEM_GLINK_NATIVE_XPRT_FIFO_0           479
36 #define SMEM_GLINK_NATIVE_XPRT_FIFO_1           480
37
38 struct qcom_glink_smem {
39         struct device dev;
40
41         int irq;
42         struct qcom_glink *glink;
43
44         struct mbox_client mbox_client;
45         struct mbox_chan *mbox_chan;
46
47         u32 remote_pid;
48 };
49
50 struct glink_smem_pipe {
51         struct qcom_glink_pipe native;
52
53         __le32 *tail;
54         __le32 *head;
55
56         void *fifo;
57
58         struct qcom_glink_smem *smem;
59 };
60
61 #define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
62
63 static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
64 {
65         struct glink_smem_pipe *pipe = to_smem_pipe(np);
66         struct qcom_glink_smem *smem = pipe->smem;
67         size_t len;
68         void *fifo;
69         u32 head;
70         u32 tail;
71
72         if (!pipe->fifo) {
73                 fifo = qcom_smem_get(smem->remote_pid,
74                                      SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
75                 if (IS_ERR(fifo)) {
76                         pr_err("failed to acquire RX fifo handle: %ld\n",
77                                PTR_ERR(fifo));
78                         return 0;
79                 }
80
81                 pipe->fifo = fifo;
82                 pipe->native.length = len;
83         }
84
85         head = le32_to_cpu(*pipe->head);
86         tail = le32_to_cpu(*pipe->tail);
87
88         if (head < tail)
89                 return pipe->native.length - tail + head;
90         else
91                 return head - tail;
92 }
93
94 static void glink_smem_rx_peek(struct qcom_glink_pipe *np,
95                                void *data, unsigned int offset, size_t count)
96 {
97         struct glink_smem_pipe *pipe = to_smem_pipe(np);
98         size_t len;
99         u32 tail;
100
101         tail = le32_to_cpu(*pipe->tail);
102         tail += offset;
103         if (tail >= pipe->native.length)
104                 tail -= pipe->native.length;
105
106         len = min_t(size_t, count, pipe->native.length - tail);
107         if (len)
108                 memcpy_fromio(data, pipe->fifo + tail, len);
109
110         if (len != count)
111                 memcpy_fromio(data + len, pipe->fifo, (count - len));
112 }
113
114 static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
115                                   size_t count)
116 {
117         struct glink_smem_pipe *pipe = to_smem_pipe(np);
118         u32 tail;
119
120         tail = le32_to_cpu(*pipe->tail);
121
122         tail += count;
123         if (tail >= pipe->native.length)
124                 tail -= pipe->native.length;
125
126         *pipe->tail = cpu_to_le32(tail);
127 }
128
129 static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
130 {
131         struct glink_smem_pipe *pipe = to_smem_pipe(np);
132         u32 head;
133         u32 tail;
134         u32 avail;
135
136         head = le32_to_cpu(*pipe->head);
137         tail = le32_to_cpu(*pipe->tail);
138
139         if (tail <= head)
140                 avail = pipe->native.length - head + tail;
141         else
142                 avail = tail - head;
143
144         if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
145                 avail = 0;
146         else
147                 avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
148
149         return avail;
150 }
151
152 static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
153                                             unsigned int head,
154                                             const void *data, size_t count)
155 {
156         size_t len;
157
158         len = min_t(size_t, count, pipe->native.length - head);
159         if (len)
160                 memcpy(pipe->fifo + head, data, len);
161
162         if (len != count)
163                 memcpy(pipe->fifo, data + len, count - len);
164
165         head += count;
166         if (head >= pipe->native.length)
167                 head -= pipe->native.length;
168
169         return head;
170 }
171
172 static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
173                                 const void *hdr, size_t hlen,
174                                 const void *data, size_t dlen)
175 {
176         struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
177         unsigned int head;
178
179         head = le32_to_cpu(*pipe->head);
180
181         head = glink_smem_tx_write_one(pipe, head, hdr, hlen);
182         head = glink_smem_tx_write_one(pipe, head, data, dlen);
183
184         /* Ensure head is always aligned to 8 bytes */
185         head = ALIGN(head, 8);
186         if (head >= pipe->native.length)
187                 head -= pipe->native.length;
188
189         /* Ensure ordering of fifo and head update */
190         wmb();
191
192         *pipe->head = cpu_to_le32(head);
193 }
194
195 static void glink_smem_tx_kick(struct qcom_glink_pipe *glink_pipe)
196 {
197         struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
198         struct qcom_glink_smem *smem = pipe->smem;
199
200         mbox_send_message(smem->mbox_chan, NULL);
201         mbox_client_txdone(smem->mbox_chan, 0);
202 }
203
204 static irqreturn_t qcom_glink_smem_intr(int irq, void *data)
205 {
206         struct qcom_glink_smem *smem = data;
207
208         qcom_glink_native_rx(smem->glink);
209
210         return IRQ_HANDLED;
211 }
212
213 static void qcom_glink_smem_release(struct device *dev)
214 {
215         struct qcom_glink_smem *smem = container_of(dev, struct qcom_glink_smem, dev);
216
217         kfree(smem);
218 }
219
220 struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent,
221                                                  struct device_node *node)
222 {
223         struct glink_smem_pipe *rx_pipe;
224         struct glink_smem_pipe *tx_pipe;
225         struct qcom_glink_smem *smem;
226         struct qcom_glink *glink;
227         struct device *dev;
228         u32 remote_pid;
229         __le32 *descs;
230         size_t size;
231         int ret;
232
233         smem = kzalloc(sizeof(*smem), GFP_KERNEL);
234         if (!smem)
235                 return ERR_PTR(-ENOMEM);
236
237         dev = &smem->dev;
238
239         dev->parent = parent;
240         dev->of_node = node;
241         dev->release = qcom_glink_smem_release;
242         dev_set_name(dev, "%s:%pOFn", dev_name(parent->parent), node);
243         ret = device_register(dev);
244         if (ret) {
245                 pr_err("failed to register glink edge\n");
246                 put_device(dev);
247                 return ERR_PTR(ret);
248         }
249
250         ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
251                                    &remote_pid);
252         if (ret) {
253                 dev_err(dev, "failed to parse qcom,remote-pid\n");
254                 goto err_put_dev;
255         }
256
257         smem->remote_pid = remote_pid;
258
259         rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
260         tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
261         if (!rx_pipe || !tx_pipe) {
262                 ret = -ENOMEM;
263                 goto err_put_dev;
264         }
265
266         ret = qcom_smem_alloc(remote_pid,
267                               SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32);
268         if (ret && ret != -EEXIST) {
269                 dev_err(dev, "failed to allocate glink descriptors\n");
270                 goto err_put_dev;
271         }
272
273         descs = qcom_smem_get(remote_pid,
274                               SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
275         if (IS_ERR(descs)) {
276                 dev_err(dev, "failed to acquire xprt descriptor\n");
277                 ret = PTR_ERR(descs);
278                 goto err_put_dev;
279         }
280
281         if (size != 32) {
282                 dev_err(dev, "glink descriptor of invalid size\n");
283                 ret = -EINVAL;
284                 goto err_put_dev;
285         }
286
287         tx_pipe->tail = &descs[0];
288         tx_pipe->head = &descs[1];
289         rx_pipe->tail = &descs[2];
290         rx_pipe->head = &descs[3];
291
292         ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
293                               SZ_16K);
294         if (ret && ret != -EEXIST) {
295                 dev_err(dev, "failed to allocate TX fifo\n");
296                 goto err_put_dev;
297         }
298
299         tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
300                                       &tx_pipe->native.length);
301         if (IS_ERR(tx_pipe->fifo)) {
302                 dev_err(dev, "failed to acquire TX fifo\n");
303                 ret = PTR_ERR(tx_pipe->fifo);
304                 goto err_put_dev;
305         }
306
307         smem->irq = of_irq_get(smem->dev.of_node, 0);
308         ret = devm_request_irq(&smem->dev, smem->irq, qcom_glink_smem_intr,
309                                IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
310                                "glink-smem", smem);
311         if (ret) {
312                 dev_err(&smem->dev, "failed to request IRQ\n");
313                 goto err_put_dev;
314         }
315
316         smem->mbox_client.dev = &smem->dev;
317         smem->mbox_client.knows_txdone = true;
318         smem->mbox_chan = mbox_request_channel(&smem->mbox_client, 0);
319         if (IS_ERR(smem->mbox_chan)) {
320                 ret = dev_err_probe(&smem->dev, PTR_ERR(smem->mbox_chan),
321                                     "failed to acquire IPC channel\n");
322                 goto err_put_dev;
323         }
324
325         rx_pipe->smem = smem;
326         rx_pipe->native.avail = glink_smem_rx_avail;
327         rx_pipe->native.peek = glink_smem_rx_peek;
328         rx_pipe->native.advance = glink_smem_rx_advance;
329
330         tx_pipe->smem = smem;
331         tx_pipe->native.avail = glink_smem_tx_avail;
332         tx_pipe->native.write = glink_smem_tx_write;
333         tx_pipe->native.kick = glink_smem_tx_kick;
334
335         *rx_pipe->tail = 0;
336         *tx_pipe->head = 0;
337
338         glink = qcom_glink_native_probe(dev,
339                                         GLINK_FEATURE_INTENT_REUSE,
340                                         &rx_pipe->native, &tx_pipe->native,
341                                         false);
342         if (IS_ERR(glink)) {
343                 ret = PTR_ERR(glink);
344                 goto err_free_mbox;
345         }
346
347         smem->glink = glink;
348
349         enable_irq(smem->irq);
350
351         return smem;
352
353 err_free_mbox:
354         mbox_free_channel(smem->mbox_chan);
355
356 err_put_dev:
357         device_unregister(dev);
358
359         return ERR_PTR(ret);
360 }
361 EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
362
363 void qcom_glink_smem_unregister(struct qcom_glink_smem *smem)
364 {
365         struct qcom_glink *glink = smem->glink;
366
367         disable_irq(smem->irq);
368
369         qcom_glink_native_remove(glink);
370
371         mbox_free_channel(smem->mbox_chan);
372         device_unregister(&smem->dev);
373 }
374 EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
375
376 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
377 MODULE_DESCRIPTION("Qualcomm GLINK SMEM driver");
378 MODULE_LICENSE("GPL v2");