source: rtems/c/src/lib/libbsp/powerpc/mvme3100/network/tsec.c @ 6771a9e7

4.104.114.95
Last change on this file since 6771a9e7 was 6771a9e7, checked in by Ralf Corsepius <ralf.corsepius@…>, on Aug 20, 2008 at 9:00:11 AM

Add missing prototypes.

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