xref: /linux/drivers/media/pci/saa7164/saa7164-bus.c (revision e0bf6c5ca2d3281f231c5f0c9bf145e9513644de)
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 static 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 static 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 
493