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