saa7164-bus.c revision 773ddbd228dc16a4829836e1dc16383e44c8575e
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 */
27int 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 *)(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_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
56void 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 */
84void 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
109void 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 */
134int 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
142	if (!msg) {
143		printk(KERN_ERR "%s() !msg\n", __func__);
144		return SAA_ERR_BAD_PARAMETER;
145	}
146
147	dprintk(DBGLVL_BUS, "%s()\n", __func__);
148
149	saa7164_bus_verify(dev);
150
151	msg->size = cpu_to_le16(msg->size);
152	msg->command = cpu_to_le32(msg->command);
153	msg->controlselector = cpu_to_le16(msg->controlselector);
154
155	if (msg->size > dev->bus.m_wMaxReqSize) {
156		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
157			__func__);
158		return SAA_ERR_BAD_PARAMETER;
159	}
160
161	if ((msg->size > 0) && (buf == NULL)) {
162		printk(KERN_ERR "%s() Missing message buffer\n", __func__);
163		return SAA_ERR_BAD_PARAMETER;
164	}
165
166	/* Lock the bus from any other access */
167	mutex_lock(&bus->lock);
168
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));
174
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;
179	else
180		/* The ring has not wrapped yet */
181		free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
182
183	dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
184		bytes_to_write);
185
186	dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
187		free_write_space);
188
189	dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
190	dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
191
192	/* Process the msg and write the content onto the bus */
193	while (bytes_to_write >= free_write_space) {
194
195		if (timeout-- == 0) {
196			printk(KERN_ERR "%s() bus timeout\n", __func__);
197			ret = SAA_ERR_NO_RESOURCES;
198			goto out;
199		}
200
201		/* TODO: Review this delay, efficient? */
202		/* Wait, allowing the hardware fetch time */
203		mdelay(1);
204
205		/* Check the space usage again */
206		curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
207
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;
212		else
213			/* Read didn't wrap around the buffer */
214			free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
215				curr_swp;
216
217	}
218
219	/* Calculate the new write position */
220	new_swp = curr_swp + bytes_to_write;
221
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);
225
226	/* Mental Note: line 462 tmmhComResBusPCIe.cpp */
227
228	/* Check if we're going to wrap again */
229	if (new_swp > bus->m_dwSizeSetRing) {
230
231		/* Ring wraps */
232		new_swp -= bus->m_dwSizeSetRing;
233
234		space_rem = bus->m_dwSizeSetRing - curr_swp;
235
236		dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
237			space_rem);
238
239		dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
240			(u32)sizeof(*msg));
241
242		if (space_rem < sizeof(*msg)) {
243			dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
244
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);
249
250			memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
251				buf, msg->size);
252
253		} else if (space_rem == sizeof(*msg)) {
254			dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
255
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);
259
260		} else {
261			/* Additional data wraps around the ring */
262			memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
263			if (msg->size > 0) {
264				memcpy(bus->m_pdwSetRing + curr_swp +
265					sizeof(*msg), buf, space_rem -
266					sizeof(*msg));
267				memcpy(bus->m_pdwSetRing, (u8 *)buf +
268					space_rem - sizeof(*msg),
269					bytes_to_write - space_rem);
270			}
271
272		}
273
274	} /* (new_swp > bus->m_dwSizeSetRing) */
275	else {
276		dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
277
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,
281			msg->size);
282	}
283
284	dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
285
286	/* Update the bus write position */
287	saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
288	ret = SAA_OK;
289
290out:
291	saa7164_bus_dump(dev);
292	mutex_unlock(&bus->lock);
293	saa7164_bus_verify(dev);
294	return ret;
295}
296
297/*
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
301 * structure.
302 *
303 * Return Value:
304 *  0          The function executed successfully.
305 *  < 0        One or more members are not initialized.
306 */
307int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
308	void *buf, int peekonly)
309{
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;
315
316	saa7164_bus_verify(dev);
317
318	if (msg == NULL)
319		return ret;
320
321	if (msg->size > dev->bus.m_wMaxReqSize) {
322		printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
323			__func__);
324		return ret;
325	}
326
327	if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
328		printk(KERN_ERR
329			"%s() Missing msg buf, size should be %d bytes\n",
330			__func__, msg->size);
331		return ret;
332	}
333
334	mutex_lock(&bus->lock);
335
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.
338	 */
339	curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
340	curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
341
342	if (curr_gwp == curr_grp) {
343		ret = SAA_ERR_EMPTY;
344		goto out;
345	}
346
347	bytes_to_read = sizeof(*msg);
348
349	/* Calculate write distance to current read position */
350	write_distance = 0;
351	if (curr_gwp >= curr_grp)
352		/* Write doesn't wrap around the ring */
353		write_distance = curr_gwp - curr_grp;
354	else
355		/* Write wraps around the ring */
356		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
357
358	if (bytes_to_read > write_distance) {
359		printk(KERN_ERR "%s() No message/response found\n", __func__);
360		ret = SAA_ERR_INVALID_COMMAND;
361		goto out;
362	}
363
364	/* Calculate the new read position */
365	new_grp = curr_grp + bytes_to_read;
366	if (new_grp > bus->m_dwSizeGetRing) {
367
368		/* Ring wraps */
369		new_grp -= bus->m_dwSizeGetRing;
370		space_rem = bus->m_dwSizeGetRing - curr_grp;
371
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);
375
376	} else {
377		/* No wrapping */
378		memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
379	}
380
381	/* No need to update the read positions, because this was a peek */
382	/* If the caller specifically want to peek, return */
383	if (peekonly) {
384		memcpy(msg, &msg_tmp, sizeof(*msg));
385		goto peekout;
386	}
387
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)) {
392
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;
397		goto out;
398	}
399
400	/* Get the actual command and response from the bus */
401	buf_size = msg->size;
402
403	bytes_to_read = sizeof(*msg) + msg->size;
404	/* Calculate write distance to current read position */
405	write_distance = 0;
406	if (curr_gwp >= curr_grp)
407		/* Write doesn't wrap around the ring */
408		write_distance = curr_gwp - curr_grp;
409	else
410		/* Write wraps around the ring */
411		write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
412
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;
417		goto out;
418	}
419
420	/* Calculate the new read position */
421	new_grp = curr_grp + bytes_to_read;
422	if (new_grp > bus->m_dwSizeGetRing) {
423
424		/* Ring wraps */
425		new_grp -= bus->m_dwSizeGetRing;
426		space_rem = bus->m_dwSizeGetRing - curr_grp;
427
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);
433			if (buf)
434				memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
435					space_rem, buf_size);
436
437		} else if (space_rem == sizeof(*msg)) {
438			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
439			if (buf)
440				memcpy(buf, bus->m_pdwGetRing, buf_size);
441		} else {
442			/* Additional data wraps around the ring */
443			memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
444			if (buf) {
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 -
449					space_rem);
450			}
451
452		}
453
454	} else {
455		/* No wrapping */
456		memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
457		if (buf)
458			memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
459				buf_size);
460	}
461
462	/* Update the read positions, adjusting the ring */
463	saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
464
465peekout:
466	msg->size = le16_to_cpu(msg->size);
467	msg->command = le32_to_cpu(msg->command);
468	msg->controlselector = le16_to_cpu(msg->controlselector);
469	ret = SAA_OK;
470out:
471	mutex_unlock(&bus->lock);
472	saa7164_bus_verify(dev);
473	return ret;
474}
475
476