Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fec.c
Go to the documentation of this file.
1 /*
2  * Bestcomm FEC tasks driver
3  *
4  *
5  * Copyright (C) 2006-2007 Sylvain Munaut <[email protected]>
6  * Copyright (C) 2003-2004 MontaVista, Software, Inc.
7  * ( by Dale Farnsworth <[email protected]> )
8  *
9  * This file is licensed under the terms of the GNU General Public License
10  * version 2. This program is licensed "as is" without any warranty of any
11  * kind, whether express or implied.
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <asm/io.h>
18 
19 #include "bestcomm.h"
20 #include "bestcomm_priv.h"
21 #include "fec.h"
22 
23 
24 /* ======================================================================== */
25 /* Task image/var/inc */
26 /* ======================================================================== */
27 
28 /* fec tasks images */
29 extern u32 bcom_fec_rx_task[];
30 extern u32 bcom_fec_tx_task[];
31 
32 /* rx task vars that need to be set before enabling the task */
34  u32 enable; /* (u16*) address of task's control register */
35  u32 fifo; /* (u32*) address of fec's fifo */
36  u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
37  u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
38  u32 bd_start; /* (struct bcom_bd*) current bd */
39  u32 buffer_size; /* size of receive buffer */
40 };
41 
42 /* rx task incs that need to be set before enabling the task */
50 };
51 
52 /* tx task vars that need to be set before enabling the task */
54  u32 DRD; /* (u32*) address of self-modified DRD */
55  u32 fifo; /* (u32*) address of fec's fifo */
56  u32 enable; /* (u16*) address of task's control register */
57  u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
58  u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
59  u32 bd_start; /* (struct bcom_bd*) current bd */
60  u32 buffer_size; /* set by uCode for each packet */
61 };
62 
63 /* tx task incs that need to be set before enabling the task */
71 };
72 
73 /* private structure in the task */
74 struct bcom_fec_priv {
77 };
78 
79 
80 /* ======================================================================== */
81 /* Task support code */
82 /* ======================================================================== */
83 
84 struct bcom_task *
85 bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
86 {
87  struct bcom_task *tsk;
88  struct bcom_fec_priv *priv;
89 
90  tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
91  sizeof(struct bcom_fec_priv));
92  if (!tsk)
93  return NULL;
94 
95  tsk->flags = BCOM_FLAGS_NONE;
96 
97  priv = tsk->priv;
98  priv->fifo = fifo;
99  priv->maxbufsize = maxbufsize;
100 
101  if (bcom_fec_rx_reset(tsk)) {
102  bcom_task_free(tsk);
103  return NULL;
104  }
105 
106  return tsk;
107 }
109 
110 int
112 {
113  struct bcom_fec_priv *priv = tsk->priv;
114  struct bcom_fec_rx_var *var;
115  struct bcom_fec_rx_inc *inc;
116 
117  /* Shutdown the task */
118  bcom_disable_task(tsk->tasknum);
119 
120  /* Reset the microcode */
121  var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);
122  inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);
123 
125  return -1;
126 
127  var->enable = bcom_eng->regs_base +
128  offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
129  var->fifo = (u32) priv->fifo;
130  var->bd_base = tsk->bd_pa;
131  var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
132  var->bd_start = tsk->bd_pa;
133  var->buffer_size = priv->maxbufsize;
134 
135  inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */
136  inc->incr_dst = sizeof(u32); /* task image, but we stick */
137  inc->incr_dst_ma= sizeof(u8); /* to the official ones */
138 
139  /* Reset the BDs */
140  tsk->index = 0;
141  tsk->outdex = 0;
142 
143  memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
144 
145  /* Configure some stuff */
146  bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
147  bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
148 
150 
151  out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
152 
153  return 0;
154 }
156 
157 void
159 {
160  /* Nothing special for the FEC tasks */
161  bcom_task_free(tsk);
162 }
164 
165 
166 
167  /* Return 2nd to last DRD */
168  /* This is an ugly hack, but at least it's only done
169  once at initialization */
170 static u32 *self_modified_drd(int tasknum)
171 {
172  u32 *desc;
173  int num_descs;
174  int drd_count;
175  int i;
176 
177  num_descs = bcom_task_num_descs(tasknum);
178  desc = bcom_task_desc(tasknum) + num_descs - 1;
179  drd_count = 0;
180  for (i=0; i<num_descs; i++, desc--)
181  if (bcom_desc_is_drd(*desc) && ++drd_count == 3)
182  break;
183  return desc;
184 }
185 
186 struct bcom_task *
188 {
189  struct bcom_task *tsk;
190  struct bcom_fec_priv *priv;
191 
192  tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
193  sizeof(struct bcom_fec_priv));
194  if (!tsk)
195  return NULL;
196 
198 
199  priv = tsk->priv;
200  priv->fifo = fifo;
201 
202  if (bcom_fec_tx_reset(tsk)) {
203  bcom_task_free(tsk);
204  return NULL;
205  }
206 
207  return tsk;
208 }
210 
211 int
213 {
214  struct bcom_fec_priv *priv = tsk->priv;
215  struct bcom_fec_tx_var *var;
216  struct bcom_fec_tx_inc *inc;
217 
218  /* Shutdown the task */
219  bcom_disable_task(tsk->tasknum);
220 
221  /* Reset the microcode */
222  var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);
223  inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);
224 
226  return -1;
227 
228  var->enable = bcom_eng->regs_base +
229  offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
230  var->fifo = (u32) priv->fifo;
231  var->DRD = bcom_sram_va2pa(self_modified_drd(tsk->tasknum));
232  var->bd_base = tsk->bd_pa;
233  var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
234  var->bd_start = tsk->bd_pa;
235 
236  inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */
237  inc->incr_src = sizeof(u32); /* task image, but we stick */
238  inc->incr_src_ma= sizeof(u8); /* to the official ones */
239 
240  /* Reset the BDs */
241  tsk->index = 0;
242  tsk->outdex = 0;
243 
244  memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
245 
246  /* Configure some stuff */
247  bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
248  bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
249 
251 
252  out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
253 
254  return 0;
255 }
257 
258 void
260 {
261  /* Nothing special for the FEC tasks */
262  bcom_task_free(tsk);
263 }
265 
266 
267 MODULE_DESCRIPTION("BestComm FEC tasks driver");
268 MODULE_AUTHOR("Dale Farnsworth <[email protected]>");
269 MODULE_LICENSE("GPL v2");
270