2 * Driver for the NXP SAA7164 PCIe bridge
4 * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
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.
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
15 * GNU General Public License for more details.
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.
24 /* The message bus to/from the firmware is a ring buffer in PCI address
25 * space. Establish the defaults.
27 int saa7164_bus_setup(struct saa7164_dev
*dev
)
29 struct tmComResBusInfo
*b
= &dev
->bus
;
33 b
->Type
= TYPE_BUS_PCIe
;
34 b
->m_wMaxReqSize
= SAA_DEVICE_MAXREQUESTSIZE
;
36 b
->m_pdwSetRing
= (u8 __iomem
*)(dev
->bmmio
+
37 ((u32
)dev
->busdesc
.CommandRing
));
39 b
->m_dwSizeSetRing
= SAA_DEVICE_BUFFERBLOCKSIZE
;
41 b
->m_pdwGetRing
= (u8 __iomem
*)(dev
->bmmio
+
42 ((u32
)dev
->busdesc
.ResponseRing
));
44 b
->m_dwSizeGetRing
= SAA_DEVICE_BUFFERBLOCKSIZE
;
46 b
->m_dwSetWritePos
= ((u32
)dev
->intfdesc
.BARLocation
) +
48 b
->m_dwSetReadPos
= b
->m_dwSetWritePos
+ (1 * sizeof(u32
));
50 b
->m_dwGetWritePos
= b
->m_dwSetWritePos
+ (2 * sizeof(u32
));
51 b
->m_dwGetReadPos
= b
->m_dwSetWritePos
+ (3 * sizeof(u32
));
56 void saa7164_bus_dump(struct saa7164_dev
*dev
)
58 struct tmComResBusInfo
*b
= &dev
->bus
;
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
);
69 dprintk(DBGLVL_BUS
, " .m_dwSetReadPos = 0x%x (0x%08x)\n",
70 b
->m_dwSetReadPos
, saa7164_readl(b
->m_dwSetReadPos
));
72 dprintk(DBGLVL_BUS
, " .m_dwSetWritePos = 0x%x (0x%08x)\n",
73 b
->m_dwSetWritePos
, saa7164_readl(b
->m_dwSetWritePos
));
75 dprintk(DBGLVL_BUS
, " .m_dwGetReadPos = 0x%x (0x%08x)\n",
76 b
->m_dwGetReadPos
, saa7164_readl(b
->m_dwGetReadPos
));
78 dprintk(DBGLVL_BUS
, " .m_dwGetWritePos = 0x%x (0x%08x)\n",
79 b
->m_dwGetWritePos
, saa7164_readl(b
->m_dwGetWritePos
));
83 /* Intensionally throw a BUG() if the state of the message bus looks corrupt */
84 static void saa7164_bus_verify(struct saa7164_dev
*dev
)
86 struct tmComResBusInfo
*b
= &dev
->bus
;
89 if (saa7164_readl(b
->m_dwSetReadPos
) > b
->m_dwSizeSetRing
)
92 if (saa7164_readl(b
->m_dwSetWritePos
) > b
->m_dwSizeSetRing
)
95 if (saa7164_readl(b
->m_dwGetReadPos
) > b
->m_dwSizeGetRing
)
98 if (saa7164_readl(b
->m_dwGetWritePos
) > b
->m_dwSizeGetRing
)
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 */
109 static void saa7164_bus_dumpmsg(struct saa7164_dev
*dev
, struct tmComResInfo
*m
,
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
);
120 dprintk(DBGLVL_BUS
, " .buffer (ignored)\n");
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.
131 * SAA_OK The function executed successfully.
132 * < 0 One or more members are not initialized.
134 int saa7164_bus_set(struct saa7164_dev
*dev
, struct tmComResInfo
* msg
,
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
;
144 printk(KERN_ERR
"%s() !msg\n", __func__
);
145 return SAA_ERR_BAD_PARAMETER
;
148 dprintk(DBGLVL_BUS
, "%s()\n", __func__
);
150 saa7164_bus_verify(dev
);
152 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
153 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
155 return SAA_ERR_BAD_PARAMETER
;
158 if ((msg
->size
> 0) && (buf
== NULL
)) {
159 printk(KERN_ERR
"%s() Missing message buffer\n", __func__
);
160 return SAA_ERR_BAD_PARAMETER
;
163 /* Lock the bus from any other access */
164 mutex_lock(&bus
->lock
);
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
);
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
;
177 /* The ring has not wrapped yet */
178 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) - curr_swp
;
180 dprintk(DBGLVL_BUS
, "%s() bytes_to_write = %d\n", __func__
,
183 dprintk(DBGLVL_BUS
, "%s() free_write_space = %d\n", __func__
,
186 dprintk(DBGLVL_BUS
, "%s() curr_srp = %x\n", __func__
, curr_srp
);
187 dprintk(DBGLVL_BUS
, "%s() curr_swp = %x\n", __func__
, curr_swp
);
189 /* Process the msg and write the content onto the bus */
190 while (bytes_to_write
>= free_write_space
) {
192 if (timeout
-- == 0) {
193 printk(KERN_ERR
"%s() bus timeout\n", __func__
);
194 ret
= SAA_ERR_NO_RESOURCES
;
198 /* TODO: Review this delay, efficient? */
199 /* Wait, allowing the hardware fetch time */
202 /* Check the space usage again */
203 curr_srp
= saa7164_readl(bus
->m_dwSetReadPos
);
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
;
210 /* Read didn't wrap around the buffer */
211 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) -
216 /* Calculate the new write position */
217 new_swp
= curr_swp
+ bytes_to_write
;
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
);
224 * Make a copy of msg->size before it is converted to le16 since it is
225 * used in the code below.
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
);
233 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
235 /* Check if we're going to wrap again */
236 if (new_swp
> bus
->m_dwSizeSetRing
) {
239 new_swp
-= bus
->m_dwSizeSetRing
;
241 space_rem
= bus
->m_dwSizeSetRing
- curr_swp
;
243 dprintk(DBGLVL_BUS
, "%s() space_rem = %x\n", __func__
,
246 dprintk(DBGLVL_BUS
, "%s() sizeof(*msg) = %d\n", __func__
,
249 if (space_rem
< sizeof(*msg
)) {
250 dprintk(DBGLVL_BUS
, "%s() tr4\n", __func__
);
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
);
257 memcpy_toio(bus
->m_pdwSetRing
+ sizeof(*msg
) - space_rem
,
260 } else if (space_rem
== sizeof(*msg
)) {
261 dprintk(DBGLVL_BUS
, "%s() tr5\n", __func__
);
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
);
268 /* Additional data wraps around the ring */
269 memcpy_toio(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
271 memcpy_toio(bus
->m_pdwSetRing
+ curr_swp
+
272 sizeof(*msg
), buf
, space_rem
-
274 memcpy_toio(bus
->m_pdwSetRing
, (u8
*)buf
+
275 space_rem
- sizeof(*msg
),
276 bytes_to_write
- space_rem
);
281 } /* (new_swp > bus->m_dwSizeSetRing) */
283 dprintk(DBGLVL_BUS
, "%s() tr6\n", __func__
);
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
,
291 dprintk(DBGLVL_BUS
, "%s() new_swp = %x\n", __func__
, new_swp
);
293 /* Update the bus write position */
294 saa7164_writel(bus
->m_dwSetWritePos
, new_swp
);
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
);
303 saa7164_bus_dump(dev
);
304 mutex_unlock(&bus
->lock
);
305 saa7164_bus_verify(dev
);
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
316 * 0 The function executed successfully.
317 * < 0 One or more members are not initialized.
319 int saa7164_bus_get(struct saa7164_dev
*dev
, struct tmComResInfo
* msg
,
320 void *buf
, int peekonly
)
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
;
328 saa7164_bus_verify(dev
);
333 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
334 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
339 if ((peekonly
== 0) && (msg
->size
> 0) && (buf
== NULL
)) {
341 "%s() Missing msg buf, size should be %d bytes\n",
342 __func__
, msg
->size
);
346 mutex_lock(&bus
->lock
);
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.
351 curr_gwp
= saa7164_readl(bus
->m_dwGetWritePos
);
352 curr_grp
= saa7164_readl(bus
->m_dwGetReadPos
);
354 if (curr_gwp
== curr_grp
) {
359 bytes_to_read
= sizeof(*msg
);
361 /* Calculate write distance to current read position */
363 if (curr_gwp
>= curr_grp
)
364 /* Write doesn't wrap around the ring */
365 write_distance
= curr_gwp
- curr_grp
;
367 /* Write wraps around the ring */
368 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
370 if (bytes_to_read
> write_distance
) {
371 printk(KERN_ERR
"%s() No message/response found\n", __func__
);
372 ret
= SAA_ERR_INVALID_COMMAND
;
376 /* Calculate the new read position */
377 new_grp
= curr_grp
+ bytes_to_read
;
378 if (new_grp
> bus
->m_dwSizeGetRing
) {
381 new_grp
-= bus
->m_dwSizeGetRing
;
382 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
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
);
390 memcpy_fromio(&msg_tmp
, bus
->m_pdwGetRing
+ curr_grp
, bytes_to_read
);
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
);
397 /* No need to update the read positions, because this was a peek */
398 /* If the caller specifically want to peek, return */
400 memcpy(msg
, &msg_tmp
, sizeof(*msg
));
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
)) {
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
;
416 /* Get the actual command and response from the bus */
417 buf_size
= msg
->size
;
419 bytes_to_read
= sizeof(*msg
) + msg
->size
;
420 /* Calculate write distance to current read position */
422 if (curr_gwp
>= curr_grp
)
423 /* Write doesn't wrap around the ring */
424 write_distance
= curr_gwp
- curr_grp
;
426 /* Write wraps around the ring */
427 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
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
;
436 /* Calculate the new read position */
437 new_grp
= curr_grp
+ bytes_to_read
;
438 if (new_grp
> bus
->m_dwSizeGetRing
) {
441 new_grp
-= bus
->m_dwSizeGetRing
;
442 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
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
);
450 memcpy_fromio(buf
, bus
->m_pdwGetRing
+ sizeof(*msg
) -
451 space_rem
, buf_size
);
453 } else if (space_rem
== sizeof(*msg
)) {
454 memcpy_fromio(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
456 memcpy_fromio(buf
, bus
->m_pdwGetRing
, buf_size
);
458 /* Additional data wraps around the ring */
459 memcpy_fromio(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
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
-
472 memcpy_fromio(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
474 memcpy_fromio(buf
, bus
->m_pdwGetRing
+ curr_grp
+ sizeof(*msg
),
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
);
482 /* Update the read positions, adjusting the ring */
483 saa7164_writel(bus
->m_dwGetReadPos
, new_grp
);
488 mutex_unlock(&bus
->lock
);
489 saa7164_bus_verify(dev
);