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