2 * Driver for the NXP SAA7164 PCIe bridge
4 * Copyright (c) 2009 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 tmComResBusInfo_t
*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_pdwSetWritePos
= (u32
*)((u8
*)(dev
->bmmio
+
47 ((u32
)dev
->intfdesc
.BARLocation
) + (2 * sizeof(u64
))));
49 b
->m_pdwSetReadPos
= (u32
*)((u8
*)b
->m_pdwSetWritePos
+
52 b
->m_pdwGetWritePos
= (u32
*)((u8
*)b
->m_pdwSetWritePos
+
55 b
->m_pdwGetReadPos
= (u32
*)((u8
*)b
->m_pdwSetWritePos
+
61 void saa7164_bus_dump(struct saa7164_dev
*dev
)
63 tmComResBusInfo_t
*b
= &dev
->bus
;
65 dprintk(DBGLVL_BUS
, "Dumping the bus structure:\n");
66 dprintk(DBGLVL_BUS
, " .type = %d\n", b
->Type
);
67 dprintk(DBGLVL_BUS
, " .dev->bmmio = 0x%p\n", dev
->bmmio
);
68 dprintk(DBGLVL_BUS
, " .m_wMaxReqSize = 0x%x\n", b
->m_wMaxReqSize
);
69 dprintk(DBGLVL_BUS
, " .m_pdwSetRing = 0x%p\n", b
->m_pdwSetRing
);
70 dprintk(DBGLVL_BUS
, " .m_dwSizeSetRing = 0x%x\n", b
->m_dwSizeSetRing
);
71 dprintk(DBGLVL_BUS
, " .m_pdwGetRing = 0x%p\n", b
->m_pdwGetRing
);
72 dprintk(DBGLVL_BUS
, " .m_dwSizeGetRing = 0x%x\n", b
->m_dwSizeGetRing
);
74 dprintk(DBGLVL_BUS
, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
75 b
->m_pdwSetWritePos
, *b
->m_pdwSetWritePos
);
77 dprintk(DBGLVL_BUS
, " .m_pdwSetReadPos = 0x%p (0x%08x)\n",
78 b
->m_pdwSetReadPos
, *b
->m_pdwSetReadPos
);
80 dprintk(DBGLVL_BUS
, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
81 b
->m_pdwGetWritePos
, *b
->m_pdwGetWritePos
);
83 dprintk(DBGLVL_BUS
, " .m_pdwGetReadPos = 0x%p (0x%08x)\n",
84 b
->m_pdwGetReadPos
, *b
->m_pdwGetReadPos
);
87 void saa7164_bus_dumpmsg(struct saa7164_dev
*dev
, tmComResInfo_t
* m
, void *buf
)
89 dprintk(DBGLVL_BUS
, "Dumping msg structure:\n");
90 dprintk(DBGLVL_BUS
, " .id = %d\n", m
->id
);
91 dprintk(DBGLVL_BUS
, " .flags = 0x%x\n", m
->flags
);
92 dprintk(DBGLVL_BUS
, " .size = 0x%x\n", m
->size
);
93 dprintk(DBGLVL_BUS
, " .command = 0x%x\n", m
->command
);
94 dprintk(DBGLVL_BUS
, " .controlselector = 0x%x\n", m
->controlselector
);
95 dprintk(DBGLVL_BUS
, " .seqno = %d\n", m
->seqno
);
97 dprintk(DBGLVL_BUS
, " .buffer (ignored)\n");
101 * Places a command or a response on the bus. The implementation does not
102 * know if it is a command or a response it just places the data on the
103 * bus depending on the bus information given in the tmComResBusInfo_t
104 * structure. If the command or response does not fit into the bus ring
105 * buffer it will be refused.
108 * SAA_OK The function executed successfully.
109 * < 0 One or more members are not initialized.
111 int saa7164_bus_set(struct saa7164_dev
*dev
, tmComResInfo_t
* msg
, void *buf
)
113 tmComResBusInfo_t
*bus
= &dev
->bus
;
114 u32 bytes_to_write
, read_distance
, timeout
, curr_srp
, curr_swp
;
115 u32 new_swp
, space_rem
;
116 int ret
= SAA_ERR_BAD_PARAMETER
;
119 printk(KERN_ERR
"%s() !msg\n", __func__
);
120 return SAA_ERR_BAD_PARAMETER
;
123 dprintk(DBGLVL_BUS
, "%s()\n", __func__
);
125 msg
->size
= cpu_to_le16(msg
->size
);
126 msg
->command
= cpu_to_le16(msg
->command
);
127 msg
->controlselector
= cpu_to_le16(msg
->controlselector
);
129 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
130 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
132 return SAA_ERR_BAD_PARAMETER
;
135 if ((msg
->size
> 0) && (buf
== 0)) {
136 printk(KERN_ERR
"%s() Missing message buffer\n", __func__
);
137 return SAA_ERR_BAD_PARAMETER
;
140 /* Lock the bus from any other access */
141 mutex_lock(&bus
->lock
);
143 bytes_to_write
= sizeof(*msg
) + msg
->size
;
145 timeout
= SAA_BUS_TIMEOUT
;
146 curr_srp
= le32_to_cpu(*bus
->m_pdwSetReadPos
);
147 curr_swp
= le32_to_cpu(*bus
->m_pdwSetWritePos
);
149 /* Deal with ring wrapping issues */
150 if (curr_srp
> curr_swp
)
151 /* The ring has not wrapped yet */
152 read_distance
= curr_srp
- curr_swp
;
154 /* Deal with the wrapped ring */
155 read_distance
= (curr_srp
+ bus
->m_dwSizeSetRing
) - curr_swp
;
157 dprintk(DBGLVL_BUS
, "%s() bytes_to_write = %d\n", __func__
,
160 dprintk(DBGLVL_BUS
, "%s() read_distance = %d\n", __func__
,
163 dprintk(DBGLVL_BUS
, "%s() curr_srp = %x\n", __func__
, curr_srp
);
164 dprintk(DBGLVL_BUS
, "%s() curr_swp = %x\n", __func__
, curr_swp
);
166 /* Process the msg and write the content onto the bus */
167 while (bytes_to_write
>= read_distance
) {
169 if (timeout
-- == 0) {
170 printk(KERN_ERR
"%s() bus timeout\n", __func__
);
171 ret
= SAA_ERR_NO_RESOURCES
;
175 /* TODO: Review this delay, efficient? */
176 /* Wait, allowing the hardware fetch time */
179 /* Check the space usage again */
180 curr_srp
= le32_to_cpu(*bus
->m_pdwSetReadPos
);
182 /* Deal with ring wrapping issues */
183 if (curr_srp
> curr_swp
)
184 /* Read didn't wrap around the buffer */
185 read_distance
= curr_srp
- curr_swp
;
187 /* Deal with the wrapped ring */
188 read_distance
= (curr_srp
+ bus
->m_dwSizeSetRing
) -
193 /* Calculate the new write position */
194 new_swp
= curr_swp
+ bytes_to_write
;
196 dprintk(DBGLVL_BUS
, "%s() new_swp = %x\n", __func__
, new_swp
);
197 dprintk(DBGLVL_BUS
, "%s() bus->m_dwSizeSetRing = %x\n", __func__
,
198 bus
->m_dwSizeSetRing
);
200 /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
202 /* Check if we're going to wrap again */
203 if (new_swp
> bus
->m_dwSizeSetRing
) {
206 new_swp
-= bus
->m_dwSizeSetRing
;
208 space_rem
= bus
->m_dwSizeSetRing
- curr_swp
;
210 dprintk(DBGLVL_BUS
, "%s() space_rem = %x\n", __func__
,
213 dprintk(DBGLVL_BUS
, "%s() sizeof(*msg) = %d\n", __func__
,
216 if (space_rem
< sizeof(*msg
)) {
217 dprintk(DBGLVL_BUS
, "%s() tr4\n", __func__
);
219 /* Split the msg into pieces as the ring wraps */
220 memcpy(bus
->m_pdwSetRing
+ curr_swp
, msg
, space_rem
);
221 memcpy(bus
->m_pdwSetRing
, (u8
*)msg
+ space_rem
,
222 sizeof(*msg
) - space_rem
);
224 memcpy(bus
->m_pdwSetRing
+ sizeof(*msg
) - space_rem
,
227 } else if (space_rem
== sizeof(*msg
)) {
228 dprintk(DBGLVL_BUS
, "%s() tr5\n", __func__
);
230 /* Additional data at the beginning of the ring */
231 memcpy(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
232 memcpy(bus
->m_pdwSetRing
, buf
, msg
->size
);
235 /* Additional data wraps around the ring */
236 memcpy(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
238 memcpy(bus
->m_pdwSetRing
+ curr_swp
+
239 sizeof(*msg
), buf
, space_rem
-
241 memcpy(bus
->m_pdwSetRing
, (u8
*)buf
+
242 space_rem
- sizeof(*msg
),
243 bytes_to_write
- space_rem
);
248 } /* (new_swp > bus->m_dwSizeSetRing) */
250 dprintk(DBGLVL_BUS
, "%s() tr6\n", __func__
);
252 /* The ring buffer doesn't wrap, two simple copies */
253 memcpy(bus
->m_pdwSetRing
+ curr_swp
, msg
, sizeof(*msg
));
254 memcpy(bus
->m_pdwSetRing
+ curr_swp
+ sizeof(*msg
), buf
,
258 dprintk(DBGLVL_BUS
, "%s() new_swp = %x\n", __func__
, new_swp
);
260 /* TODO: Convert all of the direct PCI writes into
261 * saa7164_writel/b calls for consistency.
264 /* Update the bus write position */
265 *bus
->m_pdwSetWritePos
= cpu_to_le32(new_swp
);
269 mutex_unlock(&bus
->lock
);
274 * Receive a command or a response from the bus. The implementation does not
275 * know if it is a command or a response it simply dequeues the data,
276 * depending on the bus information given in the tmComResBusInfo_t structure.
279 * 0 The function executed successfully.
280 * < 0 One or more members are not initialized.
282 int saa7164_bus_get(struct saa7164_dev
*dev
, tmComResInfo_t
* msg
, void *buf
,
285 tmComResBusInfo_t
*bus
= &dev
->bus
;
286 u32 bytes_to_read
, write_distance
, curr_grp
, curr_gwp
,
287 new_grp
, buf_size
, space_rem
;
288 tmComResInfo_t msg_tmp
;
289 int ret
= SAA_ERR_BAD_PARAMETER
;
294 if (msg
->size
> dev
->bus
.m_wMaxReqSize
) {
295 printk(KERN_ERR
"%s() Exceeded dev->bus.m_wMaxReqSize\n",
300 if ((peekonly
== 0) && (msg
->size
> 0) && (buf
== 0)) {
302 "%s() Missing msg buf, size should be %d bytes\n",
303 __func__
, msg
->size
);
307 mutex_lock(&bus
->lock
);
309 /* Peek the bus to see if a msg exists, if it's not what we're expecting
310 * then return cleanly else read the message from the bus.
312 curr_gwp
= le32_to_cpu(*bus
->m_pdwGetWritePos
);
313 curr_grp
= le32_to_cpu(*bus
->m_pdwGetReadPos
);
315 if (curr_gwp
== curr_grp
) {
316 dprintk(DBGLVL_BUS
, "%s() No message on the bus\n", __func__
);
321 bytes_to_read
= sizeof(*msg
);
323 /* Calculate write distance to current read position */
325 if (curr_gwp
>= curr_grp
)
326 /* Write doesn't wrap around the ring */
327 write_distance
= curr_gwp
- curr_grp
;
329 /* Write wraps around the ring */
330 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
332 if (bytes_to_read
> write_distance
) {
333 printk(KERN_ERR
"%s() No message/response found\n", __func__
);
334 ret
= SAA_ERR_INVALID_COMMAND
;
338 /* Calculate the new read position */
339 new_grp
= curr_grp
+ bytes_to_read
;
340 if (new_grp
> bus
->m_dwSizeGetRing
) {
343 new_grp
-= bus
->m_dwSizeGetRing
;
344 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
346 memcpy(&msg_tmp
, bus
->m_pdwGetRing
+ curr_grp
, space_rem
);
347 memcpy((u8
*)&msg_tmp
+ space_rem
, bus
->m_pdwGetRing
,
348 bytes_to_read
- space_rem
);
352 memcpy(&msg_tmp
, bus
->m_pdwGetRing
+ curr_grp
, bytes_to_read
);
355 /* No need to update the read positions, because this was a peek */
356 /* If the caller specifically want to peek, return */
358 memcpy(msg
, &msg_tmp
, sizeof(*msg
));
362 /* Check if the command/response matches what is expected */
363 if ((msg_tmp
.id
!= msg
->id
) || (msg_tmp
.command
!= msg
->command
) ||
364 (msg_tmp
.controlselector
!= msg
->controlselector
) ||
365 (msg_tmp
.seqno
!= msg
->seqno
) || (msg_tmp
.size
!= msg
->size
)) {
367 printk(KERN_ERR
"%s() Unexpected msg miss-match\n", __func__
);
368 saa7164_bus_dumpmsg(dev
, msg
, buf
);
369 saa7164_bus_dumpmsg(dev
, &msg_tmp
, 0);
370 ret
= SAA_ERR_INVALID_COMMAND
;
374 /* Get the actual command and response from the bus */
375 buf_size
= msg
->size
;
377 bytes_to_read
= sizeof(*msg
) + msg
->size
;
378 /* Calculate write distance to current read position */
380 if (curr_gwp
>= curr_grp
)
381 /* Write doesn't wrap around the ring */
382 write_distance
= curr_gwp
- curr_grp
;
384 /* Write wraps around the ring */
385 write_distance
= curr_gwp
+ bus
->m_dwSizeGetRing
- curr_grp
;
387 if (bytes_to_read
> write_distance
) {
388 printk(KERN_ERR
"%s() Invalid bus state, missing msg "
389 "or mangled ring, faulty H/W / bad code?\n", __func__
);
390 ret
= SAA_ERR_INVALID_COMMAND
;
394 /* Calculate the new read position */
395 new_grp
= curr_grp
+ bytes_to_read
;
396 if (new_grp
> bus
->m_dwSizeGetRing
) {
399 new_grp
-= bus
->m_dwSizeGetRing
;
400 space_rem
= bus
->m_dwSizeGetRing
- curr_grp
;
402 if (space_rem
< sizeof(*msg
)) {
403 /* msg wraps around the ring */
404 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, space_rem
);
405 memcpy((u8
*)msg
+ space_rem
, bus
->m_pdwGetRing
,
406 sizeof(*msg
) - space_rem
);
408 memcpy(buf
, bus
->m_pdwGetRing
+ sizeof(*msg
) -
409 space_rem
, buf_size
);
411 } else if (space_rem
== sizeof(*msg
)) {
412 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
414 memcpy(buf
, bus
->m_pdwGetRing
, buf_size
);
416 /* Additional data wraps around the ring */
417 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
419 memcpy(buf
, bus
->m_pdwGetRing
+ curr_grp
+
420 sizeof(*msg
), space_rem
- sizeof(*msg
));
421 memcpy(buf
+ space_rem
- sizeof(*msg
),
422 bus
->m_pdwGetRing
, bytes_to_read
-
430 memcpy(msg
, bus
->m_pdwGetRing
+ curr_grp
, sizeof(*msg
));
432 memcpy(buf
, bus
->m_pdwGetRing
+ curr_grp
+ sizeof(*msg
),
436 /* Update the read positions, adjusting the ring */
437 *bus
->m_pdwGetReadPos
= cpu_to_le32(new_grp
);
440 msg
->size
= le16_to_cpu(msg
->size
);
441 msg
->command
= le16_to_cpu(msg
->command
);
442 msg
->controlselector
= le16_to_cpu(msg
->controlselector
);
445 mutex_unlock(&bus
->lock
);