source: rtems/c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c @ 1c2ea245

4.9
Last change on this file since 1c2ea245 was 1c2ea245, checked in by Till Straumann <strauman@…>, on 10/20/09 at 17:13:54

2009-10-20 Till Straumann <strauman@…>

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