Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
saa7164-buffer.c
Go to the documentation of this file.
1 /*
2  * Driver for the NXP SAA7164 PCIe bridge
3  *
4  * Copyright (c) 2010 Steven Toth <[email protected]>
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 <linux/slab.h>
23 
24 #include "saa7164.h"
25 
26 /* The PCI address space for buffer handling looks like this:
27  *
28  * +-u32 wide-------------+
29  * | +
30  * +-u64 wide------------------------------------+
31  * + +
32  * +----------------------+
33  * | CurrentBufferPtr + Pointer to current PCI buffer >-+
34  * +----------------------+ |
35  * | Unused + |
36  * +----------------------+ |
37  * | Pitch + = 188 (bytes) |
38  * +----------------------+ |
39  * | PCI buffer size + = pitch * number of lines (312) |
40  * +----------------------+ |
41  * |0| Buf0 Write Offset + |
42  * +----------------------+ v
43  * |1| Buf1 Write Offset + |
44  * +----------------------+ |
45  * |2| Buf2 Write Offset + |
46  * +----------------------+ |
47  * |3| Buf3 Write Offset + |
48  * +----------------------+ |
49  * ... More write offsets |
50  * +---------------------------------------------+ |
51  * +0| set of ptrs to PCI pagetables + |
52  * +---------------------------------------------+ |
53  * +1| set of ptrs to PCI pagetables + <--------+
54  * +---------------------------------------------+
55  * +2| set of ptrs to PCI pagetables +
56  * +---------------------------------------------+
57  * +3| set of ptrs to PCI pagetables + >--+
58  * +---------------------------------------------+ |
59  * ... More buffer pointers | +----------------+
60  * +->| pt[0] TS data |
61  * | +----------------+
62  * |
63  * | +----------------+
64  * +->| pt[1] TS data |
65  * | +----------------+
66  * | etc
67  */
68 
70 {
71  struct saa7164_dev *dev = buf->port->dev;
72  int i;
73 
74  dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n",
75  __func__, buf, buf->idx);
76  dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n",
77  buf->cpu, (long long)buf->dma, buf->pci_size);
78  dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
79  buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
80 
81  /* Format the Page Table Entries to point into the data buffer */
82  for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
83 
84  dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n",
85  i, buf->pt_cpu, (u64)*(buf->pt_cpu));
86 
87  }
88 }
89 /* Allocate a new buffer structure and associated PCI space in bytes.
90  * len must be a multiple of sizeof(u64)
91  */
93  u32 len)
94 {
96  struct saa7164_buffer *buf = NULL;
97  struct saa7164_dev *dev = port->dev;
98  int i;
99 
100  if ((len == 0) || (len >= 65536) || (len % sizeof(u64))) {
101  log_warn("%s() SAA_ERR_BAD_PARAMETER\n", __func__);
102  goto ret;
103  }
104 
105  buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL);
106  if (!buf) {
107  log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__);
108  goto ret;
109  }
110 
111  buf->idx = -1;
112  buf->port = port;
113  buf->flags = SAA7164_BUFFER_FREE;
114  buf->pos = 0;
115  buf->actual_size = params->pitch * params->numberoflines;
116  buf->crc = 0;
117  /* TODO: arg len is being ignored */
118  buf->pci_size = SAA7164_PT_ENTRIES * 0x1000;
119  buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000;
120 
121  /* Allocate contiguous memory */
122  buf->cpu = pci_alloc_consistent(port->dev->pci, buf->pci_size,
123  &buf->dma);
124  if (!buf->cpu)
125  goto fail1;
126 
127  buf->pt_cpu = pci_alloc_consistent(port->dev->pci, buf->pt_size,
128  &buf->pt_dma);
129  if (!buf->pt_cpu)
130  goto fail2;
131 
132  /* init the buffers to a known pattern, easier during debugging */
133  memset_io(buf->cpu, 0xff, buf->pci_size);
134  buf->crc = crc32(0, buf->cpu, buf->actual_size);
135  memset_io(buf->pt_cpu, 0xff, buf->pt_size);
136 
137  dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p (%d pageptrs)\n",
138  __func__, buf, params->numpagetables);
139  dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n",
140  buf->cpu, (long)buf->dma, buf->pci_size);
141  dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n",
142  buf->pt_cpu, (long)buf->pt_dma, buf->pt_size);
143 
144  /* Format the Page Table Entries to point into the data buffer */
145  for (i = 0 ; i < params->numpagetables; i++) {
146 
147  *(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */
148  dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n",
149  i, buf->pt_cpu, (u64)*(buf->pt_cpu));
150 
151  }
152 
153  goto ret;
154 
155 fail2:
156  pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma);
157 fail1:
158  kfree(buf);
159 
160  buf = NULL;
161 ret:
162  return buf;
163 }
164 
166 {
167  struct saa7164_dev *dev;
168 
169  if (!buf || !buf->port)
170  return SAA_ERR_BAD_PARAMETER;
171  dev = buf->port->dev;
172 
173  dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n",
174  __func__, buf);
175 
176  if (buf->flags != SAA7164_BUFFER_FREE)
177  log_warn(" freeing a non-free buffer\n");
178 
179  pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma);
180  pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma);
181 
182  kfree(buf);
183 
184  return SAA_OK;
185 }
186 
188 {
189  struct saa7164_dev *dev = port->dev;
190 
191  if ((i < 0) || (i >= port->hwcfg.buffercount))
192  return -EINVAL;
193 
194  dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
195 
196  saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
197 
198  return 0;
199 }
200 
201 /* Write a buffer into the hardware */
203 {
204  struct saa7164_port *port = buf->port;
205  struct saa7164_dev *dev = port->dev;
206 
207  if ((i < 0) || (i >= port->hwcfg.buffercount))
208  return -EINVAL;
209 
210  dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
211 
212  buf->idx = i; /* Note of which buffer list index position we occupy */
213  buf->flags = SAA7164_BUFFER_BUSY;
214  buf->pos = 0;
215 
216  /* TODO: Review this in light of 32v64 assignments */
217  saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
218  saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma);
219  saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
220 
221  dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) "
222  "buf 0x%llx/%llx (0x%x/%x) nr=%d\n",
223  buf->idx,
224  (u64)port->bufoffset + (i * sizeof(u32)),
225  saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
226  (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
227  (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
228  saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)),
229  saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)),
230  buf->idx);
231 
232  return 0;
233 }
234 
236 {
238  struct saa7164_dev *dev = port->dev;
239  struct saa7164_buffer *buf;
240  struct list_head *c, *n;
241  int i = 0;
242 
243  dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr);
244 
245  saa7164_writel(port->bufcounter, 0);
246  saa7164_writel(port->pitch, params->pitch);
247  saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
248 
249  dprintk(DBGLVL_BUF, " configured:\n");
250  dprintk(DBGLVL_BUF, " lmmio 0x%p\n", dev->lmmio);
251  dprintk(DBGLVL_BUF, " bufcounter 0x%x = 0x%x\n", port->bufcounter,
252  saa7164_readl(port->bufcounter));
253 
254  dprintk(DBGLVL_BUF, " pitch 0x%x = %d\n", port->pitch,
255  saa7164_readl(port->pitch));
256 
257  dprintk(DBGLVL_BUF, " bufsize 0x%x = %d\n", port->bufsize,
258  saa7164_readl(port->bufsize));
259 
260  dprintk(DBGLVL_BUF, " buffercount = %d\n", port->hwcfg.buffercount);
261  dprintk(DBGLVL_BUF, " bufoffset = 0x%x\n", port->bufoffset);
262  dprintk(DBGLVL_BUF, " bufptr32h = 0x%x\n", port->bufptr32h);
263  dprintk(DBGLVL_BUF, " bufptr32l = 0x%x\n", port->bufptr32l);
264 
265  /* Poke the buffers and offsets into PCI space */
266  mutex_lock(&port->dmaqueue_lock);
267  list_for_each_safe(c, n, &port->dmaqueue.list) {
268  buf = list_entry(c, struct saa7164_buffer, list);
269 
270  if (buf->flags != SAA7164_BUFFER_FREE)
271  BUG();
272 
273  /* Place the buffer in the h/w queue */
274  saa7164_buffer_activate(buf, i);
275 
276  /* Don't exceed the device maximum # bufs */
277  if (i++ > port->hwcfg.buffercount)
278  BUG();
279 
280  }
281  mutex_unlock(&port->dmaqueue_lock);
282 
283  return 0;
284 }
285 
287  u32 len)
288 {
289  struct saa7164_user_buffer *buf;
290 
291  buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
292  if (!buf)
293  return NULL;
294 
295  buf->data = kzalloc(len, GFP_KERNEL);
296 
297  if (!buf->data) {
298  kfree(buf);
299  return NULL;
300  }
301 
302  buf->actual_size = len;
303  buf->pos = 0;
304  buf->crc = 0;
305 
306  dprintk(DBGLVL_BUF, "%s() allocated user buffer @ 0x%p\n",
307  __func__, buf);
308 
309  return buf;
310 }
311 
313 {
314  if (!buf)
315  return;
316 
317  kfree(buf->data);
318  buf->data = NULL;
319 
320  kfree(buf);
321 }
322