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