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 __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
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 */
84static 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
109static 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 */
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	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
302out:
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 */
319int 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
485peekout:
486	ret = SAA_OK;
487out:
488	mutex_unlock(&bus->lock);
489	saa7164_bus_verify(dev);
490	return ret;
491}
492
493