Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
p2m.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3  * Copyright (C) 2010 Ben Collins <[email protected]>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/scatterlist.h>
23 #include "solo6x10.h"
24 
25 /* #define SOLO_TEST_P2M */
26 
27 int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
28  void *sys_addr, u32 ext_addr, u32 size)
29 {
31  int ret;
32 
33  WARN_ON(!size);
34  BUG_ON(id >= SOLO_NR_P2M);
35 
36  if (!size)
37  return -EINVAL;
38 
39  dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
41 
42  ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
43 
44  pci_unmap_single(solo_dev->pdev, dma_addr, size,
45  wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
46 
47  return ret;
48 }
49 
50 int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
51  dma_addr_t dma_addr, u32 ext_addr, u32 size)
52 {
53  struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
54  int ret;
55 
56  if (desc == NULL)
57  return -ENOMEM;
58 
59  solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
60  ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
61  kfree(desc);
62 
63  return ret;
64 }
65 
67  u32 ext_addr, u32 size, int repeat, u32 ext_size)
68 {
69  desc->ta = cpu_to_le32(dma_addr);
70  desc->fa = cpu_to_le32(ext_addr);
71 
72  desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2));
74  (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
75 
76  /* Ext size only matters when we're repeating */
77  if (repeat) {
78  desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2));
79  desc->ctrl |= cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) |
80  SOLO_P2M_REPEAT(repeat));
81  }
82 }
83 
85  struct p2m_desc *desc, int desc_count)
86 {
87  struct solo_p2m_dev *p2m_dev;
88  unsigned int timeout;
89  int ret = 0;
90  u32 config = 0;
91  dma_addr_t desc_dma = 0;
92 
93  BUG_ON(id >= SOLO_NR_P2M);
94  BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
95 
96  p2m_dev = &solo_dev->p2m_dev[id];
97 
98  mutex_lock(&p2m_dev->mutex);
99 
100  solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
101 
102  INIT_COMPLETION(p2m_dev->completion);
103  p2m_dev->error = 0;
104 
105  /* Enable the descriptors */
106  config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
107  desc_dma = pci_map_single(solo_dev->pdev, desc,
108  desc_count * sizeof(*desc),
110  solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
111  solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
112  solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
114 
115  /* Should have all descriptors completed from one interrupt */
116  timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
117 
118  solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
119 
120  /* Reset back to non-descriptor mode */
121  solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
122  solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
123  solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
124  pci_unmap_single(solo_dev->pdev, desc_dma,
125  desc_count * sizeof(*desc),
127 
128  if (p2m_dev->error)
129  ret = -EIO;
130  else if (timeout == 0)
131  ret = -EAGAIN;
132 
133  mutex_unlock(&p2m_dev->mutex);
134 
135  WARN_ON_ONCE(ret);
136 
137  return ret;
138 }
139 
141  struct p2m_desc *pdesc, int wr,
142  struct scatterlist *sg, u32 sg_off,
143  u32 ext_addr, u32 size)
144 {
145  int i;
146  int idx;
147 
148  BUG_ON(id >= SOLO_NR_P2M);
149 
150  if (WARN_ON_ONCE(!size))
151  return -EINVAL;
152 
153  memset(pdesc, 0, sizeof(*pdesc));
154 
155  /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
156  for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
157  i++, sg = sg_next(sg)) {
158  struct p2m_desc *desc = &pdesc[idx];
159  u32 sg_len = sg_dma_len(sg);
160  u32 len;
161 
162  if (sg_off >= sg_len) {
163  sg_off -= sg_len;
164  continue;
165  }
166 
167  sg_len -= sg_off;
168  len = min(sg_len, size);
169 
170  solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
171  ext_addr, len, 0, 0);
172 
173  size -= len;
174  ext_addr += len;
175  idx++;
176 
177  sg_off = 0;
178  }
179 
180  WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
181 
182  return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
183 }
184 
185 #ifdef SOLO_TEST_P2M
186 
187 #define P2M_TEST_CHAR 0xbe
188 
189 static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
190  u32 base, int size)
191 {
192  u8 *wr_buf;
193  u8 *rd_buf;
194  int i;
195  unsigned long long err_cnt = 0;
196 
197  wr_buf = kmalloc(size, GFP_KERNEL);
198  if (!wr_buf) {
199  printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
200  return size;
201  }
202 
203  rd_buf = kmalloc(size, GFP_KERNEL);
204  if (!rd_buf) {
205  printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
206  kfree(wr_buf);
207  return size;
208  }
209 
210  memset(wr_buf, P2M_TEST_CHAR, size);
211  memset(rd_buf, P2M_TEST_CHAR + 1, size);
212 
213  solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
214  solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
215 
216  for (i = 0; i < size; i++)
217  if (wr_buf[i] != rd_buf[i])
218  err_cnt++;
219 
220  kfree(wr_buf);
221  kfree(rd_buf);
222 
223  return err_cnt;
224 }
225 
226 #define TEST_CHUNK_SIZE (8 * 1024)
227 
228 static void run_p2m_test(struct solo_dev *solo_dev)
229 {
230  unsigned long long errs = 0;
231  u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
232  int i, d;
233 
234  printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
235  SOLO6X10_NAME, size);
236 
237  for (i = 0; i < size; i += TEST_CHUNK_SIZE)
238  for (d = 0; d < 4; d++)
239  errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
240 
241  printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
242  SOLO6X10_NAME, errs);
243 
244  return;
245 }
246 #else
247 #define run_p2m_test(__solo) do {} while (0)
248 #endif
249 
250 void solo_p2m_isr(struct solo_dev *solo_dev, int id)
251 {
252  struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
253 
254  solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
255 
256  complete(&p2m_dev->completion);
257 }
258 
259 void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
260 {
261  struct solo_p2m_dev *p2m_dev;
262  int i;
263 
264  if (!(status & SOLO_PCI_ERR_P2M))
265  return;
266 
267  for (i = 0; i < SOLO_NR_P2M; i++) {
268  p2m_dev = &solo_dev->p2m_dev[i];
269  p2m_dev->error = 1;
270  solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
271  complete(&p2m_dev->completion);
272  }
273 }
274 
275 void solo_p2m_exit(struct solo_dev *solo_dev)
276 {
277  int i;
278 
279  for (i = 0; i < SOLO_NR_P2M; i++)
280  solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
281 }
282 
283 int solo_p2m_init(struct solo_dev *solo_dev)
284 {
285  struct solo_p2m_dev *p2m_dev;
286  int i;
287 
288  for (i = 0; i < SOLO_NR_P2M; i++) {
289  p2m_dev = &solo_dev->p2m_dev[i];
290 
291  mutex_init(&p2m_dev->mutex);
292  init_completion(&p2m_dev->completion);
293 
294  solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
295  solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
300  solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
301  }
302 
303  run_p2m_test(solo_dev);
304 
305  return 0;
306 }