saa7164: fix sparse warnings
[pandora-kernel.git] / drivers / media / video / 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 __iomem *)(dev->bmmio +
37                 ((u32)dev->busdesc.CommandRing));
38
39         b->m_dwSizeSetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
40
41         b->m_pdwGetRing         = (u8 __iomem *)(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         u16 size;
142
143         if (!msg) {
144                 printk(KERN_ERR "%s() !msg\n", __func__);
145                 return SAA_ERR_BAD_PARAMETER;
146         }
147
148         dprintk(DBGLVL_BUS, "%s()\n", __func__);
149
150         saa7164_bus_verify(dev);
151
152         if (msg->size > dev->bus.m_wMaxReqSize) {
153                 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
154                         __func__);
155                 return SAA_ERR_BAD_PARAMETER;
156         }
157
158         if ((msg->size > 0) && (buf == NULL)) {
159                 printk(KERN_ERR "%s() Missing message buffer\n", __func__);
160                 return SAA_ERR_BAD_PARAMETER;
161         }
162
163         /* Lock the bus from any other access */
164         mutex_lock(&bus->lock);
165
166         bytes_to_write = sizeof(*msg) + msg->size;
167         free_write_space = 0;
168         timeout = SAA_BUS_TIMEOUT;
169         curr_srp = saa7164_readl(bus->m_dwSetReadPos);
170         curr_swp = saa7164_readl(bus->m_dwSetWritePos);
171
172         /* Deal with ring wrapping issues */
173         if (curr_srp > curr_swp)
174                 /* Deal with the wrapped ring */
175                 free_write_space = curr_srp - curr_swp;
176         else
177                 /* The ring has not wrapped yet */
178                 free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
179
180         dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
181                 bytes_to_write);
182
183         dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
184                 free_write_space);
185
186         dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
187         dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
188
189         /* Process the msg and write the content onto the bus */
190         while (bytes_to_write >= free_write_space) {
191
192                 if (timeout-- == 0) {
193                         printk(KERN_ERR "%s() bus timeout\n", __func__);
194                         ret = SAA_ERR_NO_RESOURCES;
195                         goto out;
196                 }
197
198                 /* TODO: Review this delay, efficient? */
199                 /* Wait, allowing the hardware fetch time */
200                 mdelay(1);
201
202                 /* Check the space usage again */
203                 curr_srp = saa7164_readl(bus->m_dwSetReadPos);
204
205                 /* Deal with ring wrapping issues */
206                 if (curr_srp > curr_swp)
207                         /* Deal with the wrapped ring */
208                         free_write_space = curr_srp - curr_swp;
209                 else
210                         /* Read didn't wrap around the buffer */
211                         free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
212                                 curr_swp;
213
214         }
215
216         /* Calculate the new write position */
217         new_swp = curr_swp + bytes_to_write;
218
219         dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
220         dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
221                 bus->m_dwSizeSetRing);
222
223         /*
224          * Make a copy of msg->size before it is converted to le16 since it is
225          * used in the code below.
226          */
227         size = msg->size;
228         /* Convert to le16/le32 */
229         msg->size = (__force u16)cpu_to_le16(msg->size);
230         msg->command = (__force u32)cpu_to_le32(msg->command);
231         msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
232
233         /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
234
235         /* Check if we're going to wrap again */
236         if (new_swp > bus->m_dwSizeSetRing) {
237
238                 /* Ring wraps */
239                 new_swp -= bus->m_dwSizeSetRing;
240
241                 space_rem = bus->m_dwSizeSetRing - curr_swp;
242
243                 dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
244                         space_rem);
245
246                 dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
247                         (u32)sizeof(*msg));
248
249                 if (space_rem < sizeof(*msg)) {
250                         dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
251
252                         /* Split the msg into pieces as the ring wraps */
253                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
254                         memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
255                                 sizeof(*msg) - space_rem);
256
257                         memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
258                                 buf, size);
259
260                 } else if (space_rem == sizeof(*msg)) {
261                         dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
262
263                         /* Additional data at the beginning of the ring */
264                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
265                         memcpy_toio(bus->m_pdwSetRing, buf, size);
266
267                 } else {
268                         /* Additional data wraps around the ring */
269                         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
270                         if (size > 0) {
271                                 memcpy_toio(bus->m_pdwSetRing + curr_swp +
272                                         sizeof(*msg), buf, space_rem -
273                                         sizeof(*msg));
274                                 memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
275                                         space_rem - sizeof(*msg),
276                                         bytes_to_write - space_rem);
277                         }
278
279                 }
280
281         } /* (new_swp > bus->m_dwSizeSetRing) */
282         else {
283                 dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
284
285                 /* The ring buffer doesn't wrap, two simple copies */
286                 memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
287                 memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
288                         size);
289         }
290
291         dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
292
293         /* Update the bus write position */
294         saa7164_writel(bus->m_dwSetWritePos, new_swp);
295
296         /* Convert back to cpu after writing the msg to the ringbuffer. */
297         msg->size = le16_to_cpu((__force __le16)msg->size);
298         msg->command = le32_to_cpu((__force __le32)msg->command);
299         msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
300         ret = SAA_OK;
301
302 out:
303         saa7164_bus_dump(dev);
304         mutex_unlock(&bus->lock);
305         saa7164_bus_verify(dev);
306         return ret;
307 }
308
309 /*
310  * Receive a command or a response from the bus. The implementation does not
311  * know if it is a command or a response it simply dequeues the data,
312  * depending on the bus information given in the struct tmComResBusInfo
313  * structure.
314  *
315  * Return Value:
316  *  0          The function executed successfully.
317  *  < 0        One or more members are not initialized.
318  */
319 int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
320         void *buf, int peekonly)
321 {
322         struct tmComResBusInfo *bus = &dev->bus;
323         u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
324                 new_grp, buf_size, space_rem;
325         struct tmComResInfo msg_tmp;
326         int ret = SAA_ERR_BAD_PARAMETER;
327
328         saa7164_bus_verify(dev);
329
330         if (msg == NULL)
331                 return ret;
332
333         if (msg->size > dev->bus.m_wMaxReqSize) {
334                 printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
335                         __func__);
336                 return ret;
337         }
338
339         if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
340                 printk(KERN_ERR
341                         "%s() Missing msg buf, size should be %d bytes\n",
342                         __func__, msg->size);
343                 return ret;
344         }
345
346         mutex_lock(&bus->lock);
347
348         /* Peek the bus to see if a msg exists, if it's not what we're expecting
349          * then return cleanly else read the message from the bus.
350          */
351         curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
352         curr_grp = saa7164_readl(bus->m_dwGetReadPos);
353
354         if (curr_gwp == curr_grp) {
355                 ret = SAA_ERR_EMPTY;
356                 goto out;
357         }
358
359         bytes_to_read = sizeof(*msg);
360
361         /* Calculate write distance to current read position */
362         write_distance = 0;
363         if (curr_gwp >= curr_grp)
364                 /* Write doesn't wrap around the ring */
365                 write_distance = curr_gwp - curr_grp;
366         else
367                 /* Write wraps around the ring */
368                 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
369
370         if (bytes_to_read > write_distance) {
371                 printk(KERN_ERR "%s() No message/response found\n", __func__);
372                 ret = SAA_ERR_INVALID_COMMAND;
373                 goto out;
374         }
375
376         /* Calculate the new read position */
377         new_grp = curr_grp + bytes_to_read;
378         if (new_grp > bus->m_dwSizeGetRing) {
379
380                 /* Ring wraps */
381                 new_grp -= bus->m_dwSizeGetRing;
382                 space_rem = bus->m_dwSizeGetRing - curr_grp;
383
384                 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
385                 memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
386                         bytes_to_read - space_rem);
387
388         } else {
389                 /* No wrapping */
390                 memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
391         }
392         /* Convert from little endian to CPU */
393         msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
394         msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
395         msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
396
397         /* No need to update the read positions, because this was a peek */
398         /* If the caller specifically want to peek, return */
399         if (peekonly) {
400                 memcpy(msg, &msg_tmp, sizeof(*msg));
401                 goto peekout;
402         }
403
404         /* Check if the command/response matches what is expected */
405         if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
406                 (msg_tmp.controlselector != msg->controlselector) ||
407                 (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
408
409                 printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
410                 saa7164_bus_dumpmsg(dev, msg, buf);
411                 saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
412                 ret = SAA_ERR_INVALID_COMMAND;
413                 goto out;
414         }
415
416         /* Get the actual command and response from the bus */
417         buf_size = msg->size;
418
419         bytes_to_read = sizeof(*msg) + msg->size;
420         /* Calculate write distance to current read position */
421         write_distance = 0;
422         if (curr_gwp >= curr_grp)
423                 /* Write doesn't wrap around the ring */
424                 write_distance = curr_gwp - curr_grp;
425         else
426                 /* Write wraps around the ring */
427                 write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
428
429         if (bytes_to_read > write_distance) {
430                 printk(KERN_ERR "%s() Invalid bus state, missing msg "
431                         "or mangled ring, faulty H/W / bad code?\n", __func__);
432                 ret = SAA_ERR_INVALID_COMMAND;
433                 goto out;
434         }
435
436         /* Calculate the new read position */
437         new_grp = curr_grp + bytes_to_read;
438         if (new_grp > bus->m_dwSizeGetRing) {
439
440                 /* Ring wraps */
441                 new_grp -= bus->m_dwSizeGetRing;
442                 space_rem = bus->m_dwSizeGetRing - curr_grp;
443
444                 if (space_rem < sizeof(*msg)) {
445                         /* msg wraps around the ring */
446                         memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem);
447                         memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing,
448                                 sizeof(*msg) - space_rem);
449                         if (buf)
450                                 memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
451                                         space_rem, buf_size);
452
453                 } else if (space_rem == sizeof(*msg)) {
454                         memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
455                         if (buf)
456                                 memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
457                 } else {
458                         /* Additional data wraps around the ring */
459                         memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
460                         if (buf) {
461                                 memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
462                                         sizeof(*msg), space_rem - sizeof(*msg));
463                                 memcpy_fromio(buf + space_rem - sizeof(*msg),
464                                         bus->m_pdwGetRing, bytes_to_read -
465                                         space_rem);
466                         }
467
468                 }
469
470         } else {
471                 /* No wrapping */
472                 memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
473                 if (buf)
474                         memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
475                                 buf_size);
476         }
477         /* Convert from little endian to CPU */
478         msg->size = le16_to_cpu((__force __le16)msg->size);
479         msg->command = le32_to_cpu((__force __le32)msg->command);
480         msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
481
482         /* Update the read positions, adjusting the ring */
483         saa7164_writel(bus->m_dwGetReadPos, new_grp);
484
485 peekout:
486         ret = SAA_OK;
487 out:
488         mutex_unlock(&bus->lock);
489         saa7164_bus_verify(dev);
490         return ret;
491 }
492