saa7164-bus.c revision 207b42c492cc335806957c139381eb260a808837
1/*
2 *  Driver for the NXP SAA7164 PCIe bridge
3 *
4 *  Copyright (c) 2009 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 */
27int saa7164_bus_setup(struct saa7164_dev *dev)
28{
29	tmComResBusInfo_t *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 *)(dev->bmmio +
37		((u32)dev->busdesc.CommandRing));
38
39	b->m_dwSizeSetRing	= SAA_DEVICE_BUFFERBLOCKSIZE;
40
41	b->m_pdwGetRing		= (u8 *)(dev->bmmio +
42		((u32)dev->busdesc.ResponseRing));
43
44	b->m_dwSizeGetRing	= SAA_DEVICE_BUFFERBLOCKSIZE;
45
46	b->m_pdwSetWritePos	= (u32 *)((u8 *)(dev->bmmio +
47		((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64))));
48
49	b->m_pdwSetReadPos	= (u32 *)((u8 *)b->m_pdwSetWritePos +
50		1 * sizeof(u32));
51
52	b->m_pdwGetWritePos	= (u32 *)((u8 *)b->m_pdwSetWritePos +
53		2 * sizeof(u32));
54
55	b->m_pdwGetReadPos	= (u32 *)((u8 *)b->m_pdwSetWritePos +
56		3 * sizeof(u32));
57
58	return 0;
59}
60
61void saa7164_bus_dump(struct saa7164_dev *dev)
62{
63	tmComResBusInfo_t *b = &dev->bus;
64
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);
73
74	dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
75		b->m_pdwSetWritePos, *b->m_pdwSetWritePos);
76
77	dprintk(DBGLVL_BUS, " .m_pdwSetReadPos  = 0x%p (0x%08x)\n",
78		b->m_pdwSetReadPos, *b->m_pdwSetReadPos);
79
80	dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
81		b->m_pdwGetWritePos, *b->m_pdwGetWritePos);
82
83	dprintk(DBGLVL_BUS, " .m_pdwGetReadPos  = 0x%p (0x%08x)\n",
84		b->m_pdwGetReadPos, *b->m_pdwGetReadPos);
85}
86
87void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
88{
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);
96	if (buf)
97		dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
98}
99
100/*
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.
106 *
107 * Return Value:
108 *  SAA_OK     The function executed successfully.
109 *  < 0        One or more members are not initialized.
110 */
111int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
112{
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;
117
118	if (!msg) {
119		printk(KERN_ERR "%s() !msg\n", __func__);
120		return SAA_ERR_BAD_PARAMETER;
121	}
122
123	dprintk(DBGLVL_BUS, "%s()\n", __func__);
124
125	msg->size = cpu_to_le16(msg->size);
126	msg->command = cpu_to_le16(msg->command);
127	msg->controlselector = cpu_to_le16(msg->controlselector);
128
129	if (msg->size > dev->bus.m_wMaxReqSize) {
130		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
131			__func__);
132		return SAA_ERR_BAD_PARAMETER;
133	}
134
135	if ((msg->size > 0) && (buf == 0)) {
136		printk(KERN_ERR "%s() Missing message buffer\n", __func__);
137		return SAA_ERR_BAD_PARAMETER;
138	}
139
140	/* Lock the bus from any other access */
141	mutex_lock(&bus->lock);
142
143	bytes_to_write = sizeof(*msg) + msg->size;
144	read_distance = 0;
145	timeout = SAA_BUS_TIMEOUT;
146	curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
147	curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos);
148
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;
153	else
154		/* Deal with the wrapped ring */
155		read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
156
157	dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
158		bytes_to_write);
159
160	dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__,
161		read_distance);
162
163	dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
164	dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
165
166	/* Process the msg and write the content onto the bus */
167	while (bytes_to_write >= read_distance) {
168
169		if (timeout-- == 0) {
170			printk(KERN_ERR "%s() bus timeout\n", __func__);
171			ret = SAA_ERR_NO_RESOURCES;
172			goto out;
173		}
174
175		/* TODO: Review this delay, efficient? */
176		/* Wait, allowing the hardware fetch time */
177		mdelay(1);
178
179		/* Check the space usage again */
180		curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
181
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;
186		else
187			/* Deal with the wrapped ring */
188			read_distance = (curr_srp + bus->m_dwSizeSetRing) -
189				curr_swp;
190
191	}
192
193	/* Calculate the new write position */
194	new_swp = curr_swp + bytes_to_write;
195
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);
199
200	/* Mental Note: line 462 tmmhComResBusPCIe.cpp */
201
202	/* Check if we're going to wrap again */
203	if (new_swp > bus->m_dwSizeSetRing) {
204
205		/* Ring wraps */
206		new_swp -= bus->m_dwSizeSetRing;
207
208		space_rem = bus->m_dwSizeSetRing - curr_swp;
209
210		dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
211			space_rem);
212
213		dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
214			(u32)sizeof(*msg));
215
216		if (space_rem < sizeof(*msg)) {
217			dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
218
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);
223
224			memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
225				buf, msg->size);
226
227		} else if (space_rem == sizeof(*msg)) {
228			dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
229
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);
233
234		} else {
235			/* Additional data wraps around the ring */
236			memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
237			if (msg->size > 0) {
238				memcpy(bus->m_pdwSetRing + curr_swp +
239					sizeof(*msg), buf, space_rem -
240					sizeof(*msg));
241				memcpy(bus->m_pdwSetRing, (u8 *)buf +
242					space_rem - sizeof(*msg),
243					bytes_to_write - space_rem);
244			}
245
246		}
247
248	} /* (new_swp > bus->m_dwSizeSetRing) */
249	else {
250		dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
251
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,
255			msg->size);
256	}
257
258	dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
259
260	/* TODO: Convert all of the volatiles and direct PCI writes into
261	 * saa7164_writel/b calls for consistency.
262	 */
263
264	/* Update the bus write position */
265	*bus->m_pdwSetWritePos = cpu_to_le32(new_swp);
266	ret = SAA_OK;
267
268out:
269	mutex_unlock(&bus->lock);
270	return ret;
271}
272
273/*
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.
277 *
278 * Return Value:
279 *  0          The function executed successfully.
280 *  < 0        One or more members are not initialized.
281 */
282int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
283	int peekonly)
284{
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;
290
291	if (msg == 0)
292		return ret;
293
294	if (msg->size > dev->bus.m_wMaxReqSize) {
295		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
296			__func__);
297		return ret;
298	}
299
300	if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) {
301		printk(KERN_ERR
302			"%s() Missing msg buf, size should be %d bytes\n",
303			__func__, msg->size);
304		return ret;
305	}
306
307	mutex_lock(&bus->lock);
308
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.
311	 */
312	curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos);
313	curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos);
314
315	if (curr_gwp == curr_grp) {
316		dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__);
317		ret = SAA_ERR_EMPTY;
318		goto out;
319	}
320
321	bytes_to_read = sizeof(*msg);
322
323	/* Calculate write distance to current read position */
324	write_distance = 0;
325	if (curr_gwp >= curr_grp)
326		/* Write doesn't wrap around the ring */
327		write_distance = curr_gwp - curr_grp;
328	else
329		/* Write wraps around the ring */
330		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
331
332	if (bytes_to_read > write_distance) {
333		printk(KERN_ERR "%s() No message/response found\n", __func__);
334		ret = SAA_ERR_INVALID_COMMAND;
335		goto out;
336	}
337
338	/* Calculate the new read position */
339	new_grp = curr_grp + bytes_to_read;
340	if (new_grp > bus->m_dwSizeGetRing) {
341
342		/* Ring wraps */
343		new_grp -= bus->m_dwSizeGetRing;
344		space_rem = bus->m_dwSizeGetRing - curr_grp;
345
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);
349
350	} else {
351		/* No wrapping */
352		memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
353	}
354
355	/* No need to update the read positions, because this was a peek */
356	/* If the caller specifically want to peek, return */
357	if (peekonly) {
358		memcpy(msg, &msg_tmp, sizeof(*msg));
359		goto peekout;
360	}
361
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)) {
366
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;
371		goto out;
372	}
373
374	/* Get the actual command and response from the bus */
375	buf_size = msg->size;
376
377	bytes_to_read = sizeof(*msg) + msg->size;
378	/* Calculate write distance to current read position */
379	write_distance = 0;
380	if (curr_gwp >= curr_grp)
381		/* Write doesn't wrap around the ring */
382		write_distance = curr_gwp - curr_grp;
383	else
384		/* Write wraps around the ring */
385		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
386
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;
391		goto out;
392	}
393
394	/* Calculate the new read position */
395	new_grp = curr_grp + bytes_to_read;
396	if (new_grp > bus->m_dwSizeGetRing) {
397
398		/* Ring wraps */
399		new_grp -= bus->m_dwSizeGetRing;
400		space_rem = bus->m_dwSizeGetRing - curr_grp;
401
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);
407			if (buf)
408				memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
409					space_rem, buf_size);
410
411		} else if (space_rem == sizeof(*msg)) {
412			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
413			if (buf)
414				memcpy(buf, bus->m_pdwGetRing, buf_size);
415		} else {
416			/* Additional data wraps around the ring */
417			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
418			if (buf) {
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 -
423					space_rem);
424			}
425
426		}
427
428	} else {
429		/* No wrapping */
430		memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
431		if (buf)
432			memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
433				buf_size);
434	}
435
436	/* Update the read positions, adjusting the ring */
437	*bus->m_pdwGetReadPos = cpu_to_le32(new_grp);
438
439peekout:
440	msg->size = le16_to_cpu(msg->size);
441	msg->command = le16_to_cpu(msg->command);
442	msg->controlselector = le16_to_cpu(msg->controlselector);
443	ret = SAA_OK;
444out:
445	mutex_unlock(&bus->lock);
446	return ret;
447}
448
449