2 * Driver for the NXP SAA7164 PCIe bridge
4 * Copyright (c) 2010 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
*)(dev
->bmmio
+
37 ((u32
)dev
->busdesc
.CommandRing
));
39 b
->m_dwSizeSetRing
= SAA_DEVICE_BUFFERBLOCKSIZE
;
41 b
->m_pdwGetRing
= (u8
*)(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
;
143 printk(KERN_ERR
"%s() !msg\n", __func__
);
144 return SAA_ERR_BAD_PARAMETER
;
147 dprintk(DBGLVL_BUS
, "%s()\n", __func__
);
149 saa7164_bus_verify(dev
);
151 msg
->size
= cpu_to_le16(msg
->size
);
152 msg
->command
= cpu_to_le32(msg
->command
);
153 msg
->controlselector
= cpu_to_le16(msg
->controlselector
);
155 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
156 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
158 return SAA_ERR_BAD_PARAMETER
;
161 if ((msg
->size
> 0) && (buf
== NULL
)) {
162 printk(KERN_ERR
"%s() Missing message buffer\n", __func__
);
163 return SAA_ERR_BAD_PARAMETER
;
166 /* Lock the bus from any other access */
167 mutex_lock(&bus
->lock
);
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
));
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
;
180 /* The ring has not wrapped yet */
181 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) - curr_swp
;
183 dprintk(DBGLVL_BUS
, "%s() bytes_to_write = %d\n", __func__
,
186 dprintk(DBGLVL_BUS
, "%s() free_write_space = %d\n", __func__
,
189 dprintk(DBGLVL_BUS
, "%s() curr_srp = %x\n", __func__
, curr_srp
);
190 dprintk(DBGLVL_BUS
, "%s() curr_swp = %x\n", __func__
, curr_swp
);
192 /* Process the msg and write the content onto the bus */
193 while (bytes_to_write
>= free_write_space
) {
195 if (timeout
-- == 0) {
196 printk(KERN_ERR
"%s() bus timeout\n", __func__
);
197 ret
= SAA_ERR_NO_RESOURCES
;
201 /* TODO: Review this delay, efficient? */
202 /* Wait, allowing the hardware fetch time */
205 /* Check the space usage again */
206 curr_srp
= le32_to_cpu(saa7164_readl(bus
->m_dwSetReadPos
));
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
;
213 /* Read didn't wrap around the buffer */
214 free_write_space
= (curr_srp
+ bus
->m_dwSizeSetRing
) -
219 /* Calculate the new write position */
220 new_swp
= curr_swp
+ bytes_to_write
;
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
);
226 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
228 /* Check if we're going to wrap again */
229 if (new_swp
> bus
->m_dwSizeSetRing
) {
232 new_swp
-= bus
->m_dwSizeSetRing
;
234 space_rem
= bus
->m_dwSizeSetRing
- curr_swp
;
236 dprintk(DBGLVL_BUS
, "%s() space_rem = %x\n", __func__
,
239 dprintk(DBGLVL_BUS
, "%s() sizeof(*msg) = %d\n", __func__
,
242 if (space_rem
< sizeof(*msg
)) {
243 dprintk(DBGLVL_BUS
, "%s() tr4\n", __func__
);
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
);
250 memcpy(bus
->m_pdwSetRing
+ sizeof(*msg
) - space_rem
,
253 } else if (space_rem
== sizeof(*msg
)) {
254 dprintk(DBGLVL_BUS
, "%s() tr5\n", __func__
);
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
);
261 /* Additional data wraps around the ring */
262 memcpy(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
264 memcpy(bus
->m_pdwSetRing
+ curr_swp
+
265 sizeof(*msg
), buf
, space_rem
-
267 memcpy(bus
->m_pdwSetRing
, (u8
*)buf
+
268 space_rem
- sizeof(*msg
),
269 bytes_to_write
- space_rem
);
274 } /* (new_swp > bus->m_dwSizeSetRing) */
276 dprintk(DBGLVL_BUS
, "%s() tr6\n", __func__
);
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
,
284 dprintk(DBGLVL_BUS
, "%s() new_swp = %x\n", __func__
, new_swp
);
286 /* Update the bus write position */
287 saa7164_writel(bus
->m_dwSetWritePos
, cpu_to_le32(new_swp
));
291 saa7164_bus_dump(dev
);
292 mutex_unlock(&bus
->lock
);
293 saa7164_bus_verify(dev
);
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
304 * 0 The function executed successfully.
305 * < 0 One or more members are not initialized.
307 int saa7164_bus_get(struct saa7164_dev
*dev
, struct tmComResInfo
* msg
,
308 void *buf
, int peekonly
)
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
;
316 saa7164_bus_verify(dev
);
321 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
322 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
327 if ((peekonly
== 0) && (msg
->size
> 0) && (buf
== NULL
)) {
329 "%s() Missing msg buf, size should be %d bytes\n",
330 __func__
, msg
->size
);
334 mutex_lock(&bus
->lock
);
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.
339 curr_gwp
= le32_to_cpu(saa7164_readl(bus
->m_dwGetWritePos
));
340 curr_grp
= le32_to_cpu(saa7164_readl(bus
->m_dwGetReadPos
));
342 if (curr_gwp
== curr_grp
) {
347 bytes_to_read
= sizeof(*msg
);
349 /* Calculate write distance to current read position */
351 if (curr_gwp
>= curr_grp
)
352 /* Write doesn't wrap around the ring */
353 write_distance
= curr_gwp
- curr_grp
;
355 /* Write wraps around the ring */
356 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
358 if (bytes_to_read
> write_distance
) {
359 printk(KERN_ERR
"%s() No message/response found\n", __func__
);
360 ret
= SAA_ERR_INVALID_COMMAND
;
364 /* Calculate the new read position */
365 new_grp
= curr_grp
+ bytes_to_read
;
366 if (new_grp
> bus
->m_dwSizeGetRing
) {
369 new_grp
-= bus
->m_dwSizeGetRing
;
370 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
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
);
378 memcpy(&msg_tmp
, bus
->m_pdwGetRing
+ curr_grp
, bytes_to_read
);
381 /* No need to update the read positions, because this was a peek */
382 /* If the caller specifically want to peek, return */
384 memcpy(msg
, &msg_tmp
, sizeof(*msg
));
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
)) {
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
;
400 /* Get the actual command and response from the bus */
401 buf_size
= msg
->size
;
403 bytes_to_read
= sizeof(*msg
) + msg
->size
;
404 /* Calculate write distance to current read position */
406 if (curr_gwp
>= curr_grp
)
407 /* Write doesn't wrap around the ring */
408 write_distance
= curr_gwp
- curr_grp
;
410 /* Write wraps around the ring */
411 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
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
;
420 /* Calculate the new read position */
421 new_grp
= curr_grp
+ bytes_to_read
;
422 if (new_grp
> bus
->m_dwSizeGetRing
) {
425 new_grp
-= bus
->m_dwSizeGetRing
;
426 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
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
);
434 memcpy(buf
, bus
->m_pdwGetRing
+ sizeof(*msg
) -
435 space_rem
, buf_size
);
437 } else if (space_rem
== sizeof(*msg
)) {
438 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
440 memcpy(buf
, bus
->m_pdwGetRing
, buf_size
);
442 /* Additional data wraps around the ring */
443 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
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
-
456 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
458 memcpy(buf
, bus
->m_pdwGetRing
+ curr_grp
+ sizeof(*msg
),
462 /* Update the read positions, adjusting the ring */
463 saa7164_writel(bus
->m_dwGetReadPos
, cpu_to_le32(new_grp
));
466 msg
->size
= le16_to_cpu(msg
->size
);
467 msg
->command
= le32_to_cpu(msg
->command
);
468 msg
->controlselector
= le16_to_cpu(msg
->controlselector
);
471 mutex_unlock(&bus
->lock
);
472 saa7164_bus_verify(dev
);