Merge tag 'armsoc-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[sfrench/cifs-2.6.git] / drivers / media / pci / saa7164 / saa7164-bus.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Driver for the NXP SAA7164 PCIe bridge
4  *
5  *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
6  */
7
8 #include "saa7164.h"
9
10 /* The message bus to/from the firmware is a ring buffer in PCI address
11  * space. Establish the defaults.
12  */
13 int saa7164_bus_setup(struct saa7164_dev *dev)
14 {
15         struct tmComResBusInfo *b       = &dev->bus;
16
17         mutex_init(&b->lock);
18
19         b->Type                 = TYPE_BUS_PCIe;
20         b->m_wMaxReqSize        = SAA_DEVICE_MAXREQUESTSIZE;
21
22         b->m_pdwSetRing         = (u8 __iomem *)(dev->bmmio +
23                 ((u32)dev->busdesc.CommandRing));
24
25         b->m_dwSizeSetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
26
27         b->m_pdwGetRing         = (u8 __iomem *)(dev->bmmio +
28                 ((u32)dev->busdesc.ResponseRing));
29
30         b->m_dwSizeGetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
31
32         b->m_dwSetWritePos      = ((u32)dev->intfdesc.BARLocation) +
33                 (2 * sizeof(u64));
34         b->m_dwSetReadPos       = b->m_dwSetWritePos + (1 * sizeof(u32));
35
36         b->m_dwGetWritePos      = b->m_dwSetWritePos + (2 * sizeof(u32));
37         b->m_dwGetReadPos       = b->m_dwSetWritePos + (3 * sizeof(u32));
38
39         return 0;
40 }
41
42 void saa7164_bus_dump(struct saa7164_dev *dev)
43 {
44         struct tmComResBusInfo *b = &dev->bus;
45
46         dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
47         dprintk(DBGLVL_BUS, " .type             = %d\n", b->Type);
48         dprintk(DBGLVL_BUS, " .dev->bmmio       = 0x%p\n", dev->bmmio);
49         dprintk(DBGLVL_BUS, " .m_wMaxReqSize    = 0x%x\n", b->m_wMaxReqSize);
50         dprintk(DBGLVL_BUS, " .m_pdwSetRing     = 0x%p\n", b->m_pdwSetRing);
51         dprintk(DBGLVL_BUS, " .m_dwSizeSetRing  = 0x%x\n", b->m_dwSizeSetRing);
52         dprintk(DBGLVL_BUS, " .m_pdwGetRing     = 0x%p\n", b->m_pdwGetRing);
53         dprintk(DBGLVL_BUS, " .m_dwSizeGetRing  = 0x%x\n", b->m_dwSizeGetRing);
54
55         dprintk(DBGLVL_BUS, " .m_dwSetReadPos   = 0x%x (0x%08x)\n",
56                 b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
57
58         dprintk(DBGLVL_BUS, " .m_dwSetWritePos  = 0x%x (0x%08x)\n",
59                 b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
60
61         dprintk(DBGLVL_BUS, " .m_dwGetReadPos   = 0x%x (0x%08x)\n",
62                 b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
63
64         dprintk(DBGLVL_BUS, " .m_dwGetWritePos  = 0x%x (0x%08x)\n",
65                 b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
66
67 }
68
69 /* Intensionally throw a BUG() if the state of the message bus looks corrupt */
70 static void saa7164_bus_verify(struct saa7164_dev *dev)
71 {
72         struct tmComResBusInfo *b = &dev->bus;
73         int bug = 0;
74
75         if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
76                 bug++;
77
78         if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
79                 bug++;
80
81         if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
82                 bug++;
83
84         if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
85                 bug++;
86
87         if (bug) {
88                 saa_debug = 0xffff; /* Ensure we get the bus dump */
89                 saa7164_bus_dump(dev);
90                 saa_debug = 1024; /* Ensure we get the bus dump */
91                 BUG();
92         }
93 }
94
95 static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m,
96                                 void *buf)
97 {
98         dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
99         dprintk(DBGLVL_BUS, " .id               = %d\n",   m->id);
100         dprintk(DBGLVL_BUS, " .flags            = 0x%x\n", m->flags);
101         dprintk(DBGLVL_BUS, " .size             = 0x%x\n", m->size);
102         dprintk(DBGLVL_BUS, " .command          = 0x%x\n", m->command);
103         dprintk(DBGLVL_BUS, " .controlselector  = 0x%x\n", m->controlselector);
104         dprintk(DBGLVL_BUS, " .seqno            = %d\n",   m->seqno);
105         if (buf)
106                 dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
107 }
108
109 /*
110  * Places a command or a response on the bus. The implementation does not
111  * know if it is a command or a response it just places the data on the
112  * bus depending on the bus information given in the struct tmComResBusInfo
113  * structure. If the command or response does not fit into the bus ring
114  * buffer it will be refused.
115  *
116  * Return Value:
117  *  SAA_OK     The function executed successfully.
118  *  < 0        One or more members are not initialized.
119  */
120 int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
121         void *buf)
122 {
123         struct tmComResBusInfo *bus = &dev->bus;
124         u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
125         u32 new_swp, space_rem;
126         int ret = SAA_ERR_BAD_PARAMETER;
127         u16 size;
128
129         if (!msg) {
130                 printk(KERN_ERR "%s() !msg\n", __func__);
131                 return SAA_ERR_BAD_PARAMETER;
132         }
133
134         dprintk(DBGLVL_BUS, "%s()\n", __func__);
135
136         saa7164_bus_verify(dev);
137
138         if (msg->size > dev->bus.m_wMaxReqSize) {
139                 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
140                         __func__);
141                 return SAA_ERR_BAD_PARAMETER;
142         }
143
144         if ((msg->size > 0) && (buf == NULL)) {
145                 printk(KERN_ERR "%s() Missing message buffer\n", __func__);
146                 return SAA_ERR_BAD_PARAMETER;
147         }
148
149         /* Lock the bus from any other access */
150         mutex_lock(&bus->lock);
151
152         bytes_to_write = sizeof(*msg) + msg->size;
153         free_write_space = 0;
154         timeout = SAA_BUS_TIMEOUT;
155         curr_srp = saa7164_readl(bus->m_dwSetReadPos);
156         curr_swp = saa7164_readl(bus->m_dwSetWritePos);
157
158         /* Deal with ring wrapping issues */
159         if (curr_srp > curr_swp)
160                 /* Deal with the wrapped ring */
161                 free_write_space = curr_srp - curr_swp;
162         else
163                 /* The ring has not wrapped yet */
164                 free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
165
166         dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
167                 bytes_to_write);
168
169         dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
170                 free_write_space);
171
172         dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
173         dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
174
175         /* Process the msg and write the content onto the bus */
176         while (bytes_to_write >= free_write_space) {
177
178                 if (timeout-- == 0) {
179                         printk(KERN_ERR "%s() bus timeout\n", __func__);
180                         ret = SAA_ERR_NO_RESOURCES;
181                         goto out;
182                 }
183
184                 /* TODO: Review this delay, efficient? */
185                 /* Wait, allowing the hardware fetch time */
186                 mdelay(1);
187
188                 /* Check the space usage again */
189                 curr_srp = saa7164_readl(bus->m_dwSetReadPos);
190
191                 /* Deal with ring wrapping issues */
192                 if (curr_srp > curr_swp)
193                         /* Deal with the wrapped ring */
194                         free_write_space = curr_srp - curr_swp;
195                 else
196                         /* Read didn't wrap around the buffer */
197                         free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
198                                 curr_swp;
199
200         }
201
202         /* Calculate the new write position */
203         new_swp = curr_swp + bytes_to_write;
204
205         dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
206         dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
207                 bus->m_dwSizeSetRing);
208
209         /*
210          * Make a copy of msg->size before it is converted to le16 since it is
211          * used in the code below.
212          */
213         size = msg->size;
214         /* Convert to le16/le32 */
215         msg->size = (__force u16)cpu_to_le16(msg->size);
216         msg->command = (__force u32)cpu_to_le32(msg->command);
217         msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
218
219         /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
220
221         /* Check if we're going to wrap again */
222         if (new_swp > bus->m_dwSizeSetRing) {
223
224                 /* Ring wraps */
225                 new_swp -= bus->m_dwSizeSetRing;
226
227                 space_rem = bus->m_dwSizeSetRing - curr_swp;
228
229                 dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
230                         space_rem);
231
232                 dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
233                         (u32)sizeof(*msg));
234
235                 if (space_rem < sizeof(*msg)) {
236                         dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
237
238                         /* Split the msg into pieces as the ring wraps */
239                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
240                         memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
241                                 sizeof(*msg) - space_rem);
242
243                         memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
244                                 buf, size);
245
246                 } else if (space_rem == sizeof(*msg)) {
247                         dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
248
249                         /* Additional data at the beginning of the ring */
250                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
251                         memcpy_toio(bus->m_pdwSetRing, buf, size);
252
253                 } else {
254                         /* Additional data wraps around the ring */
255                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
256                         if (size > 0) {
257                                 memcpy_toio(bus->m_pdwSetRing + curr_swp +
258                                         sizeof(*msg), buf, space_rem -
259                                         sizeof(*msg));
260                                 memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
261                                         space_rem - sizeof(*msg),
262                                         bytes_to_write - space_rem);
263                         }
264
265                 }
266
267         } /* (new_swp > bus->m_dwSizeSetRing) */
268         else {
269                 dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
270
271                 /* The ring buffer doesn't wrap, two simple copies */
272                 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
273                 memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
274                         size);
275         }
276
277         dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
278
279         /* Update the bus write position */
280         saa7164_writel(bus->m_dwSetWritePos, new_swp);
281
282         /* Convert back to cpu after writing the msg to the ringbuffer. */
283         msg->size = le16_to_cpu((__force __le16)msg->size);
284         msg->command = le32_to_cpu((__force __le32)msg->command);
285         msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
286         ret = SAA_OK;
287
288 out:
289         saa7164_bus_dump(dev);
290         mutex_unlock(&bus->lock);
291         saa7164_bus_verify(dev);
292         return ret;
293 }
294
295 /*
296  * Receive a command or a response from the bus. The implementation does not
297  * know if it is a command or a response it simply dequeues the data,
298  * depending on the bus information given in the struct tmComResBusInfo
299  * structure.
300  *
301  * Return Value:
302  *  0          The function executed successfully.
303  *  < 0        One or more members are not initialized.
304  */
305 int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
306         void *buf, int peekonly)
307 {
308         struct tmComResBusInfo *bus = &dev->bus;
309         u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
310                 new_grp, buf_size, space_rem;
311         struct tmComResInfo msg_tmp;
312         int ret = SAA_ERR_BAD_PARAMETER;
313
314         saa7164_bus_verify(dev);
315
316         if (msg == NULL)
317                 return ret;
318
319         if (msg->size > dev->bus.m_wMaxReqSize) {
320                 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
321                         __func__);
322                 return ret;
323         }
324
325         if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
326                 printk(KERN_ERR
327                         "%s() Missing msg buf, size should be %d bytes\n",
328                         __func__, msg->size);
329                 return ret;
330         }
331
332         mutex_lock(&bus->lock);
333
334         /* Peek the bus to see if a msg exists, if it's not what we're expecting
335          * then return cleanly else read the message from the bus.
336          */
337         curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
338         curr_grp = saa7164_readl(bus->m_dwGetReadPos);
339
340         if (curr_gwp == curr_grp) {
341                 ret = SAA_ERR_EMPTY;
342                 goto out;
343         }
344
345         bytes_to_read = sizeof(*msg);
346
347         /* Calculate write distance to current read position */
348         write_distance = 0;
349         if (curr_gwp >= curr_grp)
350                 /* Write doesn't wrap around the ring */
351                 write_distance = curr_gwp - curr_grp;
352         else
353                 /* Write wraps around the ring */
354                 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
355
356         if (bytes_to_read > write_distance) {
357                 printk(KERN_ERR "%s() No message/response found\n", __func__);
358                 ret = SAA_ERR_INVALID_COMMAND;
359                 goto out;
360         }
361
362         /* Calculate the new read position */
363         new_grp = curr_grp + bytes_to_read;
364         if (new_grp > bus->m_dwSizeGetRing) {
365
366                 /* Ring wraps */
367                 new_grp -= bus->m_dwSizeGetRing;
368                 space_rem = bus->m_dwSizeGetRing - curr_grp;
369
370                 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
371                 memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
372                         bytes_to_read - space_rem);
373
374         } else {
375                 /* No wrapping */
376                 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
377         }
378         /* Convert from little endian to CPU */
379         msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
380         msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
381         msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
382         memcpy(msg, &msg_tmp, sizeof(*msg));
383
384         /* No need to update the read positions, because this was a peek */
385         /* If the caller specifically want to peek, return */
386         if (peekonly) {
387                 goto peekout;
388         }
389
390         /* Check if the command/response matches what is expected */
391         if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
392                 (msg_tmp.controlselector != msg->controlselector) ||
393                 (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
394
395                 printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
396                 saa7164_bus_dumpmsg(dev, msg, buf);
397                 saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
398                 ret = SAA_ERR_INVALID_COMMAND;
399                 goto out;
400         }
401
402         /* Get the actual command and response from the bus */
403         buf_size = msg->size;
404
405         bytes_to_read = sizeof(*msg) + msg->size;
406         /* Calculate write distance to current read position */
407         write_distance = 0;
408         if (curr_gwp >= curr_grp)
409                 /* Write doesn't wrap around the ring */
410                 write_distance = curr_gwp - curr_grp;
411         else
412                 /* Write wraps around the ring */
413                 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
414
415         if (bytes_to_read > write_distance) {
416                 printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n",
417                        __func__);
418                 ret = SAA_ERR_INVALID_COMMAND;
419                 goto out;
420         }
421
422         /* Calculate the new read position */
423         new_grp = curr_grp + bytes_to_read;
424         if (new_grp > bus->m_dwSizeGetRing) {
425
426                 /* Ring wraps */
427                 new_grp -= bus->m_dwSizeGetRing;
428                 space_rem = bus->m_dwSizeGetRing - curr_grp;
429
430                 if (space_rem < sizeof(*msg)) {
431                         if (buf)
432                                 memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
433                                         space_rem, buf_size);
434
435                 } else if (space_rem == sizeof(*msg)) {
436                         if (buf)
437                                 memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
438                 } else {
439                         /* Additional data wraps around the ring */
440                         if (buf) {
441                                 memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
442                                         sizeof(*msg), space_rem - sizeof(*msg));
443                                 memcpy_fromio(buf + space_rem - sizeof(*msg),
444                                         bus->m_pdwGetRing, bytes_to_read -
445                                         space_rem);
446                         }
447
448                 }
449
450         } else {
451                 /* No wrapping */
452                 if (buf)
453                         memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
454                                 buf_size);
455         }
456
457         /* Update the read positions, adjusting the ring */
458         saa7164_writel(bus->m_dwGetReadPos, new_grp);
459
460 peekout:
461         ret = SAA_OK;
462 out:
463         mutex_unlock(&bus->lock);
464         saa7164_bus_verify(dev);
465         return ret;
466 }
467