1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for the NXP SAA7164 PCIe bridge
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "saa7164.h"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun /* The message bus to/from the firmware is a ring buffer in PCI address
11*4882a593Smuzhiyun * space. Establish the defaults.
12*4882a593Smuzhiyun */
saa7164_bus_setup(struct saa7164_dev * dev)13*4882a593Smuzhiyun int saa7164_bus_setup(struct saa7164_dev *dev)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun struct tmComResBusInfo *b = &dev->bus;
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun mutex_init(&b->lock);
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun b->Type = TYPE_BUS_PCIe;
20*4882a593Smuzhiyun b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun b->m_pdwSetRing = (u8 __iomem *)(dev->bmmio +
23*4882a593Smuzhiyun ((u32)dev->busdesc.CommandRing));
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun b->m_pdwGetRing = (u8 __iomem *)(dev->bmmio +
28*4882a593Smuzhiyun ((u32)dev->busdesc.ResponseRing));
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) +
33*4882a593Smuzhiyun (2 * sizeof(u64));
34*4882a593Smuzhiyun b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32));
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32));
37*4882a593Smuzhiyun b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32));
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun return 0;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
saa7164_bus_dump(struct saa7164_dev * dev)42*4882a593Smuzhiyun void saa7164_bus_dump(struct saa7164_dev *dev)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct tmComResBusInfo *b = &dev->bus;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
47*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .type = %d\n", b->Type);
48*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio);
49*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize);
50*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing);
51*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing);
52*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing);
53*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n",
56*4882a593Smuzhiyun b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n",
59*4882a593Smuzhiyun b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n",
62*4882a593Smuzhiyun b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n",
65*4882a593Smuzhiyun b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Intensionally throw a BUG() if the state of the message bus looks corrupt */
saa7164_bus_verify(struct saa7164_dev * dev)70*4882a593Smuzhiyun static void saa7164_bus_verify(struct saa7164_dev *dev)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct tmComResBusInfo *b = &dev->bus;
73*4882a593Smuzhiyun int bug = 0;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
76*4882a593Smuzhiyun bug++;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
79*4882a593Smuzhiyun bug++;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
82*4882a593Smuzhiyun bug++;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
85*4882a593Smuzhiyun bug++;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (bug) {
88*4882a593Smuzhiyun saa_debug = 0xffff; /* Ensure we get the bus dump */
89*4882a593Smuzhiyun saa7164_bus_dump(dev);
90*4882a593Smuzhiyun saa_debug = 1024; /* Ensure we get the bus dump */
91*4882a593Smuzhiyun BUG();
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
saa7164_bus_dumpmsg(struct saa7164_dev * dev,struct tmComResInfo * m,void * buf)95*4882a593Smuzhiyun static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m,
96*4882a593Smuzhiyun void *buf)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
99*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .id = %d\n", m->id);
100*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags);
101*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size);
102*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command);
103*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector);
104*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno);
105*4882a593Smuzhiyun if (buf)
106*4882a593Smuzhiyun dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun * Places a command or a response on the bus. The implementation does not
111*4882a593Smuzhiyun * know if it is a command or a response it just places the data on the
112*4882a593Smuzhiyun * bus depending on the bus information given in the struct tmComResBusInfo
113*4882a593Smuzhiyun * structure. If the command or response does not fit into the bus ring
114*4882a593Smuzhiyun * buffer it will be refused.
115*4882a593Smuzhiyun *
116*4882a593Smuzhiyun * Return Value:
117*4882a593Smuzhiyun * SAA_OK The function executed successfully.
118*4882a593Smuzhiyun * < 0 One or more members are not initialized.
119*4882a593Smuzhiyun */
saa7164_bus_set(struct saa7164_dev * dev,struct tmComResInfo * msg,void * buf)120*4882a593Smuzhiyun int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
121*4882a593Smuzhiyun void *buf)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct tmComResBusInfo *bus = &dev->bus;
124*4882a593Smuzhiyun u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
125*4882a593Smuzhiyun u32 new_swp, space_rem;
126*4882a593Smuzhiyun int ret = SAA_ERR_BAD_PARAMETER;
127*4882a593Smuzhiyun u16 size;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (!msg) {
130*4882a593Smuzhiyun printk(KERN_ERR "%s() !msg\n", __func__);
131*4882a593Smuzhiyun return SAA_ERR_BAD_PARAMETER;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s()\n", __func__);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun saa7164_bus_verify(dev);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (msg->size > dev->bus.m_wMaxReqSize) {
139*4882a593Smuzhiyun printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
140*4882a593Smuzhiyun __func__);
141*4882a593Smuzhiyun return SAA_ERR_BAD_PARAMETER;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if ((msg->size > 0) && (buf == NULL)) {
145*4882a593Smuzhiyun printk(KERN_ERR "%s() Missing message buffer\n", __func__);
146*4882a593Smuzhiyun return SAA_ERR_BAD_PARAMETER;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Lock the bus from any other access */
150*4882a593Smuzhiyun mutex_lock(&bus->lock);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun bytes_to_write = sizeof(*msg) + msg->size;
153*4882a593Smuzhiyun free_write_space = 0;
154*4882a593Smuzhiyun timeout = SAA_BUS_TIMEOUT;
155*4882a593Smuzhiyun curr_srp = saa7164_readl(bus->m_dwSetReadPos);
156*4882a593Smuzhiyun curr_swp = saa7164_readl(bus->m_dwSetWritePos);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Deal with ring wrapping issues */
159*4882a593Smuzhiyun if (curr_srp > curr_swp)
160*4882a593Smuzhiyun /* Deal with the wrapped ring */
161*4882a593Smuzhiyun free_write_space = curr_srp - curr_swp;
162*4882a593Smuzhiyun else
163*4882a593Smuzhiyun /* The ring has not wrapped yet */
164*4882a593Smuzhiyun free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
167*4882a593Smuzhiyun bytes_to_write);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
170*4882a593Smuzhiyun free_write_space);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
173*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* Process the msg and write the content onto the bus */
176*4882a593Smuzhiyun while (bytes_to_write >= free_write_space) {
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (timeout-- == 0) {
179*4882a593Smuzhiyun printk(KERN_ERR "%s() bus timeout\n", __func__);
180*4882a593Smuzhiyun ret = SAA_ERR_NO_RESOURCES;
181*4882a593Smuzhiyun goto out;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* TODO: Review this delay, efficient? */
185*4882a593Smuzhiyun /* Wait, allowing the hardware fetch time */
186*4882a593Smuzhiyun mdelay(1);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* Check the space usage again */
189*4882a593Smuzhiyun curr_srp = saa7164_readl(bus->m_dwSetReadPos);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* Deal with ring wrapping issues */
192*4882a593Smuzhiyun if (curr_srp > curr_swp)
193*4882a593Smuzhiyun /* Deal with the wrapped ring */
194*4882a593Smuzhiyun free_write_space = curr_srp - curr_swp;
195*4882a593Smuzhiyun else
196*4882a593Smuzhiyun /* Read didn't wrap around the buffer */
197*4882a593Smuzhiyun free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
198*4882a593Smuzhiyun curr_swp;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /* Calculate the new write position */
203*4882a593Smuzhiyun new_swp = curr_swp + bytes_to_write;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
206*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
207*4882a593Smuzhiyun bus->m_dwSizeSetRing);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /*
210*4882a593Smuzhiyun * Make a copy of msg->size before it is converted to le16 since it is
211*4882a593Smuzhiyun * used in the code below.
212*4882a593Smuzhiyun */
213*4882a593Smuzhiyun size = msg->size;
214*4882a593Smuzhiyun /* Convert to le16/le32 */
215*4882a593Smuzhiyun msg->size = (__force u16)cpu_to_le16(msg->size);
216*4882a593Smuzhiyun msg->command = (__force u32)cpu_to_le32(msg->command);
217*4882a593Smuzhiyun msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* Check if we're going to wrap again */
222*4882a593Smuzhiyun if (new_swp > bus->m_dwSizeSetRing) {
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Ring wraps */
225*4882a593Smuzhiyun new_swp -= bus->m_dwSizeSetRing;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun space_rem = bus->m_dwSizeSetRing - curr_swp;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
230*4882a593Smuzhiyun space_rem);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
233*4882a593Smuzhiyun (u32)sizeof(*msg));
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun if (space_rem < sizeof(*msg)) {
236*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /* Split the msg into pieces as the ring wraps */
239*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
240*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
241*4882a593Smuzhiyun sizeof(*msg) - space_rem);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
244*4882a593Smuzhiyun buf, size);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun } else if (space_rem == sizeof(*msg)) {
247*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* Additional data at the beginning of the ring */
250*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
251*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing, buf, size);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun } else {
254*4882a593Smuzhiyun /* Additional data wraps around the ring */
255*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
256*4882a593Smuzhiyun if (size > 0) {
257*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp +
258*4882a593Smuzhiyun sizeof(*msg), buf, space_rem -
259*4882a593Smuzhiyun sizeof(*msg));
260*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
261*4882a593Smuzhiyun space_rem - sizeof(*msg),
262*4882a593Smuzhiyun bytes_to_write - space_rem);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun } /* (new_swp > bus->m_dwSizeSetRing) */
268*4882a593Smuzhiyun else {
269*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* The ring buffer doesn't wrap, two simple copies */
272*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
273*4882a593Smuzhiyun memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
274*4882a593Smuzhiyun size);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Update the bus write position */
280*4882a593Smuzhiyun saa7164_writel(bus->m_dwSetWritePos, new_swp);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* Convert back to cpu after writing the msg to the ringbuffer. */
283*4882a593Smuzhiyun msg->size = le16_to_cpu((__force __le16)msg->size);
284*4882a593Smuzhiyun msg->command = le32_to_cpu((__force __le32)msg->command);
285*4882a593Smuzhiyun msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
286*4882a593Smuzhiyun ret = SAA_OK;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun out:
289*4882a593Smuzhiyun saa7164_bus_dump(dev);
290*4882a593Smuzhiyun mutex_unlock(&bus->lock);
291*4882a593Smuzhiyun saa7164_bus_verify(dev);
292*4882a593Smuzhiyun return ret;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * Receive a command or a response from the bus. The implementation does not
297*4882a593Smuzhiyun * know if it is a command or a response it simply dequeues the data,
298*4882a593Smuzhiyun * depending on the bus information given in the struct tmComResBusInfo
299*4882a593Smuzhiyun * structure.
300*4882a593Smuzhiyun *
301*4882a593Smuzhiyun * Return Value:
302*4882a593Smuzhiyun * 0 The function executed successfully.
303*4882a593Smuzhiyun * < 0 One or more members are not initialized.
304*4882a593Smuzhiyun */
saa7164_bus_get(struct saa7164_dev * dev,struct tmComResInfo * msg,void * buf,int peekonly)305*4882a593Smuzhiyun int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
306*4882a593Smuzhiyun void *buf, int peekonly)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct tmComResBusInfo *bus = &dev->bus;
309*4882a593Smuzhiyun u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
310*4882a593Smuzhiyun new_grp, buf_size, space_rem;
311*4882a593Smuzhiyun struct tmComResInfo msg_tmp;
312*4882a593Smuzhiyun int ret = SAA_ERR_BAD_PARAMETER;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun saa7164_bus_verify(dev);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (msg == NULL)
317*4882a593Smuzhiyun return ret;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (msg->size > dev->bus.m_wMaxReqSize) {
320*4882a593Smuzhiyun printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
321*4882a593Smuzhiyun __func__);
322*4882a593Smuzhiyun return ret;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
326*4882a593Smuzhiyun printk(KERN_ERR
327*4882a593Smuzhiyun "%s() Missing msg buf, size should be %d bytes\n",
328*4882a593Smuzhiyun __func__, msg->size);
329*4882a593Smuzhiyun return ret;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun mutex_lock(&bus->lock);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /* Peek the bus to see if a msg exists, if it's not what we're expecting
335*4882a593Smuzhiyun * then return cleanly else read the message from the bus.
336*4882a593Smuzhiyun */
337*4882a593Smuzhiyun curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
338*4882a593Smuzhiyun curr_grp = saa7164_readl(bus->m_dwGetReadPos);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (curr_gwp == curr_grp) {
341*4882a593Smuzhiyun ret = SAA_ERR_EMPTY;
342*4882a593Smuzhiyun goto out;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun bytes_to_read = sizeof(*msg);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* Calculate write distance to current read position */
348*4882a593Smuzhiyun write_distance = 0;
349*4882a593Smuzhiyun if (curr_gwp >= curr_grp)
350*4882a593Smuzhiyun /* Write doesn't wrap around the ring */
351*4882a593Smuzhiyun write_distance = curr_gwp - curr_grp;
352*4882a593Smuzhiyun else
353*4882a593Smuzhiyun /* Write wraps around the ring */
354*4882a593Smuzhiyun write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (bytes_to_read > write_distance) {
357*4882a593Smuzhiyun printk(KERN_ERR "%s() No message/response found\n", __func__);
358*4882a593Smuzhiyun ret = SAA_ERR_INVALID_COMMAND;
359*4882a593Smuzhiyun goto out;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun /* Calculate the new read position */
363*4882a593Smuzhiyun new_grp = curr_grp + bytes_to_read;
364*4882a593Smuzhiyun if (new_grp > bus->m_dwSizeGetRing) {
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* Ring wraps */
367*4882a593Smuzhiyun new_grp -= bus->m_dwSizeGetRing;
368*4882a593Smuzhiyun space_rem = bus->m_dwSizeGetRing - curr_grp;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
371*4882a593Smuzhiyun memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
372*4882a593Smuzhiyun bytes_to_read - space_rem);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun } else {
375*4882a593Smuzhiyun /* No wrapping */
376*4882a593Smuzhiyun memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun /* Convert from little endian to CPU */
379*4882a593Smuzhiyun msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
380*4882a593Smuzhiyun msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
381*4882a593Smuzhiyun msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
382*4882a593Smuzhiyun memcpy(msg, &msg_tmp, sizeof(*msg));
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* No need to update the read positions, because this was a peek */
385*4882a593Smuzhiyun /* If the caller specifically want to peek, return */
386*4882a593Smuzhiyun if (peekonly) {
387*4882a593Smuzhiyun goto peekout;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* Check if the command/response matches what is expected */
391*4882a593Smuzhiyun if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
392*4882a593Smuzhiyun (msg_tmp.controlselector != msg->controlselector) ||
393*4882a593Smuzhiyun (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
396*4882a593Smuzhiyun saa7164_bus_dumpmsg(dev, msg, buf);
397*4882a593Smuzhiyun saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
398*4882a593Smuzhiyun ret = SAA_ERR_INVALID_COMMAND;
399*4882a593Smuzhiyun goto out;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun /* Get the actual command and response from the bus */
403*4882a593Smuzhiyun buf_size = msg->size;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun bytes_to_read = sizeof(*msg) + msg->size;
406*4882a593Smuzhiyun /* Calculate write distance to current read position */
407*4882a593Smuzhiyun write_distance = 0;
408*4882a593Smuzhiyun if (curr_gwp >= curr_grp)
409*4882a593Smuzhiyun /* Write doesn't wrap around the ring */
410*4882a593Smuzhiyun write_distance = curr_gwp - curr_grp;
411*4882a593Smuzhiyun else
412*4882a593Smuzhiyun /* Write wraps around the ring */
413*4882a593Smuzhiyun write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun if (bytes_to_read > write_distance) {
416*4882a593Smuzhiyun printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n",
417*4882a593Smuzhiyun __func__);
418*4882a593Smuzhiyun ret = SAA_ERR_INVALID_COMMAND;
419*4882a593Smuzhiyun goto out;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* Calculate the new read position */
423*4882a593Smuzhiyun new_grp = curr_grp + bytes_to_read;
424*4882a593Smuzhiyun if (new_grp > bus->m_dwSizeGetRing) {
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Ring wraps */
427*4882a593Smuzhiyun new_grp -= bus->m_dwSizeGetRing;
428*4882a593Smuzhiyun space_rem = bus->m_dwSizeGetRing - curr_grp;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (space_rem < sizeof(*msg)) {
431*4882a593Smuzhiyun if (buf)
432*4882a593Smuzhiyun memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
433*4882a593Smuzhiyun space_rem, buf_size);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun } else if (space_rem == sizeof(*msg)) {
436*4882a593Smuzhiyun if (buf)
437*4882a593Smuzhiyun memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
438*4882a593Smuzhiyun } else {
439*4882a593Smuzhiyun /* Additional data wraps around the ring */
440*4882a593Smuzhiyun if (buf) {
441*4882a593Smuzhiyun memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
442*4882a593Smuzhiyun sizeof(*msg), space_rem - sizeof(*msg));
443*4882a593Smuzhiyun memcpy_fromio(buf + space_rem - sizeof(*msg),
444*4882a593Smuzhiyun bus->m_pdwGetRing, bytes_to_read -
445*4882a593Smuzhiyun space_rem);
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun } else {
451*4882a593Smuzhiyun /* No wrapping */
452*4882a593Smuzhiyun if (buf)
453*4882a593Smuzhiyun memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
454*4882a593Smuzhiyun buf_size);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* Update the read positions, adjusting the ring */
458*4882a593Smuzhiyun saa7164_writel(bus->m_dwGetReadPos, new_grp);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun peekout:
461*4882a593Smuzhiyun ret = SAA_OK;
462*4882a593Smuzhiyun out:
463*4882a593Smuzhiyun mutex_unlock(&bus->lock);
464*4882a593Smuzhiyun saa7164_bus_verify(dev);
465*4882a593Smuzhiyun return ret;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468