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.
20 /* The message bus to/from the firmware is a ring buffer in PCI address
21 * space. Establish the defaults.
23 int saa7164_bus_setup(struct saa7164_dev
*dev
)
25 struct tmComResBusInfo
*b
= &dev
->bus
;
29 b
->Type
= TYPE_BUS_PCIe
;
30 b
->m_wMaxReqSize
= SAA_DEVICE_MAXREQUESTSIZE
;
32 b
->m_pdwSetRing
= (u8 __iomem
*)(dev
->bmmio
+
33 ((u32
)dev
->busdesc
.CommandRing
));
35 b
->m_dwSizeSetRing
= SAA_DEVICE_BUFFERBLOCKSIZE
;
37 b
->m_pdwGetRing
= (u8 __iomem
*)(dev
->bmmio
+
38 ((u32
)dev
->busdesc
.ResponseRing
));
40 b
->m_dwSizeGetRing
= SAA_DEVICE_BUFFERBLOCKSIZE
;
42 b
->m_dwSetWritePos
= ((u32
)dev
->intfdesc
.BARLocation
) +
44 b
->m_dwSetReadPos
= b
->m_dwSetWritePos
+ (1 * sizeof(u32
));
46 b
->m_dwGetWritePos
= b
->m_dwSetWritePos
+ (2 * sizeof(u32
));
47 b
->m_dwGetReadPos
= b
->m_dwSetWritePos
+ (3 * sizeof(u32
));
52 void saa7164_bus_dump(struct saa7164_dev
*dev
)
54 struct tmComResBusInfo
*b
= &dev
->bus
;
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
);
65 dprintk(DBGLVL_BUS
, " .m_dwSetReadPos = 0x%x (0x%08x)\n",
66 b
->m_dwSetReadPos
, saa7164_readl(b
->m_dwSetReadPos
));
68 dprintk(DBGLVL_BUS
, " .m_dwSetWritePos = 0x%x (0x%08x)\n",
69 b
->m_dwSetWritePos
, saa7164_readl(b
->m_dwSetWritePos
));
71 dprintk(DBGLVL_BUS
, " .m_dwGetReadPos = 0x%x (0x%08x)\n",
72 b
->m_dwGetReadPos
, saa7164_readl(b
->m_dwGetReadPos
));
74 dprintk(DBGLVL_BUS
, " .m_dwGetWritePos = 0x%x (0x%08x)\n",
75 b
->m_dwGetWritePos
, saa7164_readl(b
->m_dwGetWritePos
));
79 /* Intensionally throw a BUG() if the state of the message bus looks corrupt */
80 static void saa7164_bus_verify(struct saa7164_dev
*dev
)
82 struct tmComResBusInfo
*b
= &dev
->bus
;
85 if (saa7164_readl(b
->m_dwSetReadPos
) > b
->m_dwSizeSetRing
)
88 if (saa7164_readl(b
->m_dwSetWritePos
) > b
->m_dwSizeSetRing
)
91 if (saa7164_readl(b
->m_dwGetReadPos
) > b
->m_dwSizeGetRing
)
94 if (saa7164_readl(b
->m_dwGetWritePos
) > b
->m_dwSizeGetRing
)
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 */
105 static void saa7164_bus_dumpmsg(struct saa7164_dev
*dev
, struct tmComResInfo
*m
,
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
);
116 dprintk(DBGLVL_BUS
, " .buffer (ignored)\n");
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.
127 * SAA_OK The function executed successfully.
128 * < 0 One or more members are not initialized.
130 int saa7164_bus_set(struct saa7164_dev
*dev
, struct tmComResInfo
* msg
,
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
;
140 printk(KERN_ERR
"%s() !msg\n", __func__
);
141 return SAA_ERR_BAD_PARAMETER
;
144 dprintk(DBGLVL_BUS
, "%s()\n", __func__
);
146 saa7164_bus_verify(dev
);
148 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
149 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
151 return SAA_ERR_BAD_PARAMETER
;
154 if ((msg
->size
> 0) && (buf
== NULL
)) {
155 printk(KERN_ERR
"%s() Missing message buffer\n", __func__
);
156 return SAA_ERR_BAD_PARAMETER
;
159 /* Lock the bus from any other access */
160 mutex_lock(&bus
->lock
);
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
);
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
;
173 /* The ring has not wrapped yet */
174 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) - curr_swp
;
176 dprintk(DBGLVL_BUS
, "%s() bytes_to_write = %d\n", __func__
,
179 dprintk(DBGLVL_BUS
, "%s() free_write_space = %d\n", __func__
,
182 dprintk(DBGLVL_BUS
, "%s() curr_srp = %x\n", __func__
, curr_srp
);
183 dprintk(DBGLVL_BUS
, "%s() curr_swp = %x\n", __func__
, curr_swp
);
185 /* Process the msg and write the content onto the bus */
186 while (bytes_to_write
>= free_write_space
) {
188 if (timeout
-- == 0) {
189 printk(KERN_ERR
"%s() bus timeout\n", __func__
);
190 ret
= SAA_ERR_NO_RESOURCES
;
194 /* TODO: Review this delay, efficient? */
195 /* Wait, allowing the hardware fetch time */
198 /* Check the space usage again */
199 curr_srp
= saa7164_readl(bus
->m_dwSetReadPos
);
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
;
206 /* Read didn't wrap around the buffer */
207 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) -
212 /* Calculate the new write position */
213 new_swp
= curr_swp
+ bytes_to_write
;
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
);
220 * Make a copy of msg->size before it is converted to le16 since it is
221 * used in the code below.
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
);
229 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
231 /* Check if we're going to wrap again */
232 if (new_swp
> bus
->m_dwSizeSetRing
) {
235 new_swp
-= bus
->m_dwSizeSetRing
;
237 space_rem
= bus
->m_dwSizeSetRing
- curr_swp
;
239 dprintk(DBGLVL_BUS
, "%s() space_rem = %x\n", __func__
,
242 dprintk(DBGLVL_BUS
, "%s() sizeof(*msg) = %d\n", __func__
,
245 if (space_rem
< sizeof(*msg
)) {
246 dprintk(DBGLVL_BUS
, "%s() tr4\n", __func__
);
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
);
253 memcpy_toio(bus
->m_pdwSetRing
+ sizeof(*msg
) - space_rem
,
256 } else if (space_rem
== sizeof(*msg
)) {
257 dprintk(DBGLVL_BUS
, "%s() tr5\n", __func__
);
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
);
264 /* Additional data wraps around the ring */
265 memcpy_toio(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
267 memcpy_toio(bus
->m_pdwSetRing
+ curr_swp
+
268 sizeof(*msg
), buf
, space_rem
-
270 memcpy_toio(bus
->m_pdwSetRing
, (u8
*)buf
+
271 space_rem
- sizeof(*msg
),
272 bytes_to_write
- space_rem
);
277 } /* (new_swp > bus->m_dwSizeSetRing) */
279 dprintk(DBGLVL_BUS
, "%s() tr6\n", __func__
);
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
,
287 dprintk(DBGLVL_BUS
, "%s() new_swp = %x\n", __func__
, new_swp
);
289 /* Update the bus write position */
290 saa7164_writel(bus
->m_dwSetWritePos
, new_swp
);
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
);
299 saa7164_bus_dump(dev
);
300 mutex_unlock(&bus
->lock
);
301 saa7164_bus_verify(dev
);
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
312 * 0 The function executed successfully.
313 * < 0 One or more members are not initialized.
315 int saa7164_bus_get(struct saa7164_dev
*dev
, struct tmComResInfo
* msg
,
316 void *buf
, int peekonly
)
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
;
324 saa7164_bus_verify(dev
);
329 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
330 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
335 if ((peekonly
== 0) && (msg
->size
> 0) && (buf
== NULL
)) {
337 "%s() Missing msg buf, size should be %d bytes\n",
338 __func__
, msg
->size
);
342 mutex_lock(&bus
->lock
);
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.
347 curr_gwp
= saa7164_readl(bus
->m_dwGetWritePos
);
348 curr_grp
= saa7164_readl(bus
->m_dwGetReadPos
);
350 if (curr_gwp
== curr_grp
) {
355 bytes_to_read
= sizeof(*msg
);
357 /* Calculate write distance to current read position */
359 if (curr_gwp
>= curr_grp
)
360 /* Write doesn't wrap around the ring */
361 write_distance
= curr_gwp
- curr_grp
;
363 /* Write wraps around the ring */
364 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
366 if (bytes_to_read
> write_distance
) {
367 printk(KERN_ERR
"%s() No message/response found\n", __func__
);
368 ret
= SAA_ERR_INVALID_COMMAND
;
372 /* Calculate the new read position */
373 new_grp
= curr_grp
+ bytes_to_read
;
374 if (new_grp
> bus
->m_dwSizeGetRing
) {
377 new_grp
-= bus
->m_dwSizeGetRing
;
378 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
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
);
386 memcpy_fromio(&msg_tmp
, bus
->m_pdwGetRing
+ curr_grp
, bytes_to_read
);
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
));
394 /* No need to update the read positions, because this was a peek */
395 /* If the caller specifically want to peek, return */
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
)) {
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
;
412 /* Get the actual command and response from the bus */
413 buf_size
= msg
->size
;
415 bytes_to_read
= sizeof(*msg
) + msg
->size
;
416 /* Calculate write distance to current read position */
418 if (curr_gwp
>= curr_grp
)
419 /* Write doesn't wrap around the ring */
420 write_distance
= curr_gwp
- curr_grp
;
422 /* Write wraps around the ring */
423 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
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",
428 ret
= SAA_ERR_INVALID_COMMAND
;
432 /* Calculate the new read position */
433 new_grp
= curr_grp
+ bytes_to_read
;
434 if (new_grp
> bus
->m_dwSizeGetRing
) {
437 new_grp
-= bus
->m_dwSizeGetRing
;
438 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
440 if (space_rem
< sizeof(*msg
)) {
442 memcpy_fromio(buf
, bus
->m_pdwGetRing
+ sizeof(*msg
) -
443 space_rem
, buf_size
);
445 } else if (space_rem
== sizeof(*msg
)) {
447 memcpy_fromio(buf
, bus
->m_pdwGetRing
, buf_size
);
449 /* Additional data wraps around the ring */
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
-
463 memcpy_fromio(buf
, bus
->m_pdwGetRing
+ curr_grp
+ sizeof(*msg
),
467 /* Update the read positions, adjusting the ring */
468 saa7164_writel(bus
->m_dwGetReadPos
, new_grp
);
473 mutex_unlock(&bus
->lock
);
474 saa7164_bus_verify(dev
);