source: rtems/bsps/powerpc/mvme3100/net/tsec.c @ 65f868c

5
Last change on this file since 65f868c was 031df391, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 23, 2018 at 7:53:31 AM

bsps: Move legacy network drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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