1 | /* |
---|
2 | * Authorship |
---|
3 | * ---------- |
---|
4 | * This software ('mvme3100' RTEMS BSP) was created by |
---|
5 | * |
---|
6 | * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, |
---|
7 | * Stanford Linear Accelerator Center, Stanford University. |
---|
8 | * |
---|
9 | * Acknowledgement of sponsorship |
---|
10 | * ------------------------------ |
---|
11 | * The 'mvme3100' BSP was produced by |
---|
12 | * the Stanford Linear Accelerator Center, Stanford University, |
---|
13 | * under Contract DE-AC03-76SFO0515 with the Department of Energy. |
---|
14 | * |
---|
15 | * Government disclaimer of liability |
---|
16 | * ---------------------------------- |
---|
17 | * Neither the United States nor the United States Department of Energy, |
---|
18 | * nor any of their employees, makes any warranty, express or implied, or |
---|
19 | * assumes any legal liability or responsibility for the accuracy, |
---|
20 | * completeness, or usefulness of any data, apparatus, product, or process |
---|
21 | * disclosed, or represents that its use would not infringe privately owned |
---|
22 | * rights. |
---|
23 | * |
---|
24 | * Stanford disclaimer of liability |
---|
25 | * -------------------------------- |
---|
26 | * Stanford University makes no representations or warranties, express or |
---|
27 | * implied, nor assumes any liability for the use of this software. |
---|
28 | * |
---|
29 | * Stanford disclaimer of copyright |
---|
30 | * -------------------------------- |
---|
31 | * Stanford University, owner of the copyright, hereby disclaims its |
---|
32 | * copyright and all other rights in this software. Hence, anyone may |
---|
33 | * freely use it for any purpose without restriction. |
---|
34 | * |
---|
35 | * Maintenance of notices |
---|
36 | * ---------------------- |
---|
37 | * In the interest of clarity regarding the origin and status of this |
---|
38 | * SLAC software, this and all the preceding Stanford University notices |
---|
39 | * are to remain affixed to any copy or derivative of this software made |
---|
40 | * or distributed by the recipient and are to be affixed to any copy of |
---|
41 | * software made or distributed by the recipient that contains a copy or |
---|
42 | * derivative of this software. |
---|
43 | * |
---|
44 | * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 |
---|
45 | */ |
---|
46 | |
---|
47 | #include <rtems.h> |
---|
48 | #include <rtems/error.h> |
---|
49 | #include <bsp/irq.h> |
---|
50 | #include <libcpu/byteorder.h> |
---|
51 | #include <inttypes.h> |
---|
52 | #include <stdio.h> |
---|
53 | #include <assert.h> |
---|
54 | #include <bsp.h> |
---|
55 | |
---|
56 | #ifndef KERNEL |
---|
57 | #define KERNEL |
---|
58 | #endif |
---|
59 | #ifndef _KERNEL |
---|
60 | #define _KERNEL |
---|
61 | #endif |
---|
62 | |
---|
63 | #include <rtems/rtems_bsdnet.h> |
---|
64 | #include <sys/mbuf.h> |
---|
65 | #include <sys/socket.h> |
---|
66 | #include <sys/sockio.h> |
---|
67 | #include <net/ethernet.h> |
---|
68 | #include <net/if.h> |
---|
69 | #include <netinet/in.h> |
---|
70 | #include <netinet/if_ether.h> |
---|
71 | #include <rtems/rtems_mii_ioctl.h> |
---|
72 | |
---|
73 | #include <bsp/if_tsec_pub.h> |
---|
74 | |
---|
75 | #define STATIC |
---|
76 | #define PARANOIA |
---|
77 | #undef DEBUG |
---|
78 | |
---|
79 | |
---|
80 | #ifdef TEST_MII_TIMING |
---|
81 | |
---|
82 | #include <libcpu/spr.h> |
---|
83 | |
---|
84 | SPR_RO(TBRL) |
---|
85 | |
---|
86 | static inline uint32_t tb_rd() |
---|
87 | { |
---|
88 | return _read_TBRL(); |
---|
89 | } |
---|
90 | #endif |
---|
91 | |
---|
92 | struct tsec_private; |
---|
93 | |
---|
94 | /* Forward declarations */ |
---|
95 | static void |
---|
96 | phy_init_irq( int install, struct tsec_private *mp, void (*tsec_lisr)(rtems_irq_hdl_param) ); |
---|
97 | |
---|
98 | static void |
---|
99 | phy_en_irq(struct tsec_private *mp); |
---|
100 | |
---|
101 | static void |
---|
102 | phy_en_irq_at_phy(struct tsec_private *mp); |
---|
103 | |
---|
104 | static void |
---|
105 | phy_dis_irq(struct tsec_private *mp); |
---|
106 | |
---|
107 | static void |
---|
108 | phy_dis_irq_at_phy(struct tsec_private *mp); |
---|
109 | |
---|
110 | static int |
---|
111 | phy_irq_pending(struct tsec_private *mp); |
---|
112 | |
---|
113 | static uint32_t |
---|
114 | phy_ack_irq(struct tsec_private *mp); |
---|
115 | |
---|
116 | #if defined(PARANOIA) || defined(DEBUG) |
---|
117 | void tsec_dump_tring(struct tsec_private *mp); |
---|
118 | void tsec_dump_rring(struct tsec_private *mp); |
---|
119 | #endif |
---|
120 | |
---|
121 | #ifdef DEBUG |
---|
122 | #ifdef TSEC_RX_RING_SIZE |
---|
123 | #undef TSEC_RX_RING_SIZE |
---|
124 | #endif |
---|
125 | #define TSEC_RX_RING_SIZE 4 |
---|
126 | |
---|
127 | #ifdef TSEC_TX_RING_SIZE |
---|
128 | #undef TSEC_TX_RING_SIZE |
---|
129 | #endif |
---|
130 | #define TSEC_TX_RING_SIZE 2 |
---|
131 | #else |
---|
132 | #ifndef TSEC_RX_RING_SIZE |
---|
133 | #define TSEC_RX_RING_SIZE 40 |
---|
134 | #endif |
---|
135 | #ifndef TSEC_TX_RING_SIZE |
---|
136 | #define TSEC_TX_RING_SIZE 200 |
---|
137 | #endif |
---|
138 | #endif |
---|
139 | |
---|
140 | /********** Helper Macros and Definitions ******/ |
---|
141 | |
---|
142 | /* |
---|
143 | * Align 'p' up to a multiple of 'a' which must be |
---|
144 | * a power of two. Result is cast to (uintptr_t) |
---|
145 | */ |
---|
146 | #define ALIGNTO(p,a) ((((uintptr_t)(p)) + (a) - 1) & ~((a)-1)) |
---|
147 | |
---|
148 | |
---|
149 | /* |
---|
150 | * Not obvious from the doc: RX buffers apparently must be 32-byte |
---|
151 | * aligned :-(; TX buffers have no alignment requirement. |
---|
152 | * I found this by testing, T.S, 11/2007 |
---|
153 | */ |
---|
154 | #define RX_BUF_ALIGNMENT 32 |
---|
155 | |
---|
156 | /* |
---|
157 | * Alignment req. for buffer descriptors (BDs) |
---|
158 | */ |
---|
159 | #define BD_ALIGNMENT 8 |
---|
160 | |
---|
161 | |
---|
162 | #define ETH_RX_OFFSET 0 |
---|
163 | #define ETH_CRC_LEN 0 |
---|
164 | |
---|
165 | #define CPU2BUS_ADDR(x) (x) |
---|
166 | #define BUS2CPU_ADDR(x) (x) |
---|
167 | |
---|
168 | /* |
---|
169 | * Whether to automatically try to reclaim descriptors |
---|
170 | * when enqueueing new packets |
---|
171 | */ |
---|
172 | #if 1 |
---|
173 | #define TSEC_CLEAN_ON_SEND(mp) (BSP_tsec_swipe_tx(mp)) |
---|
174 | #else |
---|
175 | #define TSEC_CLEAN_ON_SEND(mp) (-1) |
---|
176 | #endif |
---|
177 | |
---|
178 | #define TX_AVAILABLE_RING_SIZE(mp) (mp)->tx_ring_size |
---|
179 | |
---|
180 | #define DRVNAME "tsec" |
---|
181 | |
---|
182 | /* |
---|
183 | * Event(s) posted by ISRs to driver task |
---|
184 | */ |
---|
185 | #define EV_PER_UNIT 1 |
---|
186 | |
---|
187 | #define TSEC_ETH_EVENT( unit ) ( 1 << (EV_PER_UNIT * (unit) )) |
---|
188 | #if EV_PER_UNIT > 1 |
---|
189 | #define TSEC_PHY_EVENT( unit ) ( 1 << (EV_PER_UNIT * (unit) + 1)) |
---|
190 | #endif |
---|
191 | |
---|
192 | #define EV_IS_ETH(ev) ( (ev) & 1 ) |
---|
193 | #if EV_PER_UNIT > 1 |
---|
194 | #define EV_IS_PHY(ev) ( (ev) & 2 ) |
---|
195 | #endif |
---|
196 | |
---|
197 | #define EV_IS_ANY(ev) ( (ev) & ((1<<EV_PER_UNIT) - 1) ) |
---|
198 | |
---|
199 | #define EV_MSK ( ( 1 << (EV_PER_UNIT * TSEC_NUM_DRIVER_SLOTS) ) - 1) |
---|
200 | |
---|
201 | |
---|
202 | /********** Register Definitions ****************/ |
---|
203 | |
---|
204 | /* |
---|
205 | * Most registers/bits apply to the FEC also; |
---|
206 | * things that are not supported by the FEC |
---|
207 | * are commented 'TSEC only' |
---|
208 | */ |
---|
209 | |
---|
210 | #define TSEC_IEVENT 0x010 |
---|
211 | #define TSEC_IEVENT_BABR (1<<(31- 0)) |
---|
212 | #define TSEC_IEVENT_RXC (1<<(31- 1)) |
---|
213 | #define TSEC_IEVENT_BSY (1<<(31- 2)) |
---|
214 | #define TSEC_IEVENT_EBERR (1<<(31- 3)) |
---|
215 | /* |
---|
216 | * Misuse reserved bit 4 to flag link interrupts |
---|
217 | * (which are totally external to the TSEC). |
---|
218 | * Because reading the MII is so slow we don't |
---|
219 | * want to poll MII unnecessarily from RX/TX ISRs |
---|
220 | */ |
---|
221 | #define TSEC_LINK_INTR (1<<(31- 4)) |
---|
222 | #define TSEC_IEVENT_MSRO (1<<(31- 5)) |
---|
223 | #define TSEC_IEVENT_GTSC (1<<(31- 6)) |
---|
224 | #define TSEC_IEVENT_BABT (1<<(31- 7)) |
---|
225 | #define TSEC_IEVENT_TXC (1<<(31- 8)) |
---|
226 | #define TSEC_IEVENT_TXE (1<<(31- 9)) |
---|
227 | #define TSEC_IEVENT_TXB (1<<(31-10)) |
---|
228 | #define TSEC_IEVENT_TXF (1<<(31-11)) |
---|
229 | #define TSEC_IEVENT_LC (1<<(31-13)) |
---|
230 | #define TSEC_IEVENT_CRLXDA (1<<(31-14)) |
---|
231 | #define TSEC_IEVENT_XFUN (1<<(31-15)) |
---|
232 | #define TSEC_IEVENT_RXB (1<<(31-16)) |
---|
233 | #define TSEC_IEVENT_GRSC (1<<(31-23)) |
---|
234 | #define TSEC_IEVENT_RXF (1<<(31-24)) |
---|
235 | #define TSEC_IEVENT_ALL (-1) |
---|
236 | |
---|
237 | #define TSEC_TXIRQ ( TSEC_IEVENT_TXE | TSEC_IEVENT_TXF ) |
---|
238 | #define TSEC_RXIRQ ( TSEC_IEVENT_RXF | TSEC_IEVENT_BABR | TSEC_IEVENT_EBERR ) |
---|
239 | |
---|
240 | #define TSEC_IMASK 0x014 |
---|
241 | #define TSEC_IMASK_BABREN (1<<(31- 0)) |
---|
242 | #define TSEC_IMASK_RXCEN (1<<(31- 1)) |
---|
243 | #define TSEC_IMASK_BSYEN (1<<(31- 2)) |
---|
244 | #define TSEC_IMASK_EBERREN (1<<(31- 3)) |
---|
245 | #define TSEC_IMASK_MSROEN (1<<(31- 5)) |
---|
246 | #define TSEC_IMASK_GTSCEN (1<<(31- 6)) |
---|
247 | #define TSEC_IMASK_BABTEN (1<<(31- 7)) |
---|
248 | #define TSEC_IMASK_TXCEN (1<<(31- 8)) |
---|
249 | #define TSEC_IMASK_TXEEN (1<<(31- 9)) |
---|
250 | #define TSEC_IMASK_TXBEN (1<<(31-10)) |
---|
251 | #define TSEC_IMASK_TXFEN (1<<(31-11)) |
---|
252 | #define TSEC_IMASK_LCEN (1<<(31-13)) |
---|
253 | #define TSEC_IMASK_CRLXDAEN (1<<(31-14)) |
---|
254 | #define TSEC_IMASK_XFUNEN (1<<(31-15)) |
---|
255 | #define TSEC_IMASK_RXBEN (1<<(31-16)) |
---|
256 | #define TSEC_IMASK_GRSCEN (1<<(31-23)) |
---|
257 | #define TSEC_IMASK_RXFEN (1<<(31-24)) |
---|
258 | #define TSEC_IMASK_NONE (0) |
---|
259 | #define TSEC_EDIS 0x018 |
---|
260 | #define TSEC_ECNTRL 0x020 /* TSEC only */ |
---|
261 | #define TSEC_ECNTRL_CLRCNT (1<<(31-17)) |
---|
262 | #define TSEC_ECNTRL_AUTOZ (1<<(31-18)) |
---|
263 | #define TSEC_ECNTRL_STEN (1<<(31-19)) |
---|
264 | #define TSEC_ECNTRL_TBIM (1<<(31-26)) |
---|
265 | #define TSEC_ECNTRL_RPM (1<<(31-27)) |
---|
266 | #define TSEC_ECNTRL_R100M (1<<(31-28)) |
---|
267 | #define TSEC_MINFLR 0x024 |
---|
268 | #define TSEC_PTV 0x028 |
---|
269 | #define TSEC_DMACTRL 0x02c |
---|
270 | #define TSEC_DMACTRL_TDSEN (1<<(31-24)) |
---|
271 | #define TSEC_DMACTRL_TBDSEN (1<<(31-25)) |
---|
272 | #define TSEC_DMACTRL_GRS (1<<(31-27)) |
---|
273 | #define TSEC_DMACTRL_GTS (1<<(31-28)) |
---|
274 | #define TSEC_DMACTRL_WWR (1<<(31-30)) |
---|
275 | #define TSEC_DMACTRL_WOP (1<<(31-31)) |
---|
276 | #define TSEC_TBIPA 0x030 /* TSEC only */ |
---|
277 | #define TSEC_FIFO_PAUSE_CTRL 0x04c |
---|
278 | #define TSEC_FIFO_TX_THR 0x08c |
---|
279 | #define TSEC_FIFO_TX_STARVE 0x098 |
---|
280 | #define TSEC_FIFO_TX_STARVE_SHUTOFF 0x09c |
---|
281 | #define TSEC_TCTRL 0x100 |
---|
282 | #define TSEC_TCTRL_THDR (1<<(31-20)) |
---|
283 | #define TSEC_TCTRL_RFC_PAUSE (1<<(31-27)) |
---|
284 | #define TSEC_TCTRL_TFC_PAUSE (1<<(31-28)) |
---|
285 | #define TSEC_TSTAT 0x104 |
---|
286 | #define TSEC_TSTAT_THLT (1<<(31- 0)) |
---|
287 | #define TSEC_TBDLEN 0x10c |
---|
288 | #define TSEC_TXIC 0x110 /* TSEC only */ |
---|
289 | #define TSEC_IC_ICEN (1<<(31- 0)) |
---|
290 | #define TSEC_IC_ICFCT(x) (((x)&0xff)<<(31-10)) |
---|
291 | #define TSEC_IC_ICTT(x) (((x)&0xffff)<<(31-31)) |
---|
292 | #define TSEC_CTBPTR 0x124 |
---|
293 | #define TSEC_TBPTR 0x184 |
---|
294 | #define TSEC_TBASE 0x204 |
---|
295 | #define TSEC_OSTBD 0x2b0 |
---|
296 | #define TSEC_OSTBDP 0x2b4 |
---|
297 | #define TSEC_RCTRL 0x300 |
---|
298 | #define TSEC_RCTRL_BC_REJ (1<<(31-27)) |
---|
299 | #define TSEC_RCTRL_PROM (1<<(31-28)) |
---|
300 | #define TSEC_RCTRL_RSF (1<<(31-29)) |
---|
301 | #define TSEC_RSTAT 0x304 |
---|
302 | #define TSEC_RSTAT_QHLT (1<<(31- 8)) |
---|
303 | #define TSEC_RBDLEN 0x30c |
---|
304 | #define TSEC_RXIC 0x310 /* TSEC only */ |
---|
305 | #define TSEC_CRBPTR 0x324 |
---|
306 | #define TSEC_MRBLR 0x340 |
---|
307 | #define TSEC_RBPTR 0x384 |
---|
308 | #define TSEC_RBASE 0x404 |
---|
309 | #define TSEC_MACCFG1 0x500 |
---|
310 | #define TSEC_MACCFG1_SOFT_RESET (1<<(31- 0)) |
---|
311 | #define TSEC_MACCFG1_LOOP_BACK (1<<(31-23)) |
---|
312 | #define TSEC_MACCFG1_RX_FLOW (1<<(31-26)) |
---|
313 | #define TSEC_MACCFG1_TX_FLOW (1<<(31-27)) |
---|
314 | #define TSEC_MACCFG1_SYNCD_RX_EN (1<<(31-28)) |
---|
315 | #define TSEC_MACCFG1_RX_EN (1<<(31-29)) |
---|
316 | #define TSEC_MACCFG1_SYNCD_TX_EN (1<<(31-30)) |
---|
317 | #define TSEC_MACCFG1_TX_EN (1<<(31-31)) |
---|
318 | #define TSEC_MACCFG2 0x504 |
---|
319 | #define TSEC_MACCFG2_PREAMBLE_7 (7<<(31-19)) |
---|
320 | #define TSEC_MACCFG2_PREAMBLE_15 (15<<(31-19)) |
---|
321 | #define TSEC_MACCFG2_IF_MODE_MII (1<<(31-23)) |
---|
322 | #define TSEC_MACCFG2_IF_MODE_GMII (2<<(31-23)) |
---|
323 | #define TSEC_MACCFG2_HUGE_FRAME (1<<(31-26)) |
---|
324 | #define TSEC_MACCFG2_LENGTH_CHECK (1<<(31-27)) |
---|
325 | #define TSEC_MACCFG2_PAD_CRC (1<<(31-29)) |
---|
326 | #define TSEC_MACCFG2_CRC_EN (1<<(31-30)) |
---|
327 | #define TSEC_MACCFG2_FD (1<<(31-31)) |
---|
328 | #define TSEC_IPGIFG 0x508 |
---|
329 | #define TSEC_HAFDUP 0x50c |
---|
330 | #define TSEC_MAXFRM 0x510 |
---|
331 | #define TSEC_MIIMCFG 0x520 /* TSEC only */ |
---|
332 | #define TSEC_MIIMCOM 0x524 /* TSEC only */ |
---|
333 | #define TSEC_MIIMCOM_SCAN (1<<(31-30)) |
---|
334 | #define TSEC_MIIMCOM_READ (1<<(31-31)) |
---|
335 | #define TSEC_MIIMADD 0x528 /* TSEC only */ |
---|
336 | #define TSEC_MIIMADD_ADDR(phy, reg) ((((phy)&0x1f)<<8) | ((reg) & 0x1f)) |
---|
337 | #define TSEC_MIIMCON 0x52c /* TSEC only */ |
---|
338 | #define TSEC_MIIMSTAT 0x530 /* TSEC only */ |
---|
339 | #define TSEC_MIIMIND 0x534 /* TSEC only */ |
---|
340 | #define TSEC_MIIMIND_NV (1<<(31-29)) |
---|
341 | #define TSEC_MIIMIND_SCAN (1<<(31-30)) |
---|
342 | #define TSEC_MIIMIND_BUSY (1<<(31-31)) |
---|
343 | #define TSEC_IFSTAT 0x53c |
---|
344 | #define TSEC_MACSTNADDR1 0x540 |
---|
345 | #define TSEC_MACSTNADDR2 0x544 |
---|
346 | #define TSEC_TR64 0x680 /* TSEC only */ |
---|
347 | #define TSEC_TR127 0x684 /* TSEC only */ |
---|
348 | #define TSEC_TR255 0x688 /* TSEC only */ |
---|
349 | #define TSEC_TR511 0x68c /* TSEC only */ |
---|
350 | #define TSEC_TR1K 0x690 /* TSEC only */ |
---|
351 | #define TSEC_TRMAX 0x694 /* TSEC only */ |
---|
352 | #define TSEC_TRMGV 0x698 /* TSEC only */ |
---|
353 | #define TSEC_RBYT 0x69c /* TSEC only */ |
---|
354 | #define TSEC_RPKT 0x6a0 /* TSEC only */ |
---|
355 | #define TSEC_RFCS 0x6a4 /* TSEC only */ |
---|
356 | #define TSEC_RMCA 0x6a8 /* TSEC only */ |
---|
357 | #define TSEC_RBCA 0x6ac /* TSEC only */ |
---|
358 | #define TSEC_RXCF 0x6b0 /* TSEC only */ |
---|
359 | #define TSEC_RXPF 0x6b4 /* TSEC only */ |
---|
360 | #define TSEC_RXUO 0x6b8 /* TSEC only */ |
---|
361 | #define TSEC_RALN 0x6bc /* TSEC only */ |
---|
362 | #define TSEC_RFLR 0x6c0 /* TSEC only */ |
---|
363 | #define TSEC_RCDE 0x6c4 /* TSEC only */ |
---|
364 | #define TSEC_RCSE 0x6c8 /* TSEC only */ |
---|
365 | #define TSEC_RUND 0x6cc /* TSEC only */ |
---|
366 | #define TSEC_ROVR 0x6d0 /* TSEC only */ |
---|
367 | #define TSEC_RFRG 0x6d4 /* TSEC only */ |
---|
368 | #define TSEC_RJBR 0x6d8 /* TSEC only */ |
---|
369 | #define TSEC_RDRP 0x6dc /* TSEC only */ |
---|
370 | #define TSEC_TBYT 0x6e0 /* TSEC only */ |
---|
371 | #define TSEC_TPKT 0x6e4 /* TSEC only */ |
---|
372 | #define TSEC_TMCA 0x6e8 /* TSEC only */ |
---|
373 | #define TSEC_TBCA 0x6ec /* TSEC only */ |
---|
374 | #define TSEC_TXPF 0x6f0 /* TSEC only */ |
---|
375 | #define TSEC_TDFR 0x6f4 /* TSEC only */ |
---|
376 | #define TSEC_TEDF 0x6f8 /* TSEC only */ |
---|
377 | #define TSEC_TSCL 0x6fc /* TSEC only */ |
---|
378 | #define TSEC_TMCL 0x700 /* TSEC only */ |
---|
379 | #define TSEC_TLCL 0x704 /* TSEC only */ |
---|
380 | #define TSEC_TXCL 0x708 /* TSEC only */ |
---|
381 | #define TSEC_TNCL 0x70c /* TSEC only */ |
---|
382 | #define TSEC_TDRP 0x714 /* TSEC only */ |
---|
383 | #define TSEC_TJBR 0x718 /* TSEC only */ |
---|
384 | #define TSEC_TFCS 0x71c /* TSEC only */ |
---|
385 | #define TSEC_TXCF 0x720 /* TSEC only */ |
---|
386 | #define TSEC_TOVR 0x724 /* TSEC only */ |
---|
387 | #define TSEC_TUND 0x728 /* TSEC only */ |
---|
388 | #define TSEC_TFRG 0x72c /* TSEC only */ |
---|
389 | #define TSEC_CAR1 0x730 /* TSEC only */ |
---|
390 | #define TSEC_CAR2 0x734 /* TSEC only */ |
---|
391 | #define TSEC_CAM1 0x738 /* TSEC only */ |
---|
392 | #define TSEC_CAM2 0x73c /* TSEC only */ |
---|
393 | #define TSEC_IADDR0 0x800 |
---|
394 | #define TSEC_IADDR1 0x804 |
---|
395 | #define TSEC_IADDR2 0x808 |
---|
396 | #define TSEC_IADDR3 0x80c |
---|
397 | #define TSEC_IADDR4 0x810 |
---|
398 | #define TSEC_IADDR5 0x814 |
---|
399 | #define TSEC_IADDR6 0x818 |
---|
400 | #define TSEC_IADDR7 0x81c |
---|
401 | #define TSEC_GADDR0 0x880 |
---|
402 | #define TSEC_GADDR1 0x884 |
---|
403 | #define TSEC_GADDR2 0x888 |
---|
404 | #define TSEC_GADDR3 0x88c |
---|
405 | #define TSEC_GADDR4 0x890 |
---|
406 | #define TSEC_GADDR5 0x894 |
---|
407 | #define TSEC_GADDR6 0x898 |
---|
408 | #define TSEC_GADDR7 0x89c |
---|
409 | #define TSEC_ATTR 0xbf8 |
---|
410 | #define TSEC_ATTR_ELCWT_NONE (0<<(31-18)) |
---|
411 | #define TSEC_ATTR_ELCWT_ALLOC (2<<(31-18)) |
---|
412 | #define TSEC_ATTR_ELCWT_ALLOC_LOCK (3<<(31-18)) |
---|
413 | #define TSEC_ATTR_BDLWT_NONE (0<<(31-21)) |
---|
414 | #define TSEC_ATTR_BDLWT_ALLOC (2<<(31-21)) |
---|
415 | #define TSEC_ATTR_BDLWT_ALLOC_LOCK (3<<(31-21)) |
---|
416 | #define TSEC_ATTR_RDSEN (1<<(31-24)) |
---|
417 | #define TSEC_ATTR_RBDSEN (1<<(31-25)) |
---|
418 | #define TSEC_ATTRELI 0xbfc |
---|
419 | |
---|
420 | /********** Memory Barriers *********************/ |
---|
421 | |
---|
422 | #ifdef __PPC__ |
---|
423 | static inline void membarrier(void) |
---|
424 | { |
---|
425 | asm volatile("sync":::"memory"); |
---|
426 | } |
---|
427 | |
---|
428 | #define EIEIO(mem) do { asm volatile("eieio"); } while (0) |
---|
429 | |
---|
430 | #else |
---|
431 | #error "memory barrier not implemented for your CPU architecture" |
---|
432 | #endif |
---|
433 | |
---|
434 | /********** Register Access Primitives **********/ |
---|
435 | |
---|
436 | /* |
---|
437 | * Typedef for base address (uint8_t *) so that |
---|
438 | * we can do easy pointer arithmetic. |
---|
439 | */ |
---|
440 | typedef volatile uint8_t *FEC_Enet_Base; |
---|
441 | |
---|
442 | /* |
---|
443 | * All TSEC/FEC registers are 32-bit only. |
---|
444 | */ |
---|
445 | typedef volatile uint32_t FEC_Reg __attribute__((may_alias)); |
---|
446 | |
---|
447 | static inline uint32_t |
---|
448 | fec_rd(FEC_Enet_Base b, uint32_t reg) |
---|
449 | { |
---|
450 | #ifdef __BIG_ENDIAN__ |
---|
451 | uint32_t rval = *(FEC_Reg *)(b + reg); |
---|
452 | EIEIO(*(FEC_Reg*)(b+reg)); |
---|
453 | return rval; |
---|
454 | #else |
---|
455 | return in_be32( (volatile uint32_t*) (b+reg) ); |
---|
456 | #endif |
---|
457 | } |
---|
458 | |
---|
459 | static inline void |
---|
460 | fec_wr(FEC_Enet_Base b, uint32_t reg, uint32_t val) |
---|
461 | { |
---|
462 | #ifdef __BIG_ENDIAN__ |
---|
463 | *(FEC_Reg *)(b + reg) = val; |
---|
464 | EIEIO(*(FEC_Reg*)(b+reg)); |
---|
465 | #else |
---|
466 | out_be32( (volatile uint32_t*) (b+reg), val ); |
---|
467 | #endif |
---|
468 | } |
---|
469 | |
---|
470 | /* Set bits in a register */ |
---|
471 | static inline void |
---|
472 | fec_set(FEC_Enet_Base b, uint32_t reg, uint32_t val) |
---|
473 | { |
---|
474 | fec_wr(b, reg, fec_rd(b, reg) | val ); |
---|
475 | } |
---|
476 | |
---|
477 | /* Clear bits in a register */ |
---|
478 | static inline void |
---|
479 | fec_clr(FEC_Enet_Base b, uint32_t reg, uint32_t val) |
---|
480 | { |
---|
481 | fec_wr(b, reg, fec_rd(b, reg) & ~val ); |
---|
482 | } |
---|
483 | |
---|
484 | /* Clear and set bits in a register */ |
---|
485 | static inline void |
---|
486 | fec_csl(FEC_Enet_Base b, uint32_t reg, uint32_t clr, uint32_t set) |
---|
487 | { |
---|
488 | fec_wr(b, reg, (fec_rd(b, reg) & ~clr) | set); |
---|
489 | } |
---|
490 | |
---|
491 | |
---|
492 | /********** Memory Access Primitives ************/ |
---|
493 | |
---|
494 | #ifdef __BIG_ENDIAN__ |
---|
495 | static inline uint16_t ld_be16(volatile uint16_t *a) |
---|
496 | { |
---|
497 | return *a; |
---|
498 | } |
---|
499 | |
---|
500 | static inline uint32_t ld_be32(volatile uint32_t *a) |
---|
501 | { |
---|
502 | return *a; |
---|
503 | } |
---|
504 | |
---|
505 | static inline void st_be16(volatile uint16_t *a, uint16_t v) |
---|
506 | { |
---|
507 | *a = v; |
---|
508 | } |
---|
509 | |
---|
510 | static inline void st_be32(volatile uint32_t *a, uint32_t v) |
---|
511 | { |
---|
512 | *a = v; |
---|
513 | } |
---|
514 | #else |
---|
515 | #error "ld_be32 & friends not implemented" |
---|
516 | #endif |
---|
517 | |
---|
518 | /********** Note About Coherency ****************/ |
---|
519 | |
---|
520 | #ifdef SW_COHERENCY |
---|
521 | #error "SW_COHERENCY not implemented" |
---|
522 | /* Note: maintaining BD coherency in software is not trivial |
---|
523 | * because BDs are smaller than a cache line; |
---|
524 | * we cannot pad a BD to the length of a cache line because |
---|
525 | * the TSEC assumes BDs layed out sequentially in memory. |
---|
526 | * We cannot use zero-length BDs to pad to a full cache |
---|
527 | * line either because the manual says that the length |
---|
528 | * field of a TX BD must not be zero. |
---|
529 | * |
---|
530 | * We probably would need MMU resources to map BDs |
---|
531 | * as non-cachable. |
---|
532 | * |
---|
533 | * Maintaining buffer coherency would be easier: |
---|
534 | * - make RX buffers cache aligned so we can |
---|
535 | * invalidate them w/o overlapping other data. |
---|
536 | * - TX buffers may be flushed to memory. If cache |
---|
537 | * lines overlap anything else (besides TX buffers) |
---|
538 | * then that would only be harmful if (part of) a |
---|
539 | * TX buffer would share a cache line with another |
---|
540 | * type of DMA buffer that is written by another |
---|
541 | * master. Note that BDs have exactly this problem; |
---|
542 | * we may not flush one BD because the TSEC could |
---|
543 | * have written another BD to memory covered by |
---|
544 | * the same cache line. |
---|
545 | * This second BD could be lost by a DBCF operation: |
---|
546 | * - writes 1st BD to memory OK |
---|
547 | * - overwrites 2nd BD with stale data from cache |
---|
548 | */ |
---|
549 | #else |
---|
550 | #define FLUSH_BUF(addr, len) do {} while(0) |
---|
551 | #endif |
---|
552 | |
---|
553 | /********** Driver Data Structures **************/ |
---|
554 | |
---|
555 | /* Buffer descriptor layout (defined by hardware) */ |
---|
556 | struct tsec_bd { |
---|
557 | volatile uint16_t flags; |
---|
558 | volatile uint16_t len; |
---|
559 | volatile uint32_t buf; |
---|
560 | }; |
---|
561 | |
---|
562 | typedef struct tsec_bd TSEC_BD __attribute__((aligned(BD_ALIGNMENT))); |
---|
563 | |
---|
564 | /* BD access primitives */ |
---|
565 | |
---|
566 | static inline uint16_t bd_rdfl(TSEC_BD *bd) |
---|
567 | { |
---|
568 | return ld_be16( & bd->flags ); |
---|
569 | } |
---|
570 | |
---|
571 | static inline void bd_wrfl(TSEC_BD *bd, uint16_t v) |
---|
572 | { |
---|
573 | st_be16( &bd->flags, v ); |
---|
574 | } |
---|
575 | |
---|
576 | static inline void bd_setfl(TSEC_BD *bd, uint16_t v) |
---|
577 | { |
---|
578 | bd_wrfl(bd, bd_rdfl(bd) | v ); |
---|
579 | } |
---|
580 | |
---|
581 | static inline void bd_clrfl(TSEC_BD *bd, uint16_t v) |
---|
582 | { |
---|
583 | bd_wrfl(bd, bd_rdfl(bd) & ~v ); |
---|
584 | } |
---|
585 | |
---|
586 | static inline void bd_cslfl(TSEC_BD *bd, uint16_t s, uint16_t c) |
---|
587 | { |
---|
588 | bd_wrfl( bd, ( bd_rdfl(bd) & ~c ) | s ); |
---|
589 | } |
---|
590 | |
---|
591 | static inline uint32_t bd_rdbuf(TSEC_BD *bd) |
---|
592 | { |
---|
593 | return BUS2CPU_ADDR( ld_be32( &bd->buf ) ); |
---|
594 | } |
---|
595 | |
---|
596 | static inline void bd_wrbuf(TSEC_BD *bd, uint32_t addr) |
---|
597 | { |
---|
598 | st_be32( &bd->buf, CPU2BUS_ADDR(addr) ); |
---|
599 | } |
---|
600 | |
---|
601 | /* BD bit definitions */ |
---|
602 | |
---|
603 | #define TSEC_TXBD_R ((uint16_t)(1<<(15- 0))) |
---|
604 | #define TSEC_TXBD_PAD_CRC ((uint16_t)(1<<(15- 1))) |
---|
605 | #define TSEC_TXBD_W ((uint16_t)(1<<(15- 2))) |
---|
606 | #define TSEC_TXBD_I ((uint16_t)(1<<(15- 3))) |
---|
607 | #define TSEC_TXBD_L ((uint16_t)(1<<(15- 4))) |
---|
608 | #define TSEC_TXBD_TC ((uint16_t)(1<<(15- 5))) |
---|
609 | #define TSEC_TXBD_DEF ((uint16_t)(1<<(15- 6))) |
---|
610 | #define TSEC_TXBD_TO1 ((uint16_t)(1<<(15- 7))) |
---|
611 | #define TSEC_TXBD_HFE_LC ((uint16_t)(1<<(15- 8))) |
---|
612 | #define TSEC_TXBD_RL ((uint16_t)(1<<(15- 9))) |
---|
613 | #define TSEC_TXBD_RC(x) ((uint16_t)(((x)>>2)&0xf)) |
---|
614 | #define TSEC_TXBD_UN ((uint16_t)(1<<(15-14))) |
---|
615 | #define TSEC_TXBD_TXTRUNC ((uint16_t)(1<<(15-15))) |
---|
616 | #define TSEC_TXBD_ERRS (TSEC_TXBD_RL | TSEC_TXBD_UN | TSEC_TXBD_TXTRUNC) |
---|
617 | |
---|
618 | #define TSEC_RXBD_E ((uint16_t)(1<<(15- 0))) |
---|
619 | #define TSEC_RXBD_RO1 ((uint16_t)(1<<(15- 1))) |
---|
620 | #define TSEC_RXBD_W ((uint16_t)(1<<(15- 2))) |
---|
621 | #define TSEC_RXBD_I ((uint16_t)(1<<(15- 3))) |
---|
622 | #define TSEC_RXBD_L ((uint16_t)(1<<(15- 4))) |
---|
623 | #define TSEC_RXBD_F ((uint16_t)(1<<(15- 5))) |
---|
624 | #define TSEC_RXBD_M ((uint16_t)(1<<(15- 7))) |
---|
625 | #define TSEC_RXBD_BC ((uint16_t)(1<<(15- 8))) |
---|
626 | #define TSEC_RXBD_MC ((uint16_t)(1<<(15- 9))) |
---|
627 | #define TSEC_RXBD_LG ((uint16_t)(1<<(15-10))) |
---|
628 | #define TSEC_RXBD_NO ((uint16_t)(1<<(15-11))) |
---|
629 | #define TSEC_RXBD_SH ((uint16_t)(1<<(15-12))) |
---|
630 | #define TSEC_RXBD_CR ((uint16_t)(1<<(15-13))) |
---|
631 | #define TSEC_RXBD_OV ((uint16_t)(1<<(15-14))) |
---|
632 | #define TSEC_RXBD_TR ((uint16_t)(1<<(15-15))) |
---|
633 | |
---|
634 | #define TSEC_RXBD_ERROR \ |
---|
635 | (TSEC_RXBD_LG | TSEC_RXBD_NO | TSEC_RXBD_SH | TSEC_RXBD_CR | TSEC_RXBD_OV | TSEC_RXBD_TR ) |
---|
636 | |
---|
637 | /* Driver 'private' data */ |
---|
638 | |
---|
639 | struct tsec_private { |
---|
640 | FEC_Enet_Base base; /* Controller base address */ |
---|
641 | FEC_Enet_Base phy_base; /* Phy base address (not necessarily identical |
---|
642 | * with controller base address); |
---|
643 | * e.g., phy attached to 2nd controller may be |
---|
644 | * connected to mii bus of 1st controller. |
---|
645 | */ |
---|
646 | unsigned phy; /* Phy address on mii bus */ |
---|
647 | unsigned unit; /* Driver instance (one-based */ |
---|
648 | int isfec; /* Set if a FEC (not TSEC) controller */ |
---|
649 | struct tsec_softc *sc; /* Pointer to BSD driver struct */ |
---|
650 | TSEC_BD *ring_area; /* Not necessarily aligned */ |
---|
651 | TSEC_BD *tx_ring; /* Aligned array of TX BDs */ |
---|
652 | void **tx_ring_user; /* Array of user pointers (1 per BD) */ |
---|
653 | unsigned tx_ring_size; |
---|
654 | unsigned tx_head; /* first 'dirty' BD; chip is working on */ |
---|
655 | unsigned tx_tail; /* BDs between head and tail */ |
---|
656 | unsigned tx_avail; /* Number of available/free TX BDs */ |
---|
657 | TSEC_BD *rx_ring; /* Aligned array of RX BDs */ |
---|
658 | void **rx_ring_user; /* Array of user pointers (1 per BD) */ |
---|
659 | unsigned rx_tail; /* Where we left off scanning for full bufs */ |
---|
660 | unsigned rx_ring_size; |
---|
661 | void (*cleanup_txbuf) /* Callback to cleanup TX ring */ |
---|
662 | (void*, void*, int); |
---|
663 | void *cleanup_txbuf_arg; |
---|
664 | void *(*alloc_rxbuf) /* Callback for allocating RX buffer */ |
---|
665 | (int *psize, uintptr_t *paddr); |
---|
666 | void (*consume_rxbuf) /* callback to consume RX buffer */ |
---|
667 | (void*, void*, int); |
---|
668 | void *consume_rxbuf_arg; |
---|
669 | rtems_id tid; /* driver task ID */ |
---|
670 | uint32_t irq_mask; |
---|
671 | uint32_t irq_pending; |
---|
672 | rtems_event_set event; /* Task synchronization events */ |
---|
673 | struct { /* Statistics */ |
---|
674 | unsigned xirqs; |
---|
675 | unsigned rirqs; |
---|
676 | unsigned eirqs; |
---|
677 | unsigned lirqs; |
---|
678 | unsigned maxchain; |
---|
679 | unsigned packet; |
---|
680 | unsigned odrops; |
---|
681 | unsigned repack; |
---|
682 | } stats; |
---|
683 | }; |
---|
684 | |
---|
685 | #define NEXT_TXI(mp, i) (((i)+1) < (mp)->tx_ring_size ? (i)+1 : 0 ) |
---|
686 | #define NEXT_RXI(mp, i) (((i)+1) < (mp)->rx_ring_size ? (i)+1 : 0 ) |
---|
687 | |
---|
688 | /* Stuff needed for bsdnet support */ |
---|
689 | struct tsec_bsdsupp { |
---|
690 | int oif_flags; /* old / cached if_flags */ |
---|
691 | }; |
---|
692 | |
---|
693 | /* bsdnet driver data */ |
---|
694 | struct tsec_softc { |
---|
695 | struct arpcom arpcom; |
---|
696 | struct tsec_bsdsupp bsd; |
---|
697 | struct tsec_private pvt; |
---|
698 | }; |
---|
699 | |
---|
700 | /* BSP glue information */ |
---|
701 | typedef struct tsec_bsp_config { |
---|
702 | uint32_t base; |
---|
703 | int xirq, rirq, eirq; |
---|
704 | uint32_t phy_base; |
---|
705 | int phy_addr; |
---|
706 | } TsecBspConfig; |
---|
707 | |
---|
708 | /********** Global Variables ********************/ |
---|
709 | |
---|
710 | /* You may override base addresses |
---|
711 | * externally - but you must |
---|
712 | * then also define TSEC_NUM_DRIVER_SLOTS. |
---|
713 | */ |
---|
714 | #ifndef TSEC_CONFIG |
---|
715 | |
---|
716 | static TsecBspConfig tsec_config[] = |
---|
717 | { |
---|
718 | { |
---|
719 | base: BSP_8540_CCSR_BASE + 0x24000, |
---|
720 | xirq: BSP_CORE_IRQ_LOWEST_OFFSET + 13, |
---|
721 | rirq: BSP_CORE_IRQ_LOWEST_OFFSET + 14, |
---|
722 | eirq: BSP_CORE_IRQ_LOWEST_OFFSET + 18, |
---|
723 | phy_base: BSP_8540_CCSR_BASE + 0x24000, |
---|
724 | phy_addr: 1, |
---|
725 | }, |
---|
726 | { |
---|
727 | base: BSP_8540_CCSR_BASE + 0x25000, |
---|
728 | xirq: BSP_CORE_IRQ_LOWEST_OFFSET + 19, |
---|
729 | rirq: BSP_CORE_IRQ_LOWEST_OFFSET + 20, |
---|
730 | eirq: BSP_CORE_IRQ_LOWEST_OFFSET + 23, |
---|
731 | /* all PHYs are on the 1st adapter's mii bus */ |
---|
732 | phy_base: BSP_8540_CCSR_BASE + 0x24000, |
---|
733 | phy_addr: 2, |
---|
734 | }, |
---|
735 | }; |
---|
736 | |
---|
737 | #define TSEC_CONFIG tsec_config |
---|
738 | |
---|
739 | #endif |
---|
740 | |
---|
741 | #ifndef TSEC_NUM_DRIVER_SLOTS |
---|
742 | #define TSEC_NUM_DRIVER_SLOTS (sizeof(TSEC_CONFIG)/sizeof(TSEC_CONFIG[0])) |
---|
743 | #endif |
---|
744 | |
---|
745 | /* Driver data structs */ |
---|
746 | STATIC struct tsec_softc theTsecEths[TSEC_NUM_DRIVER_SLOTS] = { {{{0}}} }; |
---|
747 | |
---|
748 | /* Bsdnet driver task ID; since the BSD stack is single-threaded |
---|
749 | * there is no point having multiple tasks. A single |
---|
750 | * task handling all adapters (attached to BSD stack) |
---|
751 | * is good enough. |
---|
752 | * Note that an adapter might well be used independently |
---|
753 | * from the BSD stack (use the low-level driver interface) |
---|
754 | * and be serviced by a separate task. |
---|
755 | */ |
---|
756 | STATIC rtems_id tsec_tid = 0; |
---|
757 | |
---|
758 | /* If we anticipate using adapters independently |
---|
759 | * from the BSD stack AND if all PHYs are on a single |
---|
760 | * adapter's MII bus THEN we must mutex-protect |
---|
761 | * that MII bus. |
---|
762 | * If not all of these conditions hold then you |
---|
763 | * may define TSEC_CONFIG_NO_PHY_REGLOCK and |
---|
764 | * avoid the creation and use of a mutex. |
---|
765 | */ |
---|
766 | #ifndef TSEC_CONFIG_NO_PHY_REGLOCK |
---|
767 | /* |
---|
768 | * PHY register access protection mutex; |
---|
769 | * multiple instances of tsec hardware |
---|
770 | * may share e.g., the first tsec's registers |
---|
771 | * for accessing the mii bus where all PHYs |
---|
772 | * may be connected. If we would only deal |
---|
773 | * with BSD networking then using the normal |
---|
774 | * networking semaphore would be OK. However, |
---|
775 | * we want to support standalone drivers and |
---|
776 | * therefore might require a separate lock. |
---|
777 | */ |
---|
778 | STATIC rtems_id tsec_mtx = 0; |
---|
779 | #define REGLOCK() do { \ |
---|
780 | if ( RTEMS_SUCCESSFUL != rtems_semaphore_obtain(tsec_mtx, RTEMS_WAIT, RTEMS_NO_TIMEOUT) ) \ |
---|
781 | rtems_panic(DRVNAME": unable to lock phy register protection mutex"); \ |
---|
782 | } while (0) |
---|
783 | #define REGUNLOCK() rtems_semaphore_release(tsec_mtx) |
---|
784 | #else |
---|
785 | #define REGLOCK() do { } while (0) |
---|
786 | #define REGUNLOCK() do { } while (0) |
---|
787 | #endif |
---|
788 | |
---|
789 | static void tsec_xisr(rtems_irq_hdl_param arg); |
---|
790 | static void tsec_risr(rtems_irq_hdl_param arg); |
---|
791 | static void tsec_eisr(rtems_irq_hdl_param arg); |
---|
792 | static void tsec_lisr(rtems_irq_hdl_param arg); |
---|
793 | |
---|
794 | static void noop(const rtems_irq_connect_data *unused) { } |
---|
795 | static int nopf(const rtems_irq_connect_data *unused) { return -1; } |
---|
796 | |
---|
797 | /********** Low-level Driver API ****************/ |
---|
798 | |
---|
799 | /* |
---|
800 | * This API provides driver access to applications that |
---|
801 | * want to use e.g., the second ethernet interface |
---|
802 | * independently from the BSD TCP/IP stack. E.g., for |
---|
803 | * raw ethernet packet communication... |
---|
804 | */ |
---|
805 | |
---|
806 | /* |
---|
807 | * Descriptor scavenger; cleanup the TX ring, passing all buffers |
---|
808 | * that have been sent to the cleanup_tx() callback. |
---|
809 | * This routine is called from BSP_tsec_send_buf(), BSP_tsec_init_hw(), |
---|
810 | * BSP_tsec_stop_hw(). |
---|
811 | * |
---|
812 | * RETURNS: number of buffers processed. |
---|
813 | */ |
---|
814 | |
---|
815 | int |
---|
816 | BSP_tsec_swipe_tx(struct tsec_private *mp) |
---|
817 | { |
---|
818 | int rval = 0; |
---|
819 | int i; |
---|
820 | TSEC_BD *bd; |
---|
821 | uint16_t flags; |
---|
822 | void *u; |
---|
823 | |
---|
824 | #if DEBUG > 2 |
---|
825 | printf("Swipe TX entering:\n"); |
---|
826 | tsec_dump_tring(mp); |
---|
827 | #endif |
---|
828 | |
---|
829 | for ( i = mp->tx_head; bd_rdbuf( (bd = &mp->tx_ring[i]) ); i = NEXT_TXI(mp, i) ) { |
---|
830 | |
---|
831 | flags = bd_rdfl( bd ); |
---|
832 | if ( (TSEC_TXBD_R & flags) ) { |
---|
833 | /* nothing more to clean */ |
---|
834 | break; |
---|
835 | } |
---|
836 | |
---|
837 | /* tx_ring_user[i] is only set on the last descriptor in a chain; |
---|
838 | * we only count errors in the last descriptor; |
---|
839 | */ |
---|
840 | if ( (u=mp->tx_ring_user[i]) ) { |
---|
841 | mp->cleanup_txbuf(u, mp->cleanup_txbuf_arg, (flags & TSEC_TXBD_ERRS)); |
---|
842 | mp->tx_ring_user[i] = 0; |
---|
843 | } |
---|
844 | |
---|
845 | bd_wrbuf( bd, 0 ); |
---|
846 | |
---|
847 | mp->tx_avail++; |
---|
848 | |
---|
849 | rval++; |
---|
850 | } |
---|
851 | mp->tx_head = i; |
---|
852 | |
---|
853 | #if DEBUG > 2 |
---|
854 | tsec_dump_tring(mp); |
---|
855 | printf("Swipe TX leaving\n"); |
---|
856 | #endif |
---|
857 | |
---|
858 | return rval; |
---|
859 | } |
---|
860 | |
---|
861 | |
---|
862 | /* |
---|
863 | * Reset the controller and bring into a known state; |
---|
864 | * all interrupts are off |
---|
865 | */ |
---|
866 | STATIC void |
---|
867 | tsec_reset_hw(struct tsec_private *mp) |
---|
868 | { |
---|
869 | FEC_Enet_Base b = mp->base; |
---|
870 | |
---|
871 | /* Make sure all interrupts are off */ |
---|
872 | fec_wr(b, TSEC_IMASK, TSEC_IMASK_NONE); |
---|
873 | |
---|
874 | #ifndef TSEC_CONFIG_NO_PHY_REGLOCK |
---|
875 | /* don't bother disabling irqs in the PHY if this is |
---|
876 | * called before the mutex is created; |
---|
877 | * the PHY ISR is not hooked yet and there can be no |
---|
878 | * interrupts... |
---|
879 | */ |
---|
880 | if ( tsec_mtx ) |
---|
881 | #endif |
---|
882 | phy_dis_irq_at_phy( mp ); |
---|
883 | |
---|
884 | /* Follow the manual resetting the chip */ |
---|
885 | |
---|
886 | /* Do graceful stop (if not in stop condition already) */ |
---|
887 | if ( ! (TSEC_DMACTRL_GTS & fec_rd(b, TSEC_DMACTRL)) ) { |
---|
888 | /* Make sure GTSC is clear */ |
---|
889 | fec_wr(b, TSEC_IEVENT, TSEC_IEVENT_GTSC); |
---|
890 | fec_set(b, TSEC_DMACTRL, TSEC_DMACTRL_GTS); |
---|
891 | while ( ! (TSEC_IEVENT_GTSC & fec_rd(b, TSEC_IEVENT)) ) |
---|
892 | /* wait */; |
---|
893 | } |
---|
894 | |
---|
895 | /* Clear RX/TX enable in MAC */ |
---|
896 | fec_clr(b, TSEC_MACCFG1, TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN); |
---|
897 | |
---|
898 | /* wait for > 8ms */ |
---|
899 | rtems_task_wake_after(1); |
---|
900 | |
---|
901 | /* set GRS if not already stopped */ |
---|
902 | if ( ! (TSEC_DMACTRL_GRS & fec_rd(b, TSEC_DMACTRL)) ) { |
---|
903 | /* Make sure GRSC is clear */ |
---|
904 | fec_wr(b, TSEC_IEVENT, TSEC_IEVENT_GRSC); |
---|
905 | fec_set(b, TSEC_DMACTRL, TSEC_DMACTRL_GRS); |
---|
906 | while ( ! (TSEC_IEVENT_GRSC & fec_rd(b, TSEC_IEVENT)) ) |
---|
907 | /* wait */; |
---|
908 | } |
---|
909 | |
---|
910 | fec_set(b, TSEC_MACCFG1, TSEC_MACCFG1_SOFT_RESET); |
---|
911 | fec_clr(b, TSEC_MACCFG1, TSEC_MACCFG1_SOFT_RESET); |
---|
912 | |
---|
913 | /* clear all irqs */ |
---|
914 | fec_wr (b, TSEC_IEVENT, TSEC_IEVENT_ALL); |
---|
915 | } |
---|
916 | |
---|
917 | /* Helper to hook/unhook interrupts */ |
---|
918 | |
---|
919 | static void |
---|
920 | install_remove_isrs(int install, struct tsec_private *mp, uint32_t irq_mask) |
---|
921 | { |
---|
922 | rtems_irq_connect_data xxx; |
---|
923 | int installed = 0; |
---|
924 | int line; |
---|
925 | int unit = mp->unit; |
---|
926 | |
---|
927 | xxx.on = noop; |
---|
928 | xxx.off = noop; |
---|
929 | xxx.isOn = nopf; |
---|
930 | xxx.handle = mp; |
---|
931 | |
---|
932 | if ( irq_mask & TSEC_TXIRQ ) { |
---|
933 | xxx.name = TSEC_CONFIG[unit-1].xirq; |
---|
934 | xxx.hdl = tsec_xisr; |
---|
935 | if ( ! (install ? |
---|
936 | BSP_install_rtems_irq_handler( &xxx ) : |
---|
937 | BSP_remove_rtems_irq_handler( &xxx ) ) ) { |
---|
938 | rtems_panic(DRVNAME": Unable to install TX ISR\n"); |
---|
939 | } |
---|
940 | installed++; |
---|
941 | } |
---|
942 | |
---|
943 | if ( (irq_mask & TSEC_RXIRQ) ) { |
---|
944 | if ( (line = TSEC_CONFIG[unit-1].rirq) < 0 && ! installed ) { |
---|
945 | /* have no dedicated RX IRQ line; install TX ISR if not already done */ |
---|
946 | line = TSEC_CONFIG[unit-1].xirq; |
---|
947 | } |
---|
948 | xxx.name = line; |
---|
949 | xxx.hdl = tsec_risr; |
---|
950 | if ( ! (install ? |
---|
951 | BSP_install_rtems_irq_handler( &xxx ) : |
---|
952 | BSP_remove_rtems_irq_handler( &xxx ) ) ) { |
---|
953 | rtems_panic(DRVNAME": Unable to install RX ISR\n"); |
---|
954 | } |
---|
955 | installed++; |
---|
956 | } |
---|
957 | |
---|
958 | if ( (line = TSEC_CONFIG[unit-1].eirq) < 0 && ! installed ) { |
---|
959 | /* have no dedicated RX IRQ line; install TX ISR if not already done */ |
---|
960 | line = TSEC_CONFIG[unit-1].xirq; |
---|
961 | } |
---|
962 | xxx.name = line; |
---|
963 | xxx.hdl = tsec_eisr; |
---|
964 | if ( ! (install ? |
---|
965 | BSP_install_rtems_irq_handler( &xxx ) : |
---|
966 | BSP_remove_rtems_irq_handler( &xxx ) ) ) { |
---|
967 | rtems_panic(DRVNAME": Unable to install ERR ISR\n"); |
---|
968 | } |
---|
969 | |
---|
970 | if ( irq_mask & TSEC_LINK_INTR ) { |
---|
971 | phy_init_irq( install, mp, tsec_lisr ); |
---|
972 | } |
---|
973 | } |
---|
974 | |
---|
975 | /* |
---|
976 | * Setup an interface. |
---|
977 | * Allocates resources for descriptor rings and sets up the driver software structure. |
---|
978 | * |
---|
979 | * Arguments: |
---|
980 | * unit: |
---|
981 | * interface # (1..2). The interface must not be attached to BSD already. |
---|
982 | * |
---|
983 | * driver_tid: |
---|
984 | * ISR posts RTEMS event # ('unit' - 1) to task with ID 'driver_tid' and disables interrupts |
---|
985 | * from this interface. |
---|
986 | * |
---|
987 | * void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred): |
---|
988 | * Pointer to user-supplied callback to release a buffer that had been sent |
---|
989 | * by BSP_tsec_send_buf() earlier. The callback is passed 'cleanup_txbuf_arg' |
---|
990 | * and a flag indicating whether the send had been successful. |
---|
991 | * The driver no longer accesses 'user_buf' after invoking this callback. |
---|
992 | * CONTEXT: This callback is executed either by BSP_tsec_swipe_tx() or |
---|
993 | * BSP_tsec_send_buf(), BSP_tsec_init_hw(), BSP_tsec_stop_hw() (the latter |
---|
994 | * ones calling BSP_tsec_swipe_tx()). |
---|
995 | * void *cleanup_txbuf_arg: |
---|
996 | * Closure argument that is passed on to 'cleanup_txbuf()' callback; |
---|
997 | * |
---|
998 | * void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr), |
---|
999 | * Pointer to user-supplied callback to allocate a buffer for subsequent |
---|
1000 | * insertion into the RX ring by the driver. |
---|
1001 | * RETURNS: opaque handle to the buffer (which may be a more complex object |
---|
1002 | * such as an 'mbuf'). The handle is not used by the driver directly |
---|
1003 | * but passed back to the 'consume_rxbuf()' callback. |
---|
1004 | * Size of the available data area and pointer to buffer's data area |
---|
1005 | * in '*psize' and '*p_data_area', respectively. |
---|
1006 | * If no buffer is available, this routine should return NULL in which |
---|
1007 | * case the driver drops the last packet and re-uses the last buffer |
---|
1008 | * instead of handing it out to 'consume_rxbuf()'. |
---|
1009 | * CONTEXT: Called when initializing the RX ring (BSP_tsec_init_hw()) or when |
---|
1010 | * swiping it (BSP_tsec_swipe_rx()). |
---|
1011 | * |
---|
1012 | * |
---|
1013 | * void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len); |
---|
1014 | * Pointer to user-supplied callback to pass a received buffer back to |
---|
1015 | * the user. The driver no longer accesses the buffer after invoking this |
---|
1016 | * callback (with 'len'>0, see below). 'user_buf' is the buffer handle |
---|
1017 | * previously generated by 'alloc_rxbuf()'. |
---|
1018 | * The callback is passed 'cleanup_rxbuf_arg' and a 'len' |
---|
1019 | * argument giving the number of bytes that were received. |
---|
1020 | * 'len' may be <=0 in which case the 'user_buf' argument is NULL. |
---|
1021 | * 'len' == 0 means that the last 'alloc_rxbuf()' had failed, |
---|
1022 | * 'len' < 0 indicates a receiver error. In both cases, the last packet |
---|
1023 | * was dropped/missed and the last buffer will be re-used by the driver. |
---|
1024 | * NOTE: the data are 'prefixed' with two bytes, i.e., the ethernet packet header |
---|
1025 | * is stored at offset 2 in the buffer's data area. Also, the FCS (4 bytes) |
---|
1026 | * is appended. 'len' accounts for both. |
---|
1027 | * CONTEXT: Called from BSP_tsec_swipe_rx(). |
---|
1028 | * void *cleanup_rxbuf_arg: |
---|
1029 | * Closure argument that is passed on to 'consume_rxbuf()' callback; |
---|
1030 | * |
---|
1031 | * rx_ring_size, tx_ring_size: |
---|
1032 | * How many big to make the RX and TX descriptor rings. Note that the sizes |
---|
1033 | * may be 0 in which case a reasonable default will be used. |
---|
1034 | * If either ring size is < 0 then the RX or TX will be disabled. |
---|
1035 | * Note that it is illegal in this case to use BSP_tsec_swipe_rx() or |
---|
1036 | * BSP_tsec_swipe_tx(), respectively. |
---|
1037 | * |
---|
1038 | * irq_mask: |
---|
1039 | * Interrupts to enable. OR of flags from above. |
---|
1040 | * |
---|
1041 | */ |
---|
1042 | struct tsec_private * |
---|
1043 | BSP_tsec_setup( |
---|
1044 | int unit, |
---|
1045 | rtems_id driver_tid, |
---|
1046 | void (*cleanup_txbuf)(void *user_buf, void *cleanup_txbuf_arg, int error_on_tx_occurred), |
---|
1047 | void *cleanup_txbuf_arg, |
---|
1048 | void *(*alloc_rxbuf)(int *p_size, uintptr_t *p_data_addr), |
---|
1049 | void (*consume_rxbuf)(void *user_buf, void *consume_rxbuf_arg, int len), |
---|
1050 | void *consume_rxbuf_arg, |
---|
1051 | int rx_ring_size, |
---|
1052 | int tx_ring_size, |
---|
1053 | int irq_mask |
---|
1054 | ) |
---|
1055 | { |
---|
1056 | struct tsec_private *mp; |
---|
1057 | int i; |
---|
1058 | struct ifnet *ifp; |
---|
1059 | |
---|
1060 | if ( unit <= 0 || unit > TSEC_NUM_DRIVER_SLOTS ) { |
---|
1061 | printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, TSEC_NUM_DRIVER_SLOTS); |
---|
1062 | return 0; |
---|
1063 | } |
---|
1064 | |
---|
1065 | ifp = &theTsecEths[unit-1].arpcom.ac_if; |
---|
1066 | if ( ifp->if_init ) { |
---|
1067 | if ( ifp->if_init ) { |
---|
1068 | printk(DRVNAME": instance %i already attached.\n", unit); |
---|
1069 | return 0; |
---|
1070 | } |
---|
1071 | } |
---|
1072 | |
---|
1073 | |
---|
1074 | if ( rx_ring_size < 0 && tx_ring_size < 0 ) |
---|
1075 | return 0; |
---|
1076 | |
---|
1077 | mp = &theTsecEths[unit - 1].pvt; |
---|
1078 | |
---|
1079 | memset(mp, 0, sizeof(*mp)); |
---|
1080 | |
---|
1081 | mp->sc = &theTsecEths[unit - 1]; |
---|
1082 | mp->unit = unit; |
---|
1083 | |
---|
1084 | mp->base = (FEC_Enet_Base)TSEC_CONFIG[unit-1].base; |
---|
1085 | mp->phy_base = (FEC_Enet_Base)TSEC_CONFIG[unit-1].phy_base; |
---|
1086 | mp->phy = TSEC_CONFIG[unit-1].phy_addr; |
---|
1087 | mp->tid = driver_tid; |
---|
1088 | /* use odd event flags for link status IRQ */ |
---|
1089 | mp->event = TSEC_ETH_EVENT((unit-1)); |
---|
1090 | |
---|
1091 | mp->cleanup_txbuf = cleanup_txbuf; |
---|
1092 | mp->cleanup_txbuf_arg = cleanup_txbuf_arg; |
---|
1093 | mp->alloc_rxbuf = alloc_rxbuf; |
---|
1094 | mp->consume_rxbuf = consume_rxbuf; |
---|
1095 | mp->consume_rxbuf_arg = consume_rxbuf_arg; |
---|
1096 | |
---|
1097 | /* stop hw prior to setting ring-size to anything nonzero |
---|
1098 | * so that the rings are not swept. |
---|
1099 | */ |
---|
1100 | BSP_tsec_stop_hw(mp); |
---|
1101 | |
---|
1102 | if ( 0 == rx_ring_size ) |
---|
1103 | rx_ring_size = TSEC_RX_RING_SIZE; |
---|
1104 | if ( 0 == tx_ring_size ) |
---|
1105 | tx_ring_size = TSEC_TX_RING_SIZE; |
---|
1106 | |
---|
1107 | mp->rx_ring_size = rx_ring_size < 0 ? 0 : rx_ring_size; |
---|
1108 | mp->tx_ring_size = tx_ring_size < 0 ? 0 : tx_ring_size; |
---|
1109 | |
---|
1110 | /* allocate ring area; add 1 entry -- room for alignment */ |
---|
1111 | assert( !mp->ring_area ); |
---|
1112 | mp->ring_area = malloc( |
---|
1113 | sizeof(*mp->ring_area) * |
---|
1114 | (mp->rx_ring_size + mp->tx_ring_size + 1), |
---|
1115 | M_DEVBUF, |
---|
1116 | M_WAIT ); |
---|
1117 | assert( mp->ring_area ); |
---|
1118 | |
---|
1119 | mp->tx_ring_user = malloc( sizeof(*mp->tx_ring_user) * |
---|
1120 | (mp->rx_ring_size + mp->tx_ring_size), |
---|
1121 | M_DEVBUF, |
---|
1122 | M_WAIT ); |
---|
1123 | assert( mp->tx_ring_user ); |
---|
1124 | |
---|
1125 | mp->rx_ring_user = mp->tx_ring_user + mp->tx_ring_size; |
---|
1126 | |
---|
1127 | /* Initialize TX ring */ |
---|
1128 | mp->tx_ring = (TSEC_BD *) ALIGNTO(mp->ring_area,BD_ALIGNMENT); |
---|
1129 | |
---|
1130 | mp->rx_ring = mp->tx_ring + mp->tx_ring_size; |
---|
1131 | |
---|
1132 | for ( i=0; i<mp->tx_ring_size; i++ ) { |
---|
1133 | bd_wrbuf( &mp->tx_ring[i], 0 ); |
---|
1134 | bd_wrfl( &mp->tx_ring[i], TSEC_TXBD_I ); |
---|
1135 | mp->tx_ring_user[i] = 0; |
---|
1136 | } |
---|
1137 | /* set wrap-around flag on last BD */ |
---|
1138 | if ( mp->tx_ring_size ) |
---|
1139 | bd_setfl( &mp->tx_ring[i-1], TSEC_TXBD_W ); |
---|
1140 | |
---|
1141 | mp->tx_tail = mp->tx_head = 0; |
---|
1142 | mp->tx_avail = mp->tx_ring_size; |
---|
1143 | |
---|
1144 | /* Initialize RX ring (buffers are allocated later) */ |
---|
1145 | for ( i=0; i<mp->rx_ring_size; i++ ) { |
---|
1146 | bd_wrbuf( &mp->rx_ring[i], 0 ); |
---|
1147 | bd_wrfl( &mp->rx_ring[i], TSEC_RXBD_I ); |
---|
1148 | mp->rx_ring_user[i] = 0; |
---|
1149 | } |
---|
1150 | /* set wrap-around flag on last BD */ |
---|
1151 | if ( mp->rx_ring_size ) |
---|
1152 | bd_setfl( &mp->rx_ring[i-1], TSEC_RXBD_W ); |
---|
1153 | |
---|
1154 | if ( irq_mask ) { |
---|
1155 | if ( rx_ring_size == 0 ) |
---|
1156 | irq_mask &= ~ TSEC_RXIRQ; |
---|
1157 | if ( tx_ring_size == 0 ) |
---|
1158 | irq_mask &= ~ TSEC_TXIRQ; |
---|
1159 | } |
---|
1160 | |
---|
1161 | #ifndef TSEC_CONFIG_NO_PHY_REGLOCK |
---|
1162 | /* lazy init of mutex (non thread-safe! - we assume initialization |
---|
1163 | * of 1st IF is single-threaded) |
---|
1164 | */ |
---|
1165 | if ( ! tsec_mtx ) { |
---|
1166 | rtems_status_code sc; |
---|
1167 | sc = rtems_semaphore_create( |
---|
1168 | rtems_build_name('t','s','e','X'), |
---|
1169 | 1, |
---|
1170 | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_DEFAULT_ATTRIBUTES, |
---|
1171 | 0, |
---|
1172 | &tsec_mtx); |
---|
1173 | if ( RTEMS_SUCCESSFUL != sc ) { |
---|
1174 | rtems_error(sc,DRVNAME": creating mutex\n"); |
---|
1175 | rtems_panic("unable to proceed\n"); |
---|
1176 | } |
---|
1177 | } |
---|
1178 | #endif |
---|
1179 | |
---|
1180 | if ( irq_mask ) { |
---|
1181 | install_remove_isrs( 1, mp, irq_mask ); |
---|
1182 | } |
---|
1183 | |
---|
1184 | mp->irq_mask = irq_mask; |
---|
1185 | |
---|
1186 | /* mark as used */ |
---|
1187 | ifp->if_init = (void*)(-1); |
---|
1188 | |
---|
1189 | return mp; |
---|
1190 | } |
---|
1191 | |
---|
1192 | void |
---|
1193 | BSP_tsec_reset_stats(struct tsec_private *mp) |
---|
1194 | { |
---|
1195 | FEC_Enet_Base b = mp->base; |
---|
1196 | int i; |
---|
1197 | memset( &mp->stats, 0, sizeof( mp->stats ) ); |
---|
1198 | if ( mp->isfec ) |
---|
1199 | return; |
---|
1200 | for ( i=TSEC_TR64; i<=TSEC_TFRG; i+=4 ) |
---|
1201 | fec_wr( b, i, 0 ); |
---|
1202 | |
---|
1203 | } |
---|
1204 | |
---|
1205 | /* |
---|
1206 | * retrieve media status from the PHY |
---|
1207 | * and set duplex mode in MACCFG2 based |
---|
1208 | * on the result. |
---|
1209 | * |
---|
1210 | * RETURNS: media word (or -1 if BSP_tsec_media_ioctl() fails) |
---|
1211 | */ |
---|
1212 | static int |
---|
1213 | mac_set_duplex(struct tsec_private *mp) |
---|
1214 | { |
---|
1215 | int media = 0; |
---|
1216 | |
---|
1217 | if ( 0 == BSP_tsec_media_ioctl(mp, SIOCGIFMEDIA, &media)) { |
---|
1218 | if ( IFM_LINK_OK & media ) { |
---|
1219 | /* update duplex setting in MACCFG2 */ |
---|
1220 | if ( IFM_FDX & media ) { |
---|
1221 | fec_set( mp->base, TSEC_MACCFG2, TSEC_MACCFG2_FD ); |
---|
1222 | } else { |
---|
1223 | fec_clr( mp->base, TSEC_MACCFG2, TSEC_MACCFG2_FD ); |
---|
1224 | } |
---|
1225 | } |
---|
1226 | return media; |
---|
1227 | } |
---|
1228 | return -1; |
---|
1229 | } |
---|
1230 | |
---|
1231 | /* |
---|
1232 | * Initialize interface hardware |
---|
1233 | * |
---|
1234 | * 'mp' handle obtained by from BSP_tsec_setup(). |
---|
1235 | * 'promisc' whether to set promiscuous flag. |
---|
1236 | * 'enaddr' pointer to six bytes with MAC address. Read |
---|
1237 | * from the device if NULL. |
---|
1238 | */ |
---|
1239 | void |
---|
1240 | BSP_tsec_init_hw(struct tsec_private *mp, int promisc, unsigned char *enaddr) |
---|
1241 | { |
---|
1242 | FEC_Enet_Base b = mp->base; |
---|
1243 | unsigned i; |
---|
1244 | uint32_t v; |
---|
1245 | int sz; |
---|
1246 | rtems_interrupt_level l; |
---|
1247 | |
---|
1248 | BSP_tsec_stop_hw(mp); |
---|
1249 | |
---|
1250 | #ifdef PARANOIA |
---|
1251 | assert( mp->tx_avail == mp->tx_ring_size ); |
---|
1252 | assert( mp->tx_head == mp->tx_tail ); |
---|
1253 | for ( i=0; i<mp->tx_ring_size; i++ ) { |
---|
1254 | assert( mp->tx_ring_user[i] == 0 ); |
---|
1255 | } |
---|
1256 | #endif |
---|
1257 | |
---|
1258 | /* make sure RX ring is filled */ |
---|
1259 | for ( i=0; i<mp->rx_ring_size; i++ ) { |
---|
1260 | uintptr_t data_area; |
---|
1261 | if ( ! (mp->rx_ring_user[i] = mp->alloc_rxbuf( &sz, &data_area)) ) { |
---|
1262 | rtems_panic(DRVNAME": unable to fill RX ring"); |
---|
1263 | } |
---|
1264 | if ( data_area & (RX_BUF_ALIGNMENT-1) ) |
---|
1265 | rtems_panic(DRVNAME": RX buffers must be %i-byte aligned", RX_BUF_ALIGNMENT); |
---|
1266 | |
---|
1267 | bd_wrbuf( &mp->rx_ring[i], data_area ); |
---|
1268 | st_be16 ( &mp->rx_ring[i].len, sz ); |
---|
1269 | bd_setfl( &mp->rx_ring[i], TSEC_RXBD_E | TSEC_RXBD_I ); |
---|
1270 | } |
---|
1271 | |
---|
1272 | mp->tx_tail = mp->tx_head = 0; |
---|
1273 | |
---|
1274 | mp->rx_tail = 0; |
---|
1275 | |
---|
1276 | /* tell chip what the ring areas are */ |
---|
1277 | fec_wr( b, TSEC_TBASE, (uint32_t)mp->tx_ring ); |
---|
1278 | fec_wr( b, TSEC_RBASE, (uint32_t)mp->rx_ring ); |
---|
1279 | |
---|
1280 | /* clear and disable IRQs */ |
---|
1281 | fec_wr( b, TSEC_IEVENT, TSEC_IEVENT_ALL ); |
---|
1282 | fec_wr( b, TSEC_IMASK, TSEC_IMASK_NONE ); |
---|
1283 | |
---|
1284 | /* bring other regs. into a known state */ |
---|
1285 | fec_wr( b, TSEC_EDIS, 0 ); |
---|
1286 | |
---|
1287 | if ( !mp->isfec ) |
---|
1288 | fec_wr( b, TSEC_ECNTRL, TSEC_ECNTRL_CLRCNT | TSEC_ECNTRL_STEN ); |
---|
1289 | |
---|
1290 | fec_wr( b, TSEC_MINFLR, 64 ); |
---|
1291 | fec_wr( b, TSEC_PTV, 0 ); |
---|
1292 | |
---|
1293 | v = TSEC_DMACTRL_WWR; |
---|
1294 | |
---|
1295 | if ( mp->tx_ring_size ) |
---|
1296 | v |= TSEC_DMACTRL_TDSEN | TSEC_DMACTRL_TBDSEN | TSEC_DMACTRL_WOP; |
---|
1297 | |
---|
1298 | fec_wr( b, TSEC_DMACTRL, v ); |
---|
1299 | |
---|
1300 | fec_wr( b, TSEC_FIFO_PAUSE_CTRL, 0 ); |
---|
1301 | fec_wr( b, TSEC_FIFO_TX_THR, 256 ); |
---|
1302 | fec_wr( b, TSEC_FIFO_TX_STARVE, 128 ); |
---|
1303 | fec_wr( b, TSEC_FIFO_TX_STARVE_SHUTOFF, 256 ); |
---|
1304 | fec_wr( b, TSEC_TCTRL, 0 ); |
---|
1305 | if ( !mp->isfec ) { |
---|
1306 | /* FIXME: use IRQ coalescing ? not sure how to |
---|
1307 | * set the timer (bad if it depends on the speed |
---|
1308 | * setting). |
---|
1309 | */ |
---|
1310 | fec_wr( b, TSEC_TXIC, 0); |
---|
1311 | } |
---|
1312 | fec_wr( b, TSEC_OSTBD, 0 ); |
---|
1313 | fec_wr( b, TSEC_RCTRL, (promisc ? TSEC_RCTRL_PROM : 0) ); |
---|
1314 | fec_wr( b, TSEC_RSTAT, TSEC_RSTAT_QHLT ); |
---|
1315 | if ( !mp->isfec ) { |
---|
1316 | /* FIXME: use IRQ coalescing ? not sure how to |
---|
1317 | * set the timer (bad if it depends on the speed |
---|
1318 | * setting). |
---|
1319 | */ |
---|
1320 | fec_wr( b, TSEC_RXIC, 0 ); |
---|
1321 | } |
---|
1322 | fec_wr( b, TSEC_MRBLR, sz & ~63 ); |
---|
1323 | |
---|
1324 | /* Reset config. as per manual */ |
---|
1325 | fec_wr( b, TSEC_IPGIFG, 0x40605060 ); |
---|
1326 | fec_wr( b, TSEC_HAFDUP, 0x00a1f037 ); |
---|
1327 | fec_wr( b, TSEC_MAXFRM, 1536 ); |
---|
1328 | |
---|
1329 | if ( enaddr ) { |
---|
1330 | union { |
---|
1331 | uint32_t u; |
---|
1332 | uint16_t s[2]; |
---|
1333 | uint8_t c[4]; |
---|
1334 | } x; |
---|
1335 | fec_wr( b, TSEC_MACSTNADDR1, ld_le32( (volatile uint32_t*)(enaddr + 2) ) ); |
---|
1336 | x.s[0] = ld_le16( (volatile uint16_t *)(enaddr) ); |
---|
1337 | fec_wr( b, TSEC_MACSTNADDR2, x.u ); |
---|
1338 | } |
---|
1339 | |
---|
1340 | for ( i=0; i<8*4; i+=4 ) { |
---|
1341 | fec_wr( b, TSEC_IADDR0 + i, 0 ); |
---|
1342 | fec_wr( b, TSEC_GADDR0 + i, 0 ); |
---|
1343 | } |
---|
1344 | |
---|
1345 | BSP_tsec_reset_stats(mp); |
---|
1346 | |
---|
1347 | fec_wr( b, TSEC_ATTR, (TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN) ); |
---|
1348 | fec_wr( b, TSEC_ATTRELI, 0 ); |
---|
1349 | |
---|
1350 | /* The interface type is probably board dependent; leave alone... |
---|
1351 | v = mp->isfec ? TSEC_MACCFG2_IF_MODE_MII : TSEC_MACCFG2_IF_MODE_GMII; |
---|
1352 | */ |
---|
1353 | |
---|
1354 | fec_clr( b, TSEC_MACCFG2, |
---|
1355 | TSEC_MACCFG2_PREAMBLE_15 |
---|
1356 | | TSEC_MACCFG2_HUGE_FRAME |
---|
1357 | | TSEC_MACCFG2_LENGTH_CHECK ); |
---|
1358 | |
---|
1359 | fec_set( b, TSEC_MACCFG2, |
---|
1360 | TSEC_MACCFG2_PREAMBLE_7 |
---|
1361 | | TSEC_MACCFG2_PAD_CRC ); |
---|
1362 | |
---|
1363 | mac_set_duplex( mp ); |
---|
1364 | |
---|
1365 | v = 0; |
---|
1366 | if ( mp->rx_ring_size ) { |
---|
1367 | v |= TSEC_MACCFG1_RX_EN; |
---|
1368 | } |
---|
1369 | if ( mp->tx_ring_size ) { |
---|
1370 | v |= TSEC_MACCFG1_TX_EN; |
---|
1371 | } |
---|
1372 | |
---|
1373 | fec_wr( b, TSEC_MACCFG1, v); |
---|
1374 | |
---|
1375 | /* The following sequency (FWIW) ensures that |
---|
1376 | * |
---|
1377 | * - PHY and TSEC interrupts are enabled atomically |
---|
1378 | * - IRQS are not globally off while accessing the PHY |
---|
1379 | * (slow MII) |
---|
1380 | */ |
---|
1381 | |
---|
1382 | /* disable PHY irq at PIC (fast) */ |
---|
1383 | phy_dis_irq( mp ); |
---|
1384 | /* enable PHY irq (MII operation, slow) */ |
---|
1385 | phy_en_irq_at_phy (mp ); |
---|
1386 | |
---|
1387 | /* globally disable */ |
---|
1388 | rtems_interrupt_disable( l ); |
---|
1389 | |
---|
1390 | /* enable TSEC IRQs */ |
---|
1391 | fec_wr( mp->base, TSEC_IMASK, mp->irq_mask ); |
---|
1392 | /* enable PHY irq at PIC */ |
---|
1393 | phy_en_irq( mp ); |
---|
1394 | |
---|
1395 | /* globally reenable */ |
---|
1396 | rtems_interrupt_enable( l ); |
---|
1397 | } |
---|
1398 | |
---|
1399 | void |
---|
1400 | BSP_tsec_dump_stats(struct tsec_private *mp, FILE *f) |
---|
1401 | { |
---|
1402 | FEC_Enet_Base b; |
---|
1403 | |
---|
1404 | if ( !mp ) |
---|
1405 | mp = &theTsecEths[0].pvt; |
---|
1406 | |
---|
1407 | if ( ! f ) |
---|
1408 | f = stdout; |
---|
1409 | |
---|
1410 | fprintf(f, DRVNAME"%i Statistics:\n", mp->unit); |
---|
1411 | |
---|
1412 | b = mp->base; |
---|
1413 | |
---|
1414 | fprintf(f, "TX IRQS: %u\n", mp->stats.xirqs); |
---|
1415 | fprintf(f, "RX IRQS: %u\n", mp->stats.rirqs); |
---|
1416 | fprintf(f, "ERR IRQS: %u\n", mp->stats.eirqs); |
---|
1417 | fprintf(f, "LNK IRQS: %u\n", mp->stats.lirqs); |
---|
1418 | fprintf(f, "maxchain: %u\n", mp->stats.maxchain); |
---|
1419 | fprintf(f, "xpackets: %u\n", mp->stats.packet); |
---|
1420 | fprintf(f, "odrops: %u\n", mp->stats.odrops); |
---|
1421 | fprintf(f, "repack: %u\n", mp->stats.repack); |
---|
1422 | |
---|
1423 | if ( mp->isfec ) { |
---|
1424 | fprintf(f,"FEC has no HW counters\n"); |
---|
1425 | return; |
---|
1426 | } |
---|
1427 | |
---|
1428 | fprintf(f,"TSEC MIB counters (modulo 2^32):\n"); |
---|
1429 | |
---|
1430 | fprintf(f,"RX bytes %"PRIu32"\n", fec_rd( b, TSEC_RBYT )); |
---|
1431 | fprintf(f,"RX pkts %"PRIu32"\n", fec_rd( b, TSEC_RPKT )); |
---|
1432 | fprintf(f,"RX FCS errs %"PRIu32"\n", fec_rd( b, TSEC_RFCS )); |
---|
1433 | fprintf(f,"RX mcst pkts %"PRIu32"\n", fec_rd( b, TSEC_RMCA )); |
---|
1434 | fprintf(f,"RX bcst pkts %"PRIu32"\n", fec_rd( b, TSEC_RBCA )); |
---|
1435 | fprintf(f,"RX pse frms %"PRIu32"\n", fec_rd( b, TSEC_RXPF )); |
---|
1436 | fprintf(f,"RX drop %"PRIu32"\n", fec_rd( b, TSEC_RDRP )); |
---|
1437 | fprintf(f,"TX bytes %"PRIu32"\n", fec_rd( b, TSEC_TBYT )); |
---|
1438 | fprintf(f,"TX pkts %"PRIu32"\n", fec_rd( b, TSEC_TPKT )); |
---|
1439 | fprintf(f,"TX FCS errs %"PRIu32"\n", fec_rd( b, TSEC_TFCS )); |
---|
1440 | fprintf(f,"TX mcst pkts %"PRIu32"\n", fec_rd( b, TSEC_TMCA )); |
---|
1441 | fprintf(f,"TX bcst pkts %"PRIu32"\n", fec_rd( b, TSEC_TBCA )); |
---|
1442 | fprintf(f,"TX pse frms %"PRIu32"\n", fec_rd( b, TSEC_TXPF )); |
---|
1443 | fprintf(f,"TX drop %"PRIu32"\n", fec_rd( b, TSEC_TDRP )); |
---|
1444 | fprintf(f,"TX coll %"PRIu32"\n", fec_rd( b, TSEC_TSCL )); |
---|
1445 | fprintf(f,"TX mcoll %"PRIu32"\n", fec_rd( b, TSEC_TMCL )); |
---|
1446 | fprintf(f,"TX late coll %"PRIu32"\n", fec_rd( b, TSEC_TLCL )); |
---|
1447 | fprintf(f,"TX exc coll %"PRIu32"\n", fec_rd( b, TSEC_TXCL )); |
---|
1448 | fprintf(f,"TX defer %"PRIu32"\n", fec_rd( b, TSEC_TDFR )); |
---|
1449 | fprintf(f,"TX exc defer %"PRIu32"\n", fec_rd( b, TSEC_TEDF )); |
---|
1450 | fprintf(f,"TX oversz %"PRIu32"\n", fec_rd( b, TSEC_TOVR )); |
---|
1451 | fprintf(f,"TX undersz %"PRIu32"\n", fec_rd( b, TSEC_TUND )); |
---|
1452 | } |
---|
1453 | |
---|
1454 | /* |
---|
1455 | * Shutdown hardware and clean out the rings |
---|
1456 | */ |
---|
1457 | void |
---|
1458 | BSP_tsec_stop_hw(struct tsec_private *mp) |
---|
1459 | { |
---|
1460 | unsigned i; |
---|
1461 | /* stop and reset hardware */ |
---|
1462 | tsec_reset_hw( mp ); |
---|
1463 | |
---|
1464 | if ( mp->tx_ring_size ) { |
---|
1465 | /* should be OK to clear all ownership flags */ |
---|
1466 | for ( i=0; i<mp->tx_ring_size; i++ ) { |
---|
1467 | bd_clrfl( &mp->tx_ring[i], TSEC_TXBD_R ); |
---|
1468 | } |
---|
1469 | BSP_tsec_swipe_tx(mp); |
---|
1470 | #if DEBUG > 0 |
---|
1471 | tsec_dump_tring(mp); |
---|
1472 | fflush(stderr); fflush(stdout); |
---|
1473 | #endif |
---|
1474 | #ifdef PARANOIA |
---|
1475 | assert( mp->tx_avail == mp->tx_ring_size ); |
---|
1476 | assert( mp->tx_head == mp->tx_tail ); |
---|
1477 | for ( i=0; i<mp->tx_ring_size; i++ ) { |
---|
1478 | assert( !bd_rdbuf( & mp->tx_ring[i] ) ); |
---|
1479 | assert( !mp->tx_ring_user[i] ); |
---|
1480 | } |
---|
1481 | #endif |
---|
1482 | } |
---|
1483 | |
---|
1484 | if ( mp->rx_ring_size ) { |
---|
1485 | for ( i=0; i<mp->rx_ring_size; i++ ) { |
---|
1486 | bd_clrfl( &mp->rx_ring[i], TSEC_RXBD_E ); |
---|
1487 | bd_wrbuf( &mp->rx_ring[i], 0 ); |
---|
1488 | if ( mp->rx_ring_user[i] ) |
---|
1489 | mp->consume_rxbuf( mp->rx_ring_user[i], mp->consume_rxbuf_arg, 0 ); |
---|
1490 | mp->rx_ring_user[i] = 0; |
---|
1491 | } |
---|
1492 | } |
---|
1493 | } |
---|
1494 | |
---|
1495 | /* |
---|
1496 | * calls BSP_tsec_stop_hw(), releases all resources and marks the interface |
---|
1497 | * as unused. |
---|
1498 | * RETURNS 0 on success, nonzero on failure. |
---|
1499 | * NOTE: the handle MUST NOT be used after successful execution of this |
---|
1500 | * routine. |
---|
1501 | */ |
---|
1502 | int |
---|
1503 | BSP_tsec_detach(struct tsec_private *mp) |
---|
1504 | { |
---|
1505 | |
---|
1506 | if ( ! mp || !mp->sc || ! mp->sc->arpcom.ac_if.if_init ) { |
---|
1507 | fprintf(stderr,"Unit not setup -- programming error!\n"); |
---|
1508 | return -1; |
---|
1509 | } |
---|
1510 | |
---|
1511 | BSP_tsec_stop_hw(mp); |
---|
1512 | |
---|
1513 | install_remove_isrs( 0, mp, mp->irq_mask ); |
---|
1514 | |
---|
1515 | free( (void*)mp->ring_area, M_DEVBUF ); |
---|
1516 | free( (void*)mp->tx_ring_user, M_DEVBUF ); |
---|
1517 | memset(mp, 0, sizeof(*mp)); |
---|
1518 | __asm__ __volatile__("":::"memory"); |
---|
1519 | |
---|
1520 | /* mark as unused */ |
---|
1521 | mp->sc->arpcom.ac_if.if_init = 0; |
---|
1522 | |
---|
1523 | return 0; |
---|
1524 | } |
---|
1525 | |
---|
1526 | /* |
---|
1527 | * Enqueue a mbuf chain or a raw data buffer for transmission; |
---|
1528 | * RETURN: #bytes sent or -1 if there are not enough free descriptors |
---|
1529 | * |
---|
1530 | * If 'len' is <=0 then 'm_head' is assumed to point to a mbuf chain. |
---|
1531 | * OTOH, a raw data packet (or a different type of buffer) |
---|
1532 | * may be sent (non-BSD driver) by pointing data_p to the start of |
---|
1533 | * the data and passing 'len' > 0. |
---|
1534 | * 'm_head' is passed back to the 'cleanup_txbuf()' callback. |
---|
1535 | * |
---|
1536 | * Comments: software cache-flushing incurs a penalty if the |
---|
1537 | * packet cannot be queued since it is flushed anyways. |
---|
1538 | * The algorithm is slightly more efficient in the normal |
---|
1539 | * case, though. |
---|
1540 | * |
---|
1541 | * RETURNS: # bytes enqueued to device for transmission or -1 if no |
---|
1542 | * space in the TX ring was available. |
---|
1543 | */ |
---|
1544 | |
---|
1545 | #if 0 |
---|
1546 | #define NEXT_TXD(mp, bd) ((bd_rdfl( bd ) & TSEC_TXBD_W) ? mp->tx_ring : (bd + 1)) |
---|
1547 | #endif |
---|
1548 | |
---|
1549 | /* |
---|
1550 | * allocate a new cluster and copy an existing chain there; |
---|
1551 | * old chain is released... |
---|
1552 | */ |
---|
1553 | static struct mbuf * |
---|
1554 | repackage_chain(struct mbuf *m_head) |
---|
1555 | { |
---|
1556 | struct mbuf *m; |
---|
1557 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
---|
1558 | |
---|
1559 | if ( !m ) { |
---|
1560 | goto bail; |
---|
1561 | } |
---|
1562 | |
---|
1563 | MCLGET(m, M_DONTWAIT); |
---|
1564 | |
---|
1565 | if ( !(M_EXT & m->m_flags) ) { |
---|
1566 | m_freem(m); |
---|
1567 | m = 0; |
---|
1568 | goto bail; |
---|
1569 | } |
---|
1570 | |
---|
1571 | m_copydata(m_head, 0, MCLBYTES, mtod(m, caddr_t)); |
---|
1572 | m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len; |
---|
1573 | |
---|
1574 | bail: |
---|
1575 | m_freem(m_head); |
---|
1576 | return m; |
---|
1577 | } |
---|
1578 | |
---|
1579 | static inline unsigned |
---|
1580 | tsec_assign_desc( TSEC_BD *bd, uint32_t buf, unsigned len, uint32_t flags) |
---|
1581 | { |
---|
1582 | st_be16 ( &bd->len, (uint16_t)len ); |
---|
1583 | bd_wrbuf( bd, buf ); |
---|
1584 | bd_cslfl( bd, flags, TSEC_TXBD_R | TSEC_TXBD_L ); |
---|
1585 | return len; |
---|
1586 | } |
---|
1587 | |
---|
1588 | |
---|
1589 | int |
---|
1590 | BSP_tsec_send_buf(struct tsec_private *mp, void *m_head, void *data_p, int len) |
---|
1591 | { |
---|
1592 | int rval; |
---|
1593 | register TSEC_BD *bd; |
---|
1594 | register unsigned l,d,t; |
---|
1595 | register struct mbuf *m1; |
---|
1596 | int nmbs; |
---|
1597 | int ismbuf = (len <= 0); |
---|
1598 | |
---|
1599 | #if DEBUG > 2 |
---|
1600 | printf("send entering...\n"); |
---|
1601 | tsec_dump_tring(mp); |
---|
1602 | #endif |
---|
1603 | /* Only way to get here is when we discover that the mbuf chain |
---|
1604 | * is too long for the tx ring |
---|
1605 | */ |
---|
1606 | startover: |
---|
1607 | |
---|
1608 | rval = 0; |
---|
1609 | |
---|
1610 | #ifdef PARANOIA |
---|
1611 | assert(m_head); |
---|
1612 | #endif |
---|
1613 | |
---|
1614 | /* if no descriptor is available; try to wipe the queue */ |
---|
1615 | if ( (mp->tx_avail < 1) && TSEC_CLEAN_ON_SEND(mp)<=0 ) { |
---|
1616 | return -1; |
---|
1617 | } |
---|
1618 | |
---|
1619 | t = mp->tx_tail; |
---|
1620 | |
---|
1621 | #ifdef PARANOIA |
---|
1622 | assert( ! bd_rdbuf( &mp->tx_ring[t] ) ); |
---|
1623 | assert( ! mp->tx_ring_user[t] ); |
---|
1624 | #endif |
---|
1625 | |
---|
1626 | if ( ! (m1 = m_head) ) |
---|
1627 | return 0; |
---|
1628 | |
---|
1629 | if ( ismbuf ) { |
---|
1630 | /* find first mbuf with actual data */ |
---|
1631 | while ( 0 == m1->m_len ) { |
---|
1632 | if ( ! (m1 = m1->m_next) ) { |
---|
1633 | /* end reached and still no data to send ?? */ |
---|
1634 | m_freem(m_head); |
---|
1635 | return 0; |
---|
1636 | } |
---|
1637 | } |
---|
1638 | } |
---|
1639 | |
---|
1640 | /* Don't use the first descriptor yet because BSP_tsec_swipe_tx() |
---|
1641 | * needs bd->buf == NULL as a marker. Hence, we |
---|
1642 | * start with the second mbuf and fill the first descriptor |
---|
1643 | * last. |
---|
1644 | */ |
---|
1645 | |
---|
1646 | l = t; |
---|
1647 | d = NEXT_TXI(mp,t); |
---|
1648 | |
---|
1649 | mp->tx_avail--; |
---|
1650 | |
---|
1651 | nmbs = 1; |
---|
1652 | if ( ismbuf ) { |
---|
1653 | register struct mbuf *m; |
---|
1654 | for ( m=m1->m_next; m; m=m->m_next ) { |
---|
1655 | if ( 0 == m->m_len ) |
---|
1656 | continue; /* skip empty mbufs */ |
---|
1657 | |
---|
1658 | nmbs++; |
---|
1659 | |
---|
1660 | if ( mp->tx_avail < 1 && TSEC_CLEAN_ON_SEND(mp)<=0 ) { |
---|
1661 | /* not enough descriptors; cleanup... |
---|
1662 | * the first slot was never used, so we start |
---|
1663 | * at mp->d_tx_h->next; |
---|
1664 | */ |
---|
1665 | for ( l = NEXT_TXI(mp, t); l!=d; l=NEXT_TXI(mp, l) ) { |
---|
1666 | bd = & mp->tx_ring[l]; |
---|
1667 | #ifdef PARANOIA |
---|
1668 | assert( mp->tx_ring_user[l] == 0 ); |
---|
1669 | #endif |
---|
1670 | bd_wrbuf( bd, 0 ); |
---|
1671 | bd_clrfl( bd, TSEC_TXBD_R | TSEC_TXBD_L ); |
---|
1672 | |
---|
1673 | mp->tx_avail++; |
---|
1674 | } |
---|
1675 | mp->tx_avail++; |
---|
1676 | if ( nmbs > TX_AVAILABLE_RING_SIZE(mp) ) { |
---|
1677 | /* this chain will never fit into the ring */ |
---|
1678 | if ( nmbs > mp->stats.maxchain ) |
---|
1679 | mp->stats.maxchain = nmbs; |
---|
1680 | mp->stats.repack++; |
---|
1681 | if ( ! (m_head = repackage_chain(m_head)) ) { |
---|
1682 | /* no cluster available */ |
---|
1683 | mp->stats.odrops++; |
---|
1684 | #ifdef PARANOIA |
---|
1685 | printf("send return 0\n"); |
---|
1686 | tsec_dump_tring(mp); |
---|
1687 | #endif |
---|
1688 | return 0; |
---|
1689 | } |
---|
1690 | #ifdef PARANOIA |
---|
1691 | printf("repackaged; start over\n"); |
---|
1692 | #endif |
---|
1693 | goto startover; |
---|
1694 | } |
---|
1695 | #ifdef PARANOIA |
---|
1696 | printf("send return -1\n"); |
---|
1697 | tsec_dump_tring(mp); |
---|
1698 | #endif |
---|
1699 | return -1; |
---|
1700 | } |
---|
1701 | |
---|
1702 | mp->tx_avail--; |
---|
1703 | |
---|
1704 | #ifdef PARANOIA |
---|
1705 | assert( ! mp->tx_ring_user[d] ); |
---|
1706 | if ( d == t ) { |
---|
1707 | tsec_dump_tring(mp); |
---|
1708 | printf("l %i, d %i, t %i, nmbs %i\n", l,d,t, nmbs); |
---|
1709 | } else |
---|
1710 | assert( d != t ); |
---|
1711 | assert( ! bd_rdbuf( &mp->tx_ring[d] ) ); |
---|
1712 | #endif |
---|
1713 | |
---|
1714 | /* fill this slot */ |
---|
1715 | rval += tsec_assign_desc( &mp->tx_ring[d], mtod(m, uint32_t), m->m_len, TSEC_TXBD_R); |
---|
1716 | |
---|
1717 | FLUSH_BUF(mtod(m, uint32_t), m->m_len); |
---|
1718 | |
---|
1719 | l = d; |
---|
1720 | d = NEXT_TXI(mp, d); |
---|
1721 | } |
---|
1722 | |
---|
1723 | /* fill first slot - don't release to DMA yet */ |
---|
1724 | rval += tsec_assign_desc( &mp->tx_ring[t], mtod(m1, uint32_t), m1->m_len, 0); |
---|
1725 | |
---|
1726 | |
---|
1727 | FLUSH_BUF(mtod(m1, uint32_t), m1->m_len); |
---|
1728 | |
---|
1729 | } else { |
---|
1730 | /* fill first slot with raw buffer - don't release to DMA yet */ |
---|
1731 | rval += tsec_assign_desc( &mp->tx_ring[t], (uint32_t)data_p, len, 0); |
---|
1732 | |
---|
1733 | FLUSH_BUF( (uint32_t)data_p, len); |
---|
1734 | } |
---|
1735 | |
---|
1736 | /* tag last slot; this covers the case where 1st==last */ |
---|
1737 | bd_setfl( &mp->tx_ring[l], TSEC_TXBD_L ); |
---|
1738 | |
---|
1739 | /* mbuf goes into last desc */ |
---|
1740 | mp->tx_ring_user[l] = m_head; |
---|
1741 | |
---|
1742 | membarrier(); |
---|
1743 | |
---|
1744 | /* turn over the whole chain by flipping ownership of the first desc */ |
---|
1745 | bd_setfl( &mp->tx_ring[t], TSEC_TXBD_R ); |
---|
1746 | |
---|
1747 | membarrier(); |
---|
1748 | |
---|
1749 | #if DEBUG > 2 |
---|
1750 | printf("send return (l=%i, t=%i, d=%i) %i\n", l, t, d, rval); |
---|
1751 | tsec_dump_tring(mp); |
---|
1752 | #endif |
---|
1753 | |
---|
1754 | /* notify the device */ |
---|
1755 | fec_wr( mp->base, TSEC_TSTAT, TSEC_TSTAT_THLT ); |
---|
1756 | |
---|
1757 | /* Update softc */ |
---|
1758 | mp->stats.packet++; |
---|
1759 | if ( nmbs > mp->stats.maxchain ) |
---|
1760 | mp->stats.maxchain = nmbs; |
---|
1761 | |
---|
1762 | /* remember new tail */ |
---|
1763 | mp->tx_tail = d; |
---|
1764 | |
---|
1765 | return rval; /* #bytes sent */ |
---|
1766 | } |
---|
1767 | |
---|
1768 | /* |
---|
1769 | * Retrieve all received buffers from the RX ring, replacing them |
---|
1770 | * by fresh ones (obtained from the alloc_rxbuf() callback). The |
---|
1771 | * received buffers are passed to consume_rxbuf(). |
---|
1772 | * |
---|
1773 | * RETURNS: number of buffers processed. |
---|
1774 | */ |
---|
1775 | int |
---|
1776 | BSP_tsec_swipe_rx(struct tsec_private *mp) |
---|
1777 | { |
---|
1778 | int rval = 0, err; |
---|
1779 | unsigned i; |
---|
1780 | uint16_t flags; |
---|
1781 | TSEC_BD *bd; |
---|
1782 | void *newbuf; |
---|
1783 | int sz; |
---|
1784 | uint16_t len; |
---|
1785 | uintptr_t baddr; |
---|
1786 | |
---|
1787 | i = mp->rx_tail; |
---|
1788 | bd = mp->rx_ring + i; |
---|
1789 | flags = bd_rdfl( bd ); |
---|
1790 | |
---|
1791 | while ( ! (TSEC_RXBD_E & flags) ) { |
---|
1792 | |
---|
1793 | /* err is not valid if not qualified by TSEC_RXBD_L */ |
---|
1794 | if ( ( err = (TSEC_RXBD_ERROR & flags) ) ) { |
---|
1795 | /* make sure error is < 0 */ |
---|
1796 | err |= 0xffff0000; |
---|
1797 | /* pass 'L' flag out so they can verify... */ |
---|
1798 | err |= (flags & TSEC_RXBD_L); |
---|
1799 | } |
---|
1800 | |
---|
1801 | #ifdef PARANOIA |
---|
1802 | assert( flags & TSEC_RXBD_L ); |
---|
1803 | assert( mp->rx_ring_user[i] ); |
---|
1804 | #endif |
---|
1805 | |
---|
1806 | if ( err || !(newbuf = mp->alloc_rxbuf(&sz, &baddr)) ) { |
---|
1807 | /* drop packet and recycle buffer */ |
---|
1808 | newbuf = mp->rx_ring_user[i]; |
---|
1809 | mp->consume_rxbuf( 0, mp->consume_rxbuf_arg, err ); |
---|
1810 | } else { |
---|
1811 | len = ld_be16( &bd->len ); |
---|
1812 | |
---|
1813 | #ifdef PARANOIA |
---|
1814 | assert( 0 == (baddr & (RX_BUF_ALIGNMENT-1)) ); |
---|
1815 | assert( len > 0 ); |
---|
1816 | #endif |
---|
1817 | |
---|
1818 | mp->consume_rxbuf( mp->rx_ring_user[i], mp->consume_rxbuf_arg, len ); |
---|
1819 | |
---|
1820 | mp->rx_ring_user[i] = newbuf; |
---|
1821 | st_be16( &bd->len, sz ); |
---|
1822 | bd_wrbuf( bd, baddr ); |
---|
1823 | } |
---|
1824 | |
---|
1825 | RTEMS_COMPILER_MEMORY_BARRIER(); |
---|
1826 | |
---|
1827 | bd_wrfl( &mp->rx_ring[i], (flags & ~TSEC_RXBD_ERROR) | TSEC_RXBD_E ); |
---|
1828 | |
---|
1829 | rval++; |
---|
1830 | |
---|
1831 | i = NEXT_RXI( mp, i ); |
---|
1832 | bd = mp->rx_ring + i; |
---|
1833 | flags = bd_rdfl( bd ); |
---|
1834 | } |
---|
1835 | |
---|
1836 | fec_wr( mp->base, TSEC_RSTAT, TSEC_RSTAT_QHLT ); |
---|
1837 | |
---|
1838 | mp->rx_tail = i; |
---|
1839 | return rval; |
---|
1840 | } |
---|
1841 | |
---|
1842 | /* read ethernet address from hw to buffer */ |
---|
1843 | void |
---|
1844 | BSP_tsec_read_eaddr(struct tsec_private *mp, unsigned char *eaddr) |
---|
1845 | { |
---|
1846 | union { |
---|
1847 | uint32_t u; |
---|
1848 | uint16_t s[2]; |
---|
1849 | uint8_t c[4]; |
---|
1850 | } x; |
---|
1851 | st_le32( (volatile uint32_t *)(eaddr+2), fec_rd(mp->base, TSEC_MACSTNADDR1) ); |
---|
1852 | x.u = fec_rd(mp->base, TSEC_MACSTNADDR2); |
---|
1853 | st_le16( (volatile uint16_t *)(eaddr), x.s[0]); |
---|
1854 | } |
---|
1855 | |
---|
1856 | /* mdio / mii interface wrappers for rtems_mii_ioctl API */ |
---|
1857 | |
---|
1858 | /* |
---|
1859 | * Busy-wait -- this can take a while: I measured ~550 timebase-ticks |
---|
1860 | * @333333333Hz, TB divisor is 8 -> 13us |
---|
1861 | */ |
---|
1862 | static inline void mii_wait(FEC_Enet_Base b) |
---|
1863 | { |
---|
1864 | while ( (TSEC_MIIMIND_BUSY & fec_rd( b, TSEC_MIIMIND )) ) |
---|
1865 | ; |
---|
1866 | } |
---|
1867 | |
---|
1868 | /* MII operations are rather slow :-( */ |
---|
1869 | static int |
---|
1870 | tsec_mdio_rd(int phyidx, void *uarg, unsigned reg, uint32_t *pval) |
---|
1871 | { |
---|
1872 | uint32_t v; |
---|
1873 | #ifdef TEST_MII_TIMING |
---|
1874 | uint32_t t; |
---|
1875 | #endif |
---|
1876 | struct tsec_private *mp = uarg; |
---|
1877 | FEC_Enet_Base b = mp->phy_base; |
---|
1878 | |
---|
1879 | if ( phyidx != 0 ) |
---|
1880 | return -1; /* only one phy supported for now */ |
---|
1881 | |
---|
1882 | /* write phy and register address */ |
---|
1883 | fec_wr( b, TSEC_MIIMADD, TSEC_MIIMADD_ADDR(mp->phy,reg) ); |
---|
1884 | |
---|
1885 | /* clear READ bit */ |
---|
1886 | v = fec_rd( b, TSEC_MIIMCOM ); |
---|
1887 | fec_wr( b, TSEC_MIIMCOM, v & ~TSEC_MIIMCOM_READ ); |
---|
1888 | |
---|
1889 | #ifdef TEST_MII_TIMING |
---|
1890 | t = tb_rd(); |
---|
1891 | #endif |
---|
1892 | |
---|
1893 | /* trigger READ operation by READ-bit 0-->1 transition */ |
---|
1894 | fec_wr( b, TSEC_MIIMCOM, v | TSEC_MIIMCOM_READ ); |
---|
1895 | |
---|
1896 | /* (busy) wait for completion */ |
---|
1897 | |
---|
1898 | mii_wait( b ); |
---|
1899 | |
---|
1900 | /* Ugly workaround: I observed that the link status |
---|
1901 | * is not correctly reported when the link changes to |
---|
1902 | * a good status - a failed link is reported until |
---|
1903 | * we read twice :-( |
---|
1904 | */ |
---|
1905 | if ( MII_BMSR == reg ) { |
---|
1906 | /* trigger a second read operation */ |
---|
1907 | fec_wr( b, TSEC_MIIMCOM, v & ~TSEC_MIIMCOM_READ ); |
---|
1908 | fec_wr( b, TSEC_MIIMCOM, v | TSEC_MIIMCOM_READ ); |
---|
1909 | mii_wait( b ); |
---|
1910 | } |
---|
1911 | |
---|
1912 | #ifdef TEST_MII_TIMING |
---|
1913 | t = tb_rd() - t; |
---|
1914 | printf("Reading MII took %"PRIi32"\n", t); |
---|
1915 | #endif |
---|
1916 | /* return result */ |
---|
1917 | *pval = fec_rd( b, TSEC_MIIMSTAT ) & 0xffff; |
---|
1918 | return 0; |
---|
1919 | } |
---|
1920 | |
---|
1921 | STATIC int |
---|
1922 | tsec_mdio_wr(int phyidx, void *uarg, unsigned reg, uint32_t val) |
---|
1923 | { |
---|
1924 | #ifdef TEST_MII_TIMING |
---|
1925 | uint32_t t; |
---|
1926 | #endif |
---|
1927 | struct tsec_private *mp = uarg; |
---|
1928 | FEC_Enet_Base b = mp->phy_base; |
---|
1929 | |
---|
1930 | if ( phyidx != 0 ) |
---|
1931 | return -1; /* only one phy supported for now */ |
---|
1932 | |
---|
1933 | #ifdef TEST_MII_TIMING |
---|
1934 | t = tb_rd(); |
---|
1935 | #endif |
---|
1936 | |
---|
1937 | fec_wr( b, TSEC_MIIMADD, TSEC_MIIMADD_ADDR(mp->phy,reg) ); |
---|
1938 | fec_wr( b, TSEC_MIIMCON, val & 0xffff ); |
---|
1939 | |
---|
1940 | mii_wait( b ); |
---|
1941 | |
---|
1942 | #ifdef TEST_MII_TIMING |
---|
1943 | t = tb_rd() - t; |
---|
1944 | printf("Writing MII took %"PRIi32"\n", t); |
---|
1945 | #endif |
---|
1946 | |
---|
1947 | return 0; |
---|
1948 | } |
---|
1949 | |
---|
1950 | /* Public, locked versions */ |
---|
1951 | uint32_t |
---|
1952 | BSP_tsec_mdio_rd(struct tsec_private *mp, unsigned reg) |
---|
1953 | { |
---|
1954 | uint32_t val, rval; |
---|
1955 | |
---|
1956 | REGLOCK(); |
---|
1957 | rval = tsec_mdio_rd(0, mp, reg, &val ) ? -1 : val; |
---|
1958 | REGUNLOCK(); |
---|
1959 | |
---|
1960 | return rval; |
---|
1961 | } |
---|
1962 | |
---|
1963 | int |
---|
1964 | BSP_tsec_mdio_wr(struct tsec_private *mp, unsigned reg, uint32_t val) |
---|
1965 | { |
---|
1966 | int rval; |
---|
1967 | |
---|
1968 | REGLOCK(); |
---|
1969 | rval = tsec_mdio_wr(0, mp, reg, val); |
---|
1970 | REGUNLOCK(); |
---|
1971 | |
---|
1972 | return rval; |
---|
1973 | } |
---|
1974 | |
---|
1975 | static struct rtems_mdio_info tsec_mdio = { |
---|
1976 | mdio_r: tsec_mdio_rd, |
---|
1977 | mdio_w: tsec_mdio_wr, |
---|
1978 | has_gmii: 1, |
---|
1979 | }; |
---|
1980 | |
---|
1981 | |
---|
1982 | /* |
---|
1983 | * read/write media word. |
---|
1984 | * 'cmd': can be SIOCGIFMEDIA, SIOCSIFMEDIA, 0 or 1. The latter |
---|
1985 | * are aliased to the former for convenience. |
---|
1986 | * 'parg': pointer to media word. |
---|
1987 | * |
---|
1988 | * RETURNS: 0 on success, nonzero on error |
---|
1989 | */ |
---|
1990 | int |
---|
1991 | BSP_tsec_media_ioctl(struct tsec_private *mp, int cmd, int *parg) |
---|
1992 | { |
---|
1993 | int rval; |
---|
1994 | /* alias cmd == 0,1 for convenience when calling from shell */ |
---|
1995 | switch ( cmd ) { |
---|
1996 | case 0: cmd = SIOCGIFMEDIA; |
---|
1997 | break; |
---|
1998 | case 1: cmd = SIOCSIFMEDIA; |
---|
1999 | case SIOCGIFMEDIA: |
---|
2000 | case SIOCSIFMEDIA: |
---|
2001 | break; |
---|
2002 | default: return -1; |
---|
2003 | } |
---|
2004 | REGLOCK(); |
---|
2005 | tsec_mdio.has_gmii = mp->isfec ? 0 : 1; |
---|
2006 | rval = rtems_mii_ioctl(&tsec_mdio, mp, cmd, parg); |
---|
2007 | REGUNLOCK(); |
---|
2008 | return rval; |
---|
2009 | } |
---|
2010 | |
---|
2011 | /* Interrupt related routines */ |
---|
2012 | |
---|
2013 | /* |
---|
2014 | * When it comes to interrupts the chip has two rather |
---|
2015 | * annoying features: |
---|
2016 | * 1 once an IRQ is pending, clearing the IMASK does not |
---|
2017 | * de-assert the interrupt line. |
---|
2018 | * 2 the chip has three physical interrupt lines even though |
---|
2019 | * all events are reported in a single register. Rather |
---|
2020 | * useless; we must hook 3 ISRs w/o any real benefit. |
---|
2021 | * In fact, it makes our life a bit more difficult: |
---|
2022 | * |
---|
2023 | * Hence, for (1) we would have to mask interrupts at the PIC |
---|
2024 | * but to re-enable them we would have to do that three times |
---|
2025 | * because of (2). |
---|
2026 | * |
---|
2027 | * Therefore, we take the following approach: |
---|
2028 | * |
---|
2029 | * ISR masks all interrupts on the TSEC, acks/clears them |
---|
2030 | * and stores the acked irqs in the device struct where |
---|
2031 | * it is picked up by BSP_tsec_ack_irqs(). |
---|
2032 | * Since all interrupts are disabled until the daemon |
---|
2033 | * re-enables them after calling BSP_tsec_ack_irqs() |
---|
2034 | * no interrupts are lost. |
---|
2035 | * |
---|
2036 | * BUT: NO isr (including PHY isrs) MUST INTERRUPT ANY |
---|
2037 | * OTHER ONE, i.e., they all must have the same |
---|
2038 | * priority. Otherwise, integrity of the cached |
---|
2039 | * irq_pending variable may be compromised. |
---|
2040 | */ |
---|
2041 | |
---|
2042 | static inline void |
---|
2043 | tsec_dis_irqs( struct tsec_private *mp) |
---|
2044 | { |
---|
2045 | phy_dis_irq( mp ); |
---|
2046 | fec_wr( mp->base, TSEC_IMASK, TSEC_IMASK_NONE ); |
---|
2047 | } |
---|
2048 | |
---|
2049 | static inline uint32_t |
---|
2050 | tsec_dis_clr_irqs(struct tsec_private *mp) |
---|
2051 | { |
---|
2052 | uint32_t rval; |
---|
2053 | FEC_Enet_Base b = mp->base; |
---|
2054 | tsec_dis_irqs( mp ); |
---|
2055 | rval = fec_rd( b, TSEC_IEVENT); |
---|
2056 | fec_wr( b, TSEC_IEVENT, rval ); |
---|
2057 | /* Make sure we mask out the link intr */ |
---|
2058 | return rval & ~TSEC_LINK_INTR; |
---|
2059 | } |
---|
2060 | |
---|
2061 | /* |
---|
2062 | * We have 3 different ISRs just so we can count |
---|
2063 | * interrupt types independently... |
---|
2064 | */ |
---|
2065 | |
---|
2066 | static void tsec_xisr(rtems_irq_hdl_param arg) |
---|
2067 | { |
---|
2068 | struct tsec_private *mp = (struct tsec_private *)arg; |
---|
2069 | |
---|
2070 | mp->irq_pending |= tsec_dis_clr_irqs( mp ); |
---|
2071 | |
---|
2072 | mp->stats.xirqs++; |
---|
2073 | |
---|
2074 | rtems_event_send( mp->tid, mp->event ); |
---|
2075 | } |
---|
2076 | |
---|
2077 | static void tsec_risr(rtems_irq_hdl_param arg) |
---|
2078 | { |
---|
2079 | struct tsec_private *mp = (struct tsec_private *)arg; |
---|
2080 | |
---|
2081 | mp->irq_pending |= tsec_dis_clr_irqs( mp ); |
---|
2082 | |
---|
2083 | mp->stats.rirqs++; |
---|
2084 | |
---|
2085 | rtems_event_send( mp->tid, mp->event ); |
---|
2086 | } |
---|
2087 | |
---|
2088 | static void tsec_eisr(rtems_irq_hdl_param arg) |
---|
2089 | { |
---|
2090 | struct tsec_private *mp = (struct tsec_private *)arg; |
---|
2091 | |
---|
2092 | mp->irq_pending |= tsec_dis_clr_irqs( mp ); |
---|
2093 | |
---|
2094 | mp->stats.eirqs++; |
---|
2095 | |
---|
2096 | rtems_event_send( mp->tid, mp->event ); |
---|
2097 | } |
---|
2098 | |
---|
2099 | static void tsec_lisr(rtems_irq_hdl_param arg) |
---|
2100 | { |
---|
2101 | struct tsec_private *mp = (struct tsec_private *)arg; |
---|
2102 | |
---|
2103 | if ( phy_irq_pending( mp ) ) { |
---|
2104 | |
---|
2105 | tsec_dis_irqs( mp ); |
---|
2106 | |
---|
2107 | mp->irq_pending |= TSEC_LINK_INTR; |
---|
2108 | |
---|
2109 | mp->stats.lirqs++; |
---|
2110 | |
---|
2111 | rtems_event_send( mp->tid, mp->event ); |
---|
2112 | } |
---|
2113 | } |
---|
2114 | |
---|
2115 | /* Enable interrupts at device */ |
---|
2116 | void |
---|
2117 | BSP_tsec_enable_irqs(struct tsec_private *mp) |
---|
2118 | { |
---|
2119 | rtems_interrupt_level l; |
---|
2120 | rtems_interrupt_disable( l ); |
---|
2121 | fec_wr( mp->base, TSEC_IMASK, mp->irq_mask ); |
---|
2122 | phy_en_irq( mp ); |
---|
2123 | rtems_interrupt_enable( l ); |
---|
2124 | } |
---|
2125 | |
---|
2126 | /* Disable interrupts at device */ |
---|
2127 | void |
---|
2128 | BSP_tsec_disable_irqs(struct tsec_private *mp) |
---|
2129 | { |
---|
2130 | rtems_interrupt_level l; |
---|
2131 | rtems_interrupt_disable( l ); |
---|
2132 | tsec_dis_irqs( mp ); |
---|
2133 | rtems_interrupt_enable( l ); |
---|
2134 | } |
---|
2135 | |
---|
2136 | /* |
---|
2137 | * Acknowledge (and clear) interrupts. |
---|
2138 | * RETURNS: interrupts that were raised. |
---|
2139 | */ |
---|
2140 | uint32_t |
---|
2141 | BSP_tsec_ack_irqs(struct tsec_private *mp) |
---|
2142 | { |
---|
2143 | uint32_t rval; |
---|
2144 | |
---|
2145 | /* no need to disable interrupts because |
---|
2146 | * this should only be called after receiving |
---|
2147 | * a RTEMS event posted by the ISR which |
---|
2148 | * already shut off interrupts. |
---|
2149 | */ |
---|
2150 | rval = mp->irq_pending; |
---|
2151 | mp->irq_pending = 0; |
---|
2152 | |
---|
2153 | if ( (rval & TSEC_LINK_INTR) ) { |
---|
2154 | /* interacting with the PHY is slow so |
---|
2155 | * we do it only if we have to... |
---|
2156 | */ |
---|
2157 | phy_ack_irq( mp ); |
---|
2158 | } |
---|
2159 | |
---|
2160 | return rval & mp->irq_mask; |
---|
2161 | } |
---|
2162 | |
---|
2163 | /* Retrieve the driver daemon TID that was passed to |
---|
2164 | * BSP_tsec_setup(). |
---|
2165 | */ |
---|
2166 | |
---|
2167 | rtems_id |
---|
2168 | BSP_tsec_get_tid(struct tsec_private *mp) |
---|
2169 | { |
---|
2170 | return mp->tid; |
---|
2171 | } |
---|
2172 | |
---|
2173 | struct tsec_private * |
---|
2174 | BSP_tsec_getp(unsigned index) |
---|
2175 | { |
---|
2176 | if ( index >= TSEC_NUM_DRIVER_SLOTS ) |
---|
2177 | return 0; |
---|
2178 | return & theTsecEths[index].pvt; |
---|
2179 | } |
---|
2180 | |
---|
2181 | /* |
---|
2182 | * |
---|
2183 | * Example driver task loop (note: no synchronization of |
---|
2184 | * buffer access shown!). |
---|
2185 | * RTEMS_EVENTx = 0,1 or 2 depending on IF unit. |
---|
2186 | * |
---|
2187 | * / * setup (obtain handle) and initialize hw here * / |
---|
2188 | * |
---|
2189 | * do { |
---|
2190 | * / * ISR disables IRQs and posts event * / |
---|
2191 | * rtems_event_receive( RTEMS_EVENTx, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs ); |
---|
2192 | * irqs = BSP_tsec_ack_irqs(handle); |
---|
2193 | * if ( irqs & BSP_TSEC_IRQ_TX ) { |
---|
2194 | * BSP_tsec_swipe_tx(handle); / * cleanup_txbuf() callback executed * / |
---|
2195 | * } |
---|
2196 | * if ( irqs & BSP_TSEC_IRQ_RX ) { |
---|
2197 | * BSP_tsec_swipe_rx(handle); / * alloc_rxbuf() and consume_rxbuf() executed * / |
---|
2198 | * } |
---|
2199 | * BSP_tsec_enable_irqs(handle); |
---|
2200 | * } while (1); |
---|
2201 | * |
---|
2202 | */ |
---|
2203 | |
---|
2204 | /* BSDNET SUPPORT/GLUE ROUTINES */ |
---|
2205 | |
---|
2206 | STATIC void |
---|
2207 | tsec_stop(struct tsec_softc *sc) |
---|
2208 | { |
---|
2209 | BSP_tsec_stop_hw(&sc->pvt); |
---|
2210 | sc->arpcom.ac_if.if_timer = 0; |
---|
2211 | } |
---|
2212 | |
---|
2213 | /* allocate a mbuf for RX with a properly aligned data buffer |
---|
2214 | * RETURNS 0 if allocation fails |
---|
2215 | */ |
---|
2216 | static void * |
---|
2217 | alloc_mbuf_rx(int *psz, uintptr_t *paddr) |
---|
2218 | { |
---|
2219 | struct mbuf *m; |
---|
2220 | unsigned long l,o; |
---|
2221 | |
---|
2222 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
---|
2223 | if ( !m ) |
---|
2224 | return 0; |
---|
2225 | MCLGET(m, M_DONTWAIT); |
---|
2226 | if ( ! (m->m_flags & M_EXT) ) { |
---|
2227 | m_freem(m); |
---|
2228 | return 0; |
---|
2229 | } |
---|
2230 | |
---|
2231 | o = mtod(m, unsigned long); |
---|
2232 | l = ALIGNTO(o, RX_BUF_ALIGNMENT) - o; |
---|
2233 | |
---|
2234 | /* align start of buffer */ |
---|
2235 | m->m_data += l; |
---|
2236 | |
---|
2237 | /* reduced length */ |
---|
2238 | l = MCLBYTES - l; |
---|
2239 | |
---|
2240 | m->m_len = m->m_pkthdr.len = l; |
---|
2241 | *psz = m->m_len; |
---|
2242 | *paddr = mtod(m, unsigned long); |
---|
2243 | |
---|
2244 | return (void*) m; |
---|
2245 | } |
---|
2246 | |
---|
2247 | static void consume_rx_mbuf(void *buf, void *arg, int len) |
---|
2248 | { |
---|
2249 | struct ifnet *ifp = arg; |
---|
2250 | if ( len <= 0 ) { |
---|
2251 | ifp->if_iqdrops++; |
---|
2252 | if ( len < 0 ) { |
---|
2253 | ifp->if_ierrors++; |
---|
2254 | } |
---|
2255 | /* caller recycles mbuf */ |
---|
2256 | } else { |
---|
2257 | struct ether_header *eh; |
---|
2258 | struct mbuf *m = buf; |
---|
2259 | |
---|
2260 | eh = (struct ether_header *)(mtod(m, unsigned long) + ETH_RX_OFFSET); |
---|
2261 | m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header) - ETH_RX_OFFSET - ETH_CRC_LEN; |
---|
2262 | m->m_data += sizeof(struct ether_header) + ETH_RX_OFFSET; |
---|
2263 | m->m_pkthdr.rcvif = ifp; |
---|
2264 | |
---|
2265 | ifp->if_ipackets++; |
---|
2266 | ifp->if_ibytes += m->m_pkthdr.len; |
---|
2267 | |
---|
2268 | /* send buffer upwards */ |
---|
2269 | if (0) { |
---|
2270 | /* Low-level debugging */ |
---|
2271 | int i; |
---|
2272 | for (i=0; i<13; i++) { |
---|
2273 | printf("%02X:",((char*)eh)[i]); |
---|
2274 | } |
---|
2275 | printf("%02X\n",((char*)eh)[i]); |
---|
2276 | for (i=0; i<m->m_len; i++) { |
---|
2277 | if ( !(i&15) ) |
---|
2278 | printf("\n"); |
---|
2279 | printf("0x%02x ",mtod(m,char*)[i]); |
---|
2280 | } |
---|
2281 | printf("\n"); |
---|
2282 | } |
---|
2283 | |
---|
2284 | if (0) /* Low-level debugging/testing without bsd stack */ |
---|
2285 | m_freem(m); |
---|
2286 | else |
---|
2287 | ether_input(ifp, eh, m); |
---|
2288 | } |
---|
2289 | } |
---|
2290 | |
---|
2291 | static void release_tx_mbuf(void *buf, void *arg, int err) |
---|
2292 | { |
---|
2293 | struct ifnet *ifp = arg; |
---|
2294 | struct mbuf *mb = buf; |
---|
2295 | |
---|
2296 | if ( err ) { |
---|
2297 | ifp->if_oerrors++; |
---|
2298 | } else { |
---|
2299 | ifp->if_opackets++; |
---|
2300 | } |
---|
2301 | ifp->if_obytes += mb->m_pkthdr.len; |
---|
2302 | m_freem(mb); |
---|
2303 | } |
---|
2304 | |
---|
2305 | /* BSDNET DRIVER CALLBACKS */ |
---|
2306 | |
---|
2307 | static void |
---|
2308 | tsec_init(void *arg) |
---|
2309 | { |
---|
2310 | struct tsec_softc *sc = arg; |
---|
2311 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
2312 | BSP_tsec_init_hw(&sc->pvt, ifp->if_flags & IFF_PROMISC, sc->arpcom.ac_enaddr); |
---|
2313 | ifp->if_flags |= IFF_RUNNING; |
---|
2314 | sc->arpcom.ac_if.if_timer = 0; |
---|
2315 | } |
---|
2316 | |
---|
2317 | /* bsdnet driver entry to start transmission */ |
---|
2318 | static void |
---|
2319 | tsec_start(struct ifnet *ifp) |
---|
2320 | { |
---|
2321 | struct tsec_softc *sc = ifp->if_softc; |
---|
2322 | struct mbuf *m = 0; |
---|
2323 | |
---|
2324 | while ( ifp->if_snd.ifq_head ) { |
---|
2325 | IF_DEQUEUE( &ifp->if_snd, m ); |
---|
2326 | if ( BSP_tsec_send_buf(&sc->pvt, m, 0, 0) < 0 ) { |
---|
2327 | IF_PREPEND( &ifp->if_snd, m); |
---|
2328 | ifp->if_flags |= IFF_OACTIVE; |
---|
2329 | break; |
---|
2330 | } |
---|
2331 | /* need to do this really only once |
---|
2332 | * but it's cheaper this way. |
---|
2333 | */ |
---|
2334 | ifp->if_timer = 2*IFNET_SLOWHZ; |
---|
2335 | } |
---|
2336 | } |
---|
2337 | |
---|
2338 | /* bsdnet driver entry; */ |
---|
2339 | static void |
---|
2340 | tsec_watchdog(struct ifnet *ifp) |
---|
2341 | { |
---|
2342 | struct tsec_softc *sc = ifp->if_softc; |
---|
2343 | |
---|
2344 | ifp->if_oerrors++; |
---|
2345 | printk(DRVNAME"%i: watchdog timeout; resetting\n", ifp->if_unit); |
---|
2346 | |
---|
2347 | tsec_init(sc); |
---|
2348 | tsec_start(ifp); |
---|
2349 | } |
---|
2350 | |
---|
2351 | /* bsdnet driver ioctl entry */ |
---|
2352 | static int |
---|
2353 | tsec_ioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) |
---|
2354 | { |
---|
2355 | struct tsec_softc *sc = ifp->if_softc; |
---|
2356 | struct ifreq *ifr = (struct ifreq *)data; |
---|
2357 | #if 0 |
---|
2358 | uint32_t v; |
---|
2359 | #endif |
---|
2360 | int error = 0; |
---|
2361 | int f; |
---|
2362 | |
---|
2363 | switch ( cmd ) { |
---|
2364 | case SIOCSIFFLAGS: |
---|
2365 | f = ifp->if_flags; |
---|
2366 | if ( f & IFF_UP ) { |
---|
2367 | if ( ! ( f & IFF_RUNNING ) ) { |
---|
2368 | tsec_init(sc); |
---|
2369 | } else { |
---|
2370 | if ( (f & IFF_PROMISC) != (sc->bsd.oif_flags & IFF_PROMISC) ) { |
---|
2371 | /* Hmm - the manual says we must change the RCTRL |
---|
2372 | * register only after a reset or if DMACTRL[GRS] |
---|
2373 | * is cleared which is the normal operating |
---|
2374 | * condition. I hope this is legal ?? |
---|
2375 | */ |
---|
2376 | if ( (f & IFF_PROMISC) ) { |
---|
2377 | fec_set( sc->pvt.base, TSEC_RCTRL, TSEC_RCTRL_PROM ); |
---|
2378 | } else { |
---|
2379 | fec_clr( sc->pvt.base, TSEC_RCTRL, TSEC_RCTRL_PROM ); |
---|
2380 | } |
---|
2381 | } |
---|
2382 | /* FIXME: other flag changes are ignored/unimplemented */ |
---|
2383 | } |
---|
2384 | } else { |
---|
2385 | if ( f & IFF_RUNNING ) { |
---|
2386 | tsec_stop(sc); |
---|
2387 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
---|
2388 | } |
---|
2389 | } |
---|
2390 | sc->bsd.oif_flags = ifp->if_flags; |
---|
2391 | break; |
---|
2392 | |
---|
2393 | case SIOCGIFMEDIA: |
---|
2394 | case SIOCSIFMEDIA: |
---|
2395 | error = BSP_tsec_media_ioctl(&sc->pvt, cmd, &ifr->ifr_media); |
---|
2396 | break; |
---|
2397 | |
---|
2398 | /* |
---|
2399 | * TODO |
---|
2400 | * |
---|
2401 | * case SIOCADDMULTI: |
---|
2402 | * case SIOCDELMULTI: |
---|
2403 | * |
---|
2404 | * break; |
---|
2405 | */ |
---|
2406 | |
---|
2407 | |
---|
2408 | case SIO_RTEMS_SHOW_STATS: |
---|
2409 | BSP_tsec_dump_stats( &sc->pvt, stdout ); |
---|
2410 | break; |
---|
2411 | |
---|
2412 | default: |
---|
2413 | error = ether_ioctl(ifp, cmd, data); |
---|
2414 | break; |
---|
2415 | } |
---|
2416 | |
---|
2417 | return error; |
---|
2418 | } |
---|
2419 | |
---|
2420 | /* DRIVER TASK */ |
---|
2421 | |
---|
2422 | /* Daemon task does all the 'interrupt' work */ |
---|
2423 | static void tsec_daemon(void *arg) |
---|
2424 | { |
---|
2425 | struct tsec_softc *sc; |
---|
2426 | struct ifnet *ifp; |
---|
2427 | rtems_event_set evs; |
---|
2428 | for (;;) { |
---|
2429 | rtems_bsdnet_event_receive( EV_MSK, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &evs ); |
---|
2430 | evs &= EV_MSK; |
---|
2431 | for ( sc = theTsecEths; evs; evs>>=EV_PER_UNIT, sc++ ) { |
---|
2432 | if ( EV_IS_ANY(evs) ) { |
---|
2433 | |
---|
2434 | register uint32_t x; |
---|
2435 | |
---|
2436 | ifp = &sc->arpcom.ac_if; |
---|
2437 | |
---|
2438 | if ( !(ifp->if_flags & IFF_UP) ) { |
---|
2439 | tsec_stop(sc); |
---|
2440 | ifp->if_flags &= ~(IFF_UP|IFF_RUNNING); |
---|
2441 | continue; |
---|
2442 | } |
---|
2443 | |
---|
2444 | if ( !(ifp->if_flags & IFF_RUNNING) ) { |
---|
2445 | /* event could have been pending at the time hw was stopped; |
---|
2446 | * just ignore... |
---|
2447 | */ |
---|
2448 | continue; |
---|
2449 | } |
---|
2450 | |
---|
2451 | x = BSP_tsec_ack_irqs(&sc->pvt); |
---|
2452 | |
---|
2453 | if ( TSEC_LINK_INTR & x ) { |
---|
2454 | /* phy status changed */ |
---|
2455 | int media; |
---|
2456 | |
---|
2457 | #ifdef DEBUG |
---|
2458 | printf("LINK INTR\n"); |
---|
2459 | #endif |
---|
2460 | if ( -1 != (media = mac_set_duplex( &sc->pvt )) ) { |
---|
2461 | #ifdef DEBUG |
---|
2462 | rtems_ifmedia2str( media, 0, 0 ); |
---|
2463 | printf("\n"); |
---|
2464 | #endif |
---|
2465 | if ( IFM_LINK_OK & media ) { |
---|
2466 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
2467 | tsec_start(ifp); |
---|
2468 | } else { |
---|
2469 | /* stop sending */ |
---|
2470 | ifp->if_flags |= IFF_OACTIVE; |
---|
2471 | } |
---|
2472 | } |
---|
2473 | } |
---|
2474 | |
---|
2475 | /* free tx chain */ |
---|
2476 | if ( (TSEC_TXIRQ & x) && BSP_tsec_swipe_tx(&sc->pvt) ) { |
---|
2477 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
2478 | if ( TX_AVAILABLE_RING_SIZE(&sc->pvt) == sc->pvt.tx_avail ) |
---|
2479 | ifp->if_timer = 0; |
---|
2480 | tsec_start(ifp); |
---|
2481 | } |
---|
2482 | if ( (TSEC_RXIRQ & x) ) |
---|
2483 | BSP_tsec_swipe_rx(&sc->pvt); |
---|
2484 | |
---|
2485 | BSP_tsec_enable_irqs(&sc->pvt); |
---|
2486 | } |
---|
2487 | } |
---|
2488 | } |
---|
2489 | } |
---|
2490 | |
---|
2491 | /* PUBLIC RTEMS BSDNET ATTACH FUNCTION */ |
---|
2492 | int |
---|
2493 | rtems_tsec_attach(struct rtems_bsdnet_ifconfig *ifcfg, int attaching) |
---|
2494 | { |
---|
2495 | char *unitName; |
---|
2496 | int unit,i,cfgUnits; |
---|
2497 | struct tsec_softc *sc; |
---|
2498 | struct ifnet *ifp; |
---|
2499 | |
---|
2500 | unit = rtems_bsdnet_parse_driver_name(ifcfg, &unitName); |
---|
2501 | if ( unit <= 0 || unit > TSEC_NUM_DRIVER_SLOTS ) { |
---|
2502 | printk(DRVNAME": Bad unit number %i; must be 1..%i\n", unit, TSEC_NUM_DRIVER_SLOTS); |
---|
2503 | return 1; |
---|
2504 | } |
---|
2505 | |
---|
2506 | sc = &theTsecEths[unit-1]; |
---|
2507 | ifp = &sc->arpcom.ac_if; |
---|
2508 | |
---|
2509 | if ( attaching ) { |
---|
2510 | if ( ifp->if_init ) { |
---|
2511 | printk(DRVNAME": instance %i already attached.\n", unit); |
---|
2512 | return -1; |
---|
2513 | } |
---|
2514 | |
---|
2515 | for ( i=cfgUnits = 0; i<TSEC_NUM_DRIVER_SLOTS; i++ ) { |
---|
2516 | if ( theTsecEths[i].arpcom.ac_if.if_init ) |
---|
2517 | cfgUnits++; |
---|
2518 | } |
---|
2519 | cfgUnits++; /* this new one */ |
---|
2520 | |
---|
2521 | /* lazy init of TID should still be thread-safe because we are protected |
---|
2522 | * by the global networking semaphore.. |
---|
2523 | */ |
---|
2524 | if ( !tsec_tid ) { |
---|
2525 | /* newproc uses the 1st 4 chars of name string to build an rtems name */ |
---|
2526 | tsec_tid = rtems_bsdnet_newproc("FECd", 4096, tsec_daemon, 0); |
---|
2527 | } |
---|
2528 | |
---|
2529 | if ( !BSP_tsec_setup( unit, |
---|
2530 | tsec_tid, |
---|
2531 | release_tx_mbuf, ifp, |
---|
2532 | alloc_mbuf_rx, |
---|
2533 | consume_rx_mbuf, ifp, |
---|
2534 | ifcfg->rbuf_count, |
---|
2535 | ifcfg->xbuf_count, |
---|
2536 | TSEC_RXIRQ | TSEC_TXIRQ | TSEC_LINK_INTR) ) { |
---|
2537 | return -1; |
---|
2538 | } |
---|
2539 | |
---|
2540 | if ( nmbclusters < sc->pvt.rx_ring_size * cfgUnits + 60 /* arbitrary */ ) { |
---|
2541 | printk(DRVNAME"%i: (tsec ethernet) Your application has not enough mbuf clusters\n", unit); |
---|
2542 | printk( " configured for this driver.\n"); |
---|
2543 | return -1; |
---|
2544 | } |
---|
2545 | |
---|
2546 | if ( ifcfg->hardware_address ) { |
---|
2547 | memcpy(sc->arpcom.ac_enaddr, ifcfg->hardware_address, ETHER_ADDR_LEN); |
---|
2548 | } else { |
---|
2549 | /* read back from hardware assuming that MotLoad already had set it up */ |
---|
2550 | BSP_tsec_read_eaddr(&sc->pvt, sc->arpcom.ac_enaddr); |
---|
2551 | } |
---|
2552 | |
---|
2553 | ifp->if_softc = sc; |
---|
2554 | ifp->if_unit = unit; |
---|
2555 | ifp->if_name = unitName; |
---|
2556 | |
---|
2557 | ifp->if_mtu = ifcfg->mtu ? ifcfg->mtu : ETHERMTU; |
---|
2558 | |
---|
2559 | ifp->if_init = tsec_init; |
---|
2560 | ifp->if_ioctl = tsec_ioctl; |
---|
2561 | ifp->if_start = tsec_start; |
---|
2562 | ifp->if_output = ether_output; |
---|
2563 | /* |
---|
2564 | * While nonzero, the 'if->if_timer' is decremented |
---|
2565 | * (by the networking code) at a rate of IFNET_SLOWHZ (1hz) and 'if_watchdog' |
---|
2566 | * is called when it expires. |
---|
2567 | * If either of those fields is 0 the feature is disabled. |
---|
2568 | */ |
---|
2569 | ifp->if_watchdog = tsec_watchdog; |
---|
2570 | ifp->if_timer = 0; |
---|
2571 | |
---|
2572 | sc->bsd.oif_flags = /* ... */ |
---|
2573 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; |
---|
2574 | |
---|
2575 | /* |
---|
2576 | * if unset, this set to 10Mbps by ether_ifattach; seems to be unused by bsdnet stack; |
---|
2577 | * could be updated along with phy speed, though... |
---|
2578 | ifp->if_baudrate = 10000000; |
---|
2579 | */ |
---|
2580 | |
---|
2581 | /* NOTE: ether_output drops packets if ifq_len >= ifq_maxlen |
---|
2582 | * but this is the packet count, not the fragment count! |
---|
2583 | ifp->if_snd.ifq_maxlen = sc->pvt.tx_ring_size; |
---|
2584 | */ |
---|
2585 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
2586 | |
---|
2587 | #ifdef TSEC_DETACH_HACK |
---|
2588 | if ( !ifp->if_addrlist ) /* do only the first time [reattach hack] */ |
---|
2589 | #endif |
---|
2590 | { |
---|
2591 | if_attach(ifp); |
---|
2592 | ether_ifattach(ifp); |
---|
2593 | } |
---|
2594 | |
---|
2595 | } else { |
---|
2596 | #ifdef TSEC_DETACH_HACK |
---|
2597 | if ( !ifp->if_init ) { |
---|
2598 | printk(DRVNAME": instance %i not attached.\n", unit); |
---|
2599 | return -1; |
---|
2600 | } |
---|
2601 | return tsec_detach(sc); |
---|
2602 | #else |
---|
2603 | printk(DRVNAME": interface detaching not implemented\n"); |
---|
2604 | return -1; |
---|
2605 | #endif |
---|
2606 | } |
---|
2607 | |
---|
2608 | return 0; |
---|
2609 | } |
---|
2610 | |
---|
2611 | /* PHY stuff should really not be in this driver but separate :-( |
---|
2612 | * However, I don't have time right now to implement clean |
---|
2613 | * boundaries: |
---|
2614 | * - PHY driver should only know about the PHY |
---|
2615 | * - TSEC driver only provides MII access and knows |
---|
2616 | * how to deal with a PHY interrupt. |
---|
2617 | * - BSP knows how interrupts are routed. E.g., the MVME3100 |
---|
2618 | * shares a single IRQ line among 3 PHYs (for the three ports) |
---|
2619 | * and provides a special 'on-board' register for determining |
---|
2620 | * what PHY raised an interrupt w/o the need to do any MII IO. |
---|
2621 | * Integrating all these bits in a clean way is not as easy as |
---|
2622 | * just hacking away, sorry... |
---|
2623 | */ |
---|
2624 | |
---|
2625 | /* |
---|
2626 | * Broadcom 54xx PHY register definitions. Unfriendly Broadcom doesn't |
---|
2627 | * release specs for their products :-( -- valuable info comes from |
---|
2628 | * the linux driver by |
---|
2629 | * Maciej W. Rozycki <macro@linux-mips.org> |
---|
2630 | * Amy Fong |
---|
2631 | */ |
---|
2632 | |
---|
2633 | #define BCM54xx_GBCR 0x09 /* gigabit control */ |
---|
2634 | #define BCM54xx_GBCR_FD (1<<9) /* full-duplex cap. */ |
---|
2635 | |
---|
2636 | #define BCM54xx_ECR 0x10 /* extended control */ |
---|
2637 | #define BCM54xx_ECR_IM (1<<12) /* IRQ mask */ |
---|
2638 | #define BCM54xx_ECR_IF (1<<12) /* IRQ force */ |
---|
2639 | |
---|
2640 | #define BCM54xx_ESR 0x11 /* extended status */ |
---|
2641 | #define BCM54xx_ESR_IRQ (1<<12) /* IRQ pending */ |
---|
2642 | |
---|
2643 | #define BCM54xx_AUXCR 0x18 /* AUX control */ |
---|
2644 | #define BCM54xx_AUXCR_PWR10BASET (1<<2) |
---|
2645 | |
---|
2646 | #define BCM54xx_AUXST 0x19 /* AUX status */ |
---|
2647 | #define BCM54xx_AUXST_LNKMM (7<<8) /* link mode mask */ |
---|
2648 | |
---|
2649 | /* link mode (linux' syngem_phy.c helped here...) |
---|
2650 | * |
---|
2651 | * 0: no link |
---|
2652 | * 1: 10BT half |
---|
2653 | * 2: 10BT full |
---|
2654 | * 3: 100BT half |
---|
2655 | * 4: 100BT half |
---|
2656 | * 5: 100BT full |
---|
2657 | * 6: 1000BT full |
---|
2658 | * 7: 1000BT full |
---|
2659 | */ |
---|
2660 | |
---|
2661 | #define BCM54xx_ISR 0x1a /* IRQ status */ |
---|
2662 | #define BCM54xx_IMR 0x1b /* IRQ mask */ |
---|
2663 | #define BCM54xx_IRQ_CRC (1<< 0) /* CRC error */ |
---|
2664 | #define BCM54xx_IRQ_LNK (1<< 1) /* LINK status chg. */ |
---|
2665 | #define BCM54xx_IRQ_SPD (1<< 2) /* SPEED change */ |
---|
2666 | #define BCM54xx_IRQ_DUP (1<< 3) /* LINK status chg. */ |
---|
2667 | #define BCM54xx_IRQ_LRS (1<< 4) /* Lcl. RX status chg.*/ |
---|
2668 | #define BCM54xx_IRQ_RRS (1<< 5) /* Rem. RX status chg.*/ |
---|
2669 | #define BCM54xx_IRQ_SSE (1<< 6) /* Scrambler sync err */ |
---|
2670 | #define BCM54xx_IRQ_UHCD (1<< 7) /* Unsupp. HCD neg. */ |
---|
2671 | #define BCM54xx_IRQ_NHCD (1<< 8) /* No HCD */ |
---|
2672 | #define BCM54xx_IRQ_HCDL (1<< 9) /* No HCD Link */ |
---|
2673 | #define BCM54xx_IRQ_ANPR (1<<10) /* Aneg. pg. req. */ |
---|
2674 | #define BCM54xx_IRQ_LC (1<<11) /* All ctrs. < 128 */ |
---|
2675 | #define BCM54xx_IRQ_HC (1<<12) /* Ctr > 32768 */ |
---|
2676 | #define BCM54xx_IRQ_MDIX (1<<13) /* MDIX status chg. */ |
---|
2677 | #define BCM54xx_IRQ_PSERR (1<<14) /* Pair swap error */ |
---|
2678 | |
---|
2679 | #define PHY_IRQS ( BCM54xx_IRQ_LNK | BCM54xx_IRQ_SPD | BCM54xx_IRQ_DUP ) |
---|
2680 | |
---|
2681 | |
---|
2682 | static void |
---|
2683 | phy_en_irq_at_phy( struct tsec_private *mp ) |
---|
2684 | { |
---|
2685 | uint32_t ecr; |
---|
2686 | |
---|
2687 | REGLOCK(); |
---|
2688 | tsec_mdio_rd( 0, mp, BCM54xx_ECR, &ecr ); |
---|
2689 | ecr &= ~BCM54xx_ECR_IM; |
---|
2690 | tsec_mdio_wr( 0, mp, BCM54xx_ECR, ecr ); |
---|
2691 | REGUNLOCK(); |
---|
2692 | } |
---|
2693 | |
---|
2694 | static void |
---|
2695 | phy_dis_irq_at_phy( struct tsec_private *mp ) |
---|
2696 | { |
---|
2697 | uint32_t ecr; |
---|
2698 | |
---|
2699 | REGLOCK(); |
---|
2700 | tsec_mdio_rd( 0, mp, BCM54xx_ECR, &ecr ); |
---|
2701 | ecr |= BCM54xx_ECR_IM; |
---|
2702 | tsec_mdio_wr( 0, mp, BCM54xx_ECR, ecr ); |
---|
2703 | REGUNLOCK(); |
---|
2704 | } |
---|
2705 | |
---|
2706 | static void |
---|
2707 | phy_init_irq( int install, struct tsec_private *mp, void (*isr)(rtems_irq_hdl_param) ) |
---|
2708 | { |
---|
2709 | uint32_t v; |
---|
2710 | rtems_irq_connect_data xxx; |
---|
2711 | |
---|
2712 | xxx.on = noop; |
---|
2713 | xxx.off = noop; |
---|
2714 | xxx.isOn = nopf; |
---|
2715 | xxx.name = BSP_PHY_IRQ; |
---|
2716 | xxx.handle = mp; |
---|
2717 | xxx.hdl = isr; |
---|
2718 | |
---|
2719 | phy_dis_irq_at_phy( mp ); |
---|
2720 | |
---|
2721 | REGLOCK(); |
---|
2722 | /* Select IRQs we want */ |
---|
2723 | tsec_mdio_wr( 0, mp, BCM54xx_IMR, ~ PHY_IRQS ); |
---|
2724 | /* clear pending irqs */ |
---|
2725 | tsec_mdio_rd( 0, mp, BCM54xx_ISR, &v ); |
---|
2726 | REGUNLOCK(); |
---|
2727 | |
---|
2728 | /* install shared ISR */ |
---|
2729 | if ( ! (install ? |
---|
2730 | BSP_install_rtems_shared_irq_handler( &xxx ) : |
---|
2731 | BSP_remove_rtems_irq_handler( &xxx )) ) { |
---|
2732 | rtems_panic( "Unable to %s shared irq handler (PHY)\n", install ? "install" : "remove" ); |
---|
2733 | } |
---|
2734 | } |
---|
2735 | |
---|
2736 | /* Because on the MVME3100 multiple PHYs (belonging to different |
---|
2737 | * TSEC instances) share a single interrupt line and we want |
---|
2738 | * to disable interrupts at the PIC rather than in the individual |
---|
2739 | * PHYs (because access to those is slow) we must implement |
---|
2740 | * nesting... |
---|
2741 | */ |
---|
2742 | STATIC int phy_irq_dis_level = 0; |
---|
2743 | |
---|
2744 | /* assume 'en_irq' / 'dis_irq' cannot be interrupted. |
---|
2745 | * Either because they are called from an ISR (all |
---|
2746 | * tsec + phy isrs must have the same priority) or |
---|
2747 | * from a IRQ-protected section of code |
---|
2748 | */ |
---|
2749 | static void |
---|
2750 | phy_en_irq(struct tsec_private *mp) |
---|
2751 | { |
---|
2752 | if ( ! ( --phy_irq_dis_level ) ) { |
---|
2753 | BSP_enable_irq_at_pic( BSP_PHY_IRQ ); |
---|
2754 | } |
---|
2755 | } |
---|
2756 | |
---|
2757 | |
---|
2758 | static void |
---|
2759 | phy_dis_irq(struct tsec_private *mp) |
---|
2760 | { |
---|
2761 | if ( !(phy_irq_dis_level++) ) { |
---|
2762 | BSP_disable_irq_at_pic( BSP_PHY_IRQ ); |
---|
2763 | } |
---|
2764 | } |
---|
2765 | |
---|
2766 | static int |
---|
2767 | phy_irq_pending(struct tsec_private *mp) |
---|
2768 | { |
---|
2769 | /* MVME3100 speciality: we can check for a pending |
---|
2770 | * PHY IRQ w/o having to access the MII bus :-) |
---|
2771 | */ |
---|
2772 | return in_8( BSP_MVME3100_IRQ_DETECT_REG ) & (1 << (mp->unit - 1)); |
---|
2773 | } |
---|
2774 | |
---|
2775 | static uint32_t |
---|
2776 | phy_ack_irq(struct tsec_private *mp) |
---|
2777 | { |
---|
2778 | uint32_t v; |
---|
2779 | |
---|
2780 | REGLOCK(); |
---|
2781 | tsec_mdio_rd( 0, mp, BCM54xx_ISR, &v ); |
---|
2782 | REGUNLOCK(); |
---|
2783 | |
---|
2784 | #ifdef DEBUG |
---|
2785 | printf("phy_ack_irq: 0x%08"PRIx32"\n", v); |
---|
2786 | #endif |
---|
2787 | |
---|
2788 | return v; |
---|
2789 | } |
---|
2790 | |
---|
2791 | #if defined(PARANOIA) || defined(DEBUG) |
---|
2792 | |
---|
2793 | static void dumpbd(TSEC_BD *bd) |
---|
2794 | { |
---|
2795 | printf("Flags 0x%04"PRIx16", len 0x%04"PRIx16", buf 0x%08"PRIx32"\n", |
---|
2796 | bd_rdfl( bd ), ld_be16( &bd->len ), bd_rdbuf( bd ) ); |
---|
2797 | } |
---|
2798 | |
---|
2799 | void tsec_dump_rring(struct tsec_private *mp) |
---|
2800 | { |
---|
2801 | int i; |
---|
2802 | TSEC_BD *bd; |
---|
2803 | if ( !mp ) { |
---|
2804 | printf("Neet tsec_private * arg\n"); |
---|
2805 | return; |
---|
2806 | } |
---|
2807 | for ( i=0; i<mp->rx_ring_size; i++ ) { |
---|
2808 | bd = &mp->rx_ring[i]; |
---|
2809 | printf("[%i]: ", i); |
---|
2810 | dumpbd(bd); |
---|
2811 | } |
---|
2812 | } |
---|
2813 | |
---|
2814 | void tsec_dump_tring(struct tsec_private *mp) |
---|
2815 | { |
---|
2816 | int i; |
---|
2817 | TSEC_BD *bd; |
---|
2818 | if ( !mp ) { |
---|
2819 | printf("Neet tsec_private * arg\n"); |
---|
2820 | return; |
---|
2821 | } |
---|
2822 | for ( i=0; i<mp->tx_ring_size; i++ ) { |
---|
2823 | bd = &mp->tx_ring[i]; |
---|
2824 | printf("[%i]: ", i); |
---|
2825 | dumpbd(bd); |
---|
2826 | } |
---|
2827 | printf("Avail: %i; Head %i; Tail %i\n", mp->tx_avail, mp->tx_head, mp->tx_tail); |
---|
2828 | } |
---|
2829 | #endif |
---|
2830 | |
---|
2831 | |
---|
2832 | #ifdef DEBUG |
---|
2833 | |
---|
2834 | #undef free |
---|
2835 | #undef malloc |
---|
2836 | |
---|
2837 | #include <stdlib.h> |
---|
2838 | |
---|
2839 | void cleanup_txbuf_test(void *u, void *a, int err) |
---|
2840 | { |
---|
2841 | printf("cleanup_txbuf_test (releasing buf 0x%8p)\n", u); |
---|
2842 | free(u); |
---|
2843 | if ( err ) |
---|
2844 | printf("cleanup_txbuf_test: an error was detected\n"); |
---|
2845 | } |
---|
2846 | |
---|
2847 | void *alloc_rxbuf_test(int *p_size, uintptr_t *p_data_addr) |
---|
2848 | { |
---|
2849 | void *rval; |
---|
2850 | |
---|
2851 | *p_size = 1600; |
---|
2852 | rval = malloc( *p_size + RX_BUF_ALIGNMENT ); |
---|
2853 | *p_data_addr = (uintptr_t)ALIGNTO(rval,RX_BUF_ALIGNMENT); |
---|
2854 | |
---|
2855 | /* PRIxPTR is still broken :-( */ |
---|
2856 | printf("alloc_rxxbuf_test: allocated %i bytes @0x%8p/0x%08"PRIx32"\n", |
---|
2857 | *p_size, rval, (uint32_t)*p_data_addr); |
---|
2858 | |
---|
2859 | return rval; |
---|
2860 | } |
---|
2861 | |
---|
2862 | void consume_rxbuf_test(void *user_buf, void *consume_rxbuf_arg, int len) |
---|
2863 | { |
---|
2864 | int i; |
---|
2865 | uintptr_t d = (uintptr_t)ALIGNTO(user_buf,RX_BUF_ALIGNMENT); |
---|
2866 | |
---|
2867 | /* PRIxPTR is still broken */ |
---|
2868 | printf("consuming rx buf 0x%8p (data@ 0x%08"PRIx32")\n",user_buf, (uint32_t)d); |
---|
2869 | if ( len > 32 ) |
---|
2870 | len = 32; |
---|
2871 | if ( len < 0 ) |
---|
2872 | printf("consume_rxbuf_test: ERROR occurred: 0x%x\n", len); |
---|
2873 | else { |
---|
2874 | printf("RX:"); |
---|
2875 | for ( i=0; i<len; i++ ) { |
---|
2876 | if ( 0 == (i&0xf) ) |
---|
2877 | printf("\n "); |
---|
2878 | printf("0x%02x ", ((char*)d)[i]); |
---|
2879 | } |
---|
2880 | printf("\n"); |
---|
2881 | free(user_buf); |
---|
2882 | } |
---|
2883 | } |
---|
2884 | |
---|
2885 | unsigned char pkt[100]; |
---|
2886 | |
---|
2887 | void * tsec_up() |
---|
2888 | { |
---|
2889 | struct tsec_private *tsec = |
---|
2890 | BSP_tsec_setup( 1, 0, |
---|
2891 | cleanup_txbuf_test, 0, |
---|
2892 | alloc_rxbuf_test, |
---|
2893 | consume_rxbuf_test, 0, |
---|
2894 | 2, |
---|
2895 | 2, |
---|
2896 | 0); |
---|
2897 | BSP_tsec_init_hw(tsec, 0, 0); |
---|
2898 | memset(pkt,0,100); |
---|
2899 | memset(pkt,0xff,6); |
---|
2900 | BSP_tsec_read_eaddr(tsec, pkt+6); |
---|
2901 | pkt[12] = 0; |
---|
2902 | pkt[13] = 64; |
---|
2903 | return tsec; |
---|
2904 | } |
---|
2905 | |
---|
2906 | #ifdef DEBUG_MODULAR |
---|
2907 | int |
---|
2908 | _cexpModuleInitialize(void*u) |
---|
2909 | { |
---|
2910 | extern int ifattach(); |
---|
2911 | extern int ifconf(); |
---|
2912 | extern int rtconf(); |
---|
2913 | ifattach("ts1",rtems_tsec_attach,0); |
---|
2914 | ifconf("ts1","134.79.33.137","255.255.252.0"); |
---|
2915 | ifconf("pcn1",0,0); |
---|
2916 | rtconf(0, "134.79.33.86",0,0); |
---|
2917 | return 0; |
---|
2918 | } |
---|
2919 | #endif |
---|
2920 | #endif |
---|