source: rtems/c/src/libchip/network/smc91111.c @ 6e701e2

4.104.11
Last change on this file since 6e701e2 was 6e701e2, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 23, 2009 at 8:12:39 PM

2009-11-23 Joel Sherrill <joel.sherrill@…>

  • libchip/network/smc91111.c: Formatting.
  • Property mode set to 100644
File size: 43.5 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <rtems.h>
6#include <errno.h>
7
8/*
9 *  This driver currently only supports architectures with the old style
10 *  exception processing.  The following checks try to keep this
11 *  from being compiled on systems which can't support this driver.
12 *
13 *  NOTE: As of 28 September 2005, this has only been tested on the SPARC,
14 *        so that is all it is enabled for.
15 */
16
17#if defined(__sparc__)
18  #define SMC91111_SUPPORTED
19#endif
20
21#if defined(SMC91111_SUPPORTED)
22
23#include <bsp.h>
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <stdarg.h>
28#include <rtems/error.h>
29#include <rtems/rtems_bsdnet.h>
30
31#include <sys/param.h>
32#include <sys/mbuf.h>
33
34#include <sys/socket.h>
35#include <sys/sockio.h>
36#include <net/if.h>
37#include <netinet/in.h>
38#include <netinet/if_ether.h>
39
40#define SMC91111_INTERRUPT_EVENT      RTEMS_EVENT_1     /* RTEMS event used by interrupt handler to signal driver tasks. This must not be any of the events used by the network task synchronization. */
41#define SMC91111_START_TRANSMIT_EVENT RTEMS_EVENT_2     /* RTEMS event used to start transmit/receive daemon. This must not be the same as INTERRUPT_EVENT. */
42#define SMC91111_TX_WAIT_EVENT        RTEMS_EVENT_3     /* event to send when tx buffers become available */
43
44/* Set to perms of:
45   0 disables all debug output
46   1 for process debug output
47   2 for added data IO output: get_reg, put_reg
48   4 for packet allocation/free output
49   8 for only startup status, so we can tell we're installed OK
50   16 dump phy read/write
51   32 precise register dump
52   64 dump packets
53*/
54/*#define DEBUG (-1)*/
55/*#define DEBUG (-1 & ~(16))*/
56#define DEBUG (0)
57
58#include "smc91111config.h"
59#include <libchip/smc91111.h>
60
61#if defined(__m68k__)
62extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
63#else
64extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
65#endif
66
67struct lan91cxx_priv_data smc91111;
68
69int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);
70static uint16_t lan91cxx_read_phy(struct lan91cxx_priv_data *cpd,
71                                    uint8_t phyaddr, uint8_t phyreg);
72static void lan91cxx_write_phy(struct lan91cxx_priv_data *cpd,
73                               uint8_t phyaddr, uint8_t phyreg,
74                               uint16_t value);
75static void lan91cxx_start(struct ifnet *ifp);
76static void smc91111_start(struct ifnet *ifp);
77static int smc_probe(struct lan91cxx_priv_data *cpd);
78static void smc91111_stop(struct lan91cxx_priv_data *cpd);
79static void smc91111_init(void *arg);
80static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd);
81#if 0
82static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd);
83static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);
84#endif
85
86#define min(l,r) ((l) < (r) ? (l) : (r))
87#define max(l,r) ((l) > (r) ? (l) : (r))
88
89/* \ ------------- Interrupt ------------- \ */
90rtems_isr lan91cxx_interrupt_handler(rtems_vector_number v)
91{
92        struct lan91cxx_priv_data *cpd = &smc91111;
93        unsigned short irq, event;
94        unsigned short oldbase;
95        unsigned short oldpointer;
96        INCR_STAT(cpd, interrupts);
97        DEBUG_FUNCTION();
98
99        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
100        oldpointer = get_reg(cpd, LAN91CXX_POINTER);
101
102        /* Get the (unmasked) requests */
103        irq = get_reg(cpd, LAN91CXX_INTERRUPT);
104        event = irq & (irq >> 8) & 0xff;
105        if (0 == event)
106                return;
107
108        /*put_reg(cpd, LAN91CXX_INTERRUPT, irq ); */ /* ack interrupts */
109
110        if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
111                db_printf("Early receive interrupt");
112        } else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
113                db_printf("ethernet protocol handler failures");
114        } else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
115                db_printf("receive overrun");
116        } else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
117                db_printf("allocation interrupt");
118        } else {
119
120                if (event & LAN91CXX_INTERRUPT_TX_SET) {
121                        db_printf("#*tx irq\n");
122                        lan91cxx_finish_sent(cpd);
123                        put_reg(cpd, LAN91CXX_INTERRUPT,
124                                (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);
125
126                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */
127                        /*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */
128                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */
129                }
130                if (event & LAN91CXX_INTERRUPT_RCV_INT) {
131                        db_printf("#*rx irq\n");
132                        rtems_event_send(cpd->rxDaemonTid,
133                                         SMC91111_INTERRUPT_EVENT);
134                }
135                if (event &
136                    ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
137                        db_printf("Unknown interrupt\n");
138        }
139        db_printf("out %s\n", __FUNCTION__);
140
141        put_reg(cpd, LAN91CXX_POINTER, oldpointer);
142        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
143}
144
145/* \ ------------- Rx receive ------------- \ */
146
147 /**/
148/* This function is called as a result of the "readpacket()" call.*/
149/* Its job is to actually fetch data for a packet from the hardware once*/
150/* memory buffers have been allocated for the packet.  Note that the buffers*/
151/* may come in pieces, using a mbuf list.  */
152static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m)
153{
154        struct ifnet *ifp = &cpd->arpcom.ac_if;
155        struct ether_header *eh;
156        short mlen = 0, plen;
157        char *start;
158        rxd_t *data = NULL, val, lp;
159        struct mbuf *n;
160        lp = 0;
161        dbg_prefix = "<";
162
163        DEBUG_FUNCTION();
164        INCR_STAT(cpd, rx_deliver);
165
166        /* ############ read packet ############ */
167
168        put_reg(cpd, LAN91CXX_POINTER,
169                (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
170                 LAN91CXX_POINTER_AUTO_INCR));
171        val = get_data(cpd);
172
173        /* packet length (minus header/footer) */
174#ifdef LAN91CXX_32BIT_RX
175        val = CYG_LE32_TO_CPU(val);
176        plen = (val >> 16) - 6;
177#else
178        val = CYG_LE16_TO_CPU(val);
179        plen = get_data(cpd);
180        plen = CYG_LE16_TO_CPU(plen) - 6;
181#endif
182
183        if ( cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, val) ) /* RevA Odd-bit BUG */
184                plen++;
185
186        for (n = m; n; n = n->m_next) {
187#ifdef LAN91CXX_32BIT_RX
188                if (mlen == 2) {
189#if DEBUG & 64
190                        db_printf("Appending to last apacket\n");
191#endif
192
193                        val = get_data(cpd);
194                        *((unsigned short *)data) = (val >> 16) & 0xffff;
195                        plen -= 2;
196                        data = (rxd_t *) n->m_data;
197                        start = (char *)data;
198                        mlen = n->m_len;
199                        if ((data) && (mlen > 1)) {
200                                *(unsigned short *)data = (val & 0xffff);
201                                data = (rxd_t *)((unsigned short *)data + 1);
202                                plen -= 2;
203                                mlen -= 2;
204                        }
205                } else {
206                        data = (rxd_t *) n->m_data;
207                        start = (char *)data;
208                        mlen = n->m_len;
209                }
210#else
211                data = (rxd_t *) n->m_data;
212                start = (char *)data;
213                mlen = n->m_len;
214#endif
215
216                db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);
217
218                if (data) {
219                        while (mlen >= sizeof(*data)) {
220#ifdef LAN91CXX_32BIT_RX
221                                val = get_data(cpd);
222                                *(unsigned short *)data = (val >> 16) & 0xffff;
223                                data = (rxd_t *)((unsigned short *)data + 1);
224                                *(unsigned short *)data = (val & 0xffff);
225                                data = (rxd_t *)((unsigned short *)data + 1);
226#else
227                                *data++ = get_data(cpd);
228#endif
229                                mlen -= sizeof(*data);
230                                plen -= sizeof(*data);
231                        }
232                } else {        /* must actively discard ie. read it from the chip anyway. */
233                        while (mlen >= sizeof(*data)) {
234                                (void)get_data(cpd);
235                                mlen -= sizeof(*data);
236                                plen -= sizeof(*data);
237                        }
238                }
239
240#if DEBUG & 64
241                lp = 0;
242                while (((int)start) < ((int)data)) {
243                        unsigned char a = *(start++);
244                        unsigned char b = *(start++);
245                        db64_printf("%02x %02x ", a, b);
246                        lp += 2;
247                        if (lp >= 16) {
248                                db64_printf("\n");
249                                lp = 0;
250                        }
251                }
252                db64_printf(" \n");
253
254#endif
255        }
256        val = get_data(cpd);    /* Read control word (and potential data) unconditionally */
257#ifdef LAN91CXX_32BIT_RX
258        if (plen & 2) {
259                if (data && (mlen>1) ) {
260                        *(unsigned short *)data = (val >> 16) & 0xffff;
261                        data = (rxd_t *)((unsigned short *)data + 1);
262                        val <<= 16;
263                        mlen-=2;
264                }
265        }
266        if ( (plen & 1) && data && (mlen>0) )
267                *(unsigned char *)data = val >> 24;
268#else
269        val = CYG_LE16_TO_CPU(val);
270        cp = (unsigned char *)data;
271
272        CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX, "Controlbyte is not for Rx");
273        CYG_ASSERT((1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)),
274                   "Controlbyte does not match");
275        if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)) {
276                cval = val & 0x00ff;    /* last byte contains data */
277                *cp = cval;
278        }
279#endif
280
281        val = get_reg(cpd, LAN91CXX_FIFO_PORTS);
282        if (0x8000 & val) {     /* Then the Rx FIFO is empty */
283                db4_printf
284                    ("<+Rx packet NOT freed, stat is %x (expected %x)\n",
285                     val, cpd->rxpacket);
286        } else {
287                db4_printf("<+Rx packet freed %x (expected %x)\n",
288                           0xff & (val >> 8), cpd->rxpacket);
289        }
290
291        CYG_ASSERT((0xff & (val >> 8)) == cpd->rxpacket,
292                   "Unexpected rx packet");
293
294        /* ############ free packet ############ */
295        /* Free packet */
296        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
297
298        dbg_prefix = "";
299
300        /* Remove the mac header. This is different from the NetBSD stack. */
301        eh = mtod(m, struct ether_header *);
302        m->m_data += sizeof(struct ether_header);
303        m->m_len -= sizeof(struct ether_header);
304        m->m_pkthdr.len -= sizeof(struct ether_header);
305
306        ether_input(ifp, eh, m);
307
308}
309
310/* allocate mbuf chain */
311static struct mbuf *smc91111_allocmbufchain(int totlen, struct ifnet *ifp)
312{
313
314        struct mbuf *m, *m0, *newm;
315        int len;
316
317        MGETHDR(m0, M_DONTWAIT, MT_DATA);
318        if (m0 == 0)
319                return (0);
320        m0->m_pkthdr.rcvif = ifp;
321        m0->m_pkthdr.len = totlen;
322        len = MHLEN;
323        m = m0;
324
325        /* This loop goes through and allocates mbufs for all the data we will be copying in.  */
326        while (totlen > 0) {
327                if (totlen >= MINCLSIZE) {
328                        MCLGET(m, M_DONTWAIT);
329                        if ((m->m_flags & M_EXT) == 0)
330                                goto bad;
331                        len = MCLBYTES;
332                }
333
334                if (m == m0) {
335                        caddr_t newdata = (caddr_t)
336                            ALIGN(m->m_data +
337                                  sizeof(struct ether_header)) -
338                            sizeof(struct ether_header);
339                        len -= newdata - m->m_data;
340                        m->m_data = newdata;
341                }
342
343                m->m_len = len = min(totlen, len);
344
345                totlen -= len;
346                if (totlen > 0) {
347                        MGET(newm, M_DONTWAIT, MT_DATA);
348                        if (newm == 0)
349                                goto bad;
350                        len = MLEN;
351                        m = m->m_next = newm;
352                }
353        }
354        return (m0);
355
356      bad:
357        m_freem(m0);
358        return (0);
359}
360
361static int readpacket(struct lan91cxx_priv_data *cpd)
362{
363        struct mbuf *m;
364        unsigned short stat, complen;
365        struct ifnet *ifp = &cpd->arpcom.ac_if;
366#ifdef LAN91CXX_32BIT_RX
367        uint32_t val;
368#endif
369
370        DEBUG_FUNCTION();
371
372        /* ############ read packet nr ############ */
373        stat = get_reg(cpd, LAN91CXX_FIFO_PORTS);
374        db1_printf("+LAN91CXX_FIFO_PORTS: 0x%04x\n", stat);
375
376        if (0x8000 & stat) {
377                /* Then the Rx FIFO is empty */
378                db4_printf("!RxEvent with empty fifo\n");
379                return 0;
380        }
381
382        INCR_STAT(cpd, rx_count);
383
384        db4_printf("+Rx packet allocated %x (previous %x)\n",
385                   0xff & (stat >> 8), cpd->rxpacket);
386
387        /* There is an Rx Packet ready */
388        cpd->rxpacket = 0xff & (stat >> 8);
389
390        /* ############ read packet header ############ */
391        /* Read status and (word) length */
392        put_reg(cpd, LAN91CXX_POINTER,
393                (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
394                 LAN91CXX_POINTER_AUTO_INCR | 0x0000));
395#ifdef LAN91CXX_32BIT_RX
396        val = get_data(cpd);
397        val = CYG_LE32_TO_CPU(val);
398        stat = val & 0xffff;
399        complen = ((val >> 16) & 0xffff) - 6;   /* minus header/footer words */
400#else
401        stat = get_data(cpd);
402        stat = CYG_LE16_TO_CPU(stat);
403        complen = get_data(cpd);
404        complen = CYG_LE16_TO_CPU(len) - 6;     /* minus header/footer words */
405#endif
406
407#ifdef KEEP_STATISTICS
408        if (stat & LAN91CXX_RX_STATUS_ALIGNERR)
409                INCR_STAT(cpd, rx_align_errors);
410        /*if ( stat & LAN91CXX_RX_STATUS_BCAST    ) INCR_STAT(  ); */
411        if (stat & LAN91CXX_RX_STATUS_BADCRC)
412                INCR_STAT(cpd, rx_crc_errors);
413        if (stat & LAN91CXX_RX_STATUS_TOOLONG)
414                INCR_STAT(cpd, rx_too_long_frames);
415        if (stat & LAN91CXX_RX_STATUS_TOOSHORT)
416                INCR_STAT(cpd, rx_short_frames);
417        /*if ( stat & LAN91CXX_RX_STATUS_MCAST    ) INCR_STAT(  ); */
418#endif                          /* KEEP_STATISTICS */
419
420        if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {
421                INCR_STAT(cpd, rx_good);
422                /* Then it's OK */
423
424                if (cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, stat)) /* RevA Odd-bit BUG */
425                        complen++;
426
427#if DEBUG & 1
428                db_printf("good rx - stat: 0x%04x, len: 0x%04x\n", stat,
429                          complen);
430#endif
431                /* Check for bogusly short packets; can happen in promisc mode: */
432                /* Asserted against and checked by upper layer driver. */
433                if (complen > sizeof(struct ether_header)) {
434                        /* then it is acceptable; offer the data to the network stack */
435
436                        complen = ((complen + 3) & ~3);
437
438                        m = smc91111_allocmbufchain(complen, ifp);
439                        {
440                                struct mbuf *n = m;
441                                db_printf("mbuf-chain:");
442                                while (n) {
443                                        db_printf("[%x:%x]",
444                                                  (unsigned int)(n-> m_data),
445                                                  (unsigned int)(n->m_len));
446                                        n = n->m_next;
447                                }
448                                db_printf("\n");
449                        }
450
451                        if (m) {
452                                /* fetch packet data into mbuf chain */
453                                lan91cxx_recv(cpd, m);
454                                return 1;
455                        }
456                }
457                /*(sc->funs->eth_drv->recv)(sc, len); */
458        }
459
460        /* Not OK for one reason or another... */
461        db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);
462
463        /* ############ free packet ############ */
464        /* Free packet */
465        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
466        return 1;
467
468}
469
470static void smc91111_rxDaemon(void *arg)
471{
472        struct lan91cxx_priv_data *cpd = arg;
473        rtems_event_set events;
474        DEBUG_FUNCTION();
475
476        for (;;) {
477                rtems_bsdnet_event_receive(INTERRUPT_EVENT,
478                                           RTEMS_WAIT | RTEMS_EVENT_ANY,
479                                           RTEMS_NO_TIMEOUT, &events);
480
481                /* read until read fifo is empty */
482                while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {
483                        readpacket(cpd);
484                }
485        }
486}
487
488/* \ ------------- Tx send ------------- \ */
489
490static void sendpacket(struct ifnet *ifp, struct mbuf *m)
491{
492        struct lan91cxx_priv_data *cpd = ifp->if_softc;
493        int i, len, plen, tcr, odd;
494        struct mbuf *n = m;
495        unsigned short *sdata = NULL;
496        unsigned short ints, control;
497        uint16_t packet, status;
498        dbg_prefix = ">";
499        DEBUG_FUNCTION();
500
501        cpd->txbusy = 1;
502
503        /* Worry about the TX engine stopping. */
504        tcr = get_reg(cpd, LAN91CXX_TCR);
505        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
506                db1_printf("> ENGINE RESTART: tcr %x\n", tcr);
507                tcr |= LAN91CXX_TCR_TXENA;
508                put_reg(cpd, LAN91CXX_TCR, tcr);
509        }
510
511        /* ############ packet allocation ############ */
512
513        /* Find packet length */
514        plen = 0;
515        while (n) {
516                plen += n->m_len;
517                n = n->m_next;
518        }
519
520        /* Alloc new TX packet */
521        do {
522                put_reg(cpd, LAN91CXX_MMU_COMMAND,
523                        LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));
524
525                i = 1024 * 1024;
526                do {
527                        status = get_reg(cpd, LAN91CXX_INTERRUPT);
528                } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)
529                         && (--i > 0));
530                if (i)
531                        packet = get_reg(cpd, LAN91CXX_PNR);
532                else
533                        packet = 0xffff;
534                db1_printf(">+allocated packet %04x\n", packet);
535
536                packet = packet >> 8;
537                if (packet & 0x80) {
538                        /* Hm.. Isn't this a dead end? */
539                        db1_printf("Allocation failed! Retrying...\n");
540                        continue;
541                }
542        } while (0);
543
544        db4_printf(">+Tx packet allocated %x (previous %x)\n",
545                   packet, cpd->txpacket);
546
547        cpd->txpacket = packet;
548
549        /* ############ assemble packet data ############ */
550
551        /* prepare send */
552        put_reg(cpd, LAN91CXX_PNR, packet);
553        /* Note: Check FIFO state here before continuing? */
554        put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);
555        /* Pointer is now set, and the proper bank is selected for */
556        /* data writes. */
557
558        /* Prepare header: */
559        put_data(cpd, CYG_CPU_TO_LE16(0));      /* reserve space for status word */
560        /* packet length (includes status, byte-count and control shorts) */
561        put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6)));     /* Always even, always < 15xx(dec) */
562
563        /* Put data into buffer */
564        odd = 0;
565        n = m;
566        while (n) {
567                sdata = (unsigned short *)n->m_data;
568                len = n->m_len;
569
570                CYG_ASSERT(sdata, "!No sg data pointer here");
571
572                /* start on an odd offset?
573                 * If last byte also (1byte mbuf with different pointer should not occur)
574                 * let following code handle it
575                 */
576                if ( ((unsigned int)sdata & 1) && (len>1) ){
577                        put_data8(cpd,*(unsigned char *)sdata);
578                        sdata = (unsigned short *)((unsigned int)sdata + 1);
579                        odd = ~odd;
580                        len--;
581                }
582               
583                /* speed up copying a bit, never copy last word */
584                while(len >= 17){
585                        put_data(cpd, *(sdata));
586                        put_data(cpd, *(sdata+1));
587                        put_data(cpd, *(sdata+2));
588                        put_data(cpd, *(sdata+3));
589                        put_data(cpd, *(sdata+4));
590                        put_data(cpd, *(sdata+5));
591                        put_data(cpd, *(sdata+6));
592                        put_data(cpd, *(sdata+7));
593                        sdata += 8;
594                        len -= 16;
595                }
596               
597                /* copy word wise, skip last word */
598                while (len >= 3) {
599                        put_data(cpd, *sdata++);
600                        len -= sizeof(*sdata);
601                }
602               
603                /* one or two bytes left to put into fifo */
604                if ( len > 1 ){
605                        /* the last 2bytes */
606                        if ( !odd || n->m_next ){
607                                put_data(cpd, *sdata++);
608                                len -= sizeof(*sdata);
609                        }else{
610                                /* write next byte, mark that we are not at an odd offset any more,
611                                 * remaining byte will be written outside while together with control byte.
612                                 */
613                                put_data8(cpd,*(unsigned char *)sdata);
614                                sdata = (unsigned short *)((unsigned int)sdata + 1);
615                                odd = 0;
616                                len--;
617                                /*break;*/
618                        }
619                }else if ( (len>0) && (n->m_next) ){
620                        /* one byte left to write, and more bytes is comming in next mbuf */
621                        put_data8(cpd,*(unsigned char *)sdata);
622                        odd = ~odd;
623                }
624
625                n = n->m_next;
626        }
627
628        /* Lay down the control short unconditionally at the end. */
629        /* (or it might use random memory contents) */
630        control = 0;
631        if ( len > 0 ){
632                if ( !odd ) {
633                        /* Need to set ODD flag and insert the data */
634                        unsigned char onebyte = *(unsigned char *)sdata;
635                        control = onebyte;
636                        control |= LAN91CXX_CONTROLBYTE_ODD;
637                }else{
638                        put_data8(cpd,*(unsigned char *)sdata);
639                }
640        }
641        control |= LAN91CXX_CONTROLBYTE_CRC;    /* Just in case... */
642        put_data(cpd, CYG_CPU_TO_LE16(control));
643
644        m_freem(m);
645        CYG_ASSERT(sdata, "!No sg data pointer outside");
646
647        /* ############ start transmit ############ */
648
649        /* Ack TX empty int and unmask it. */
650        ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
651        put_reg(cpd, LAN91CXX_INTERRUPT,
652                ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
653        put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M);   /* notify on error only (Autorelease) */
654
655        /* Enqueue the packet */
656        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
657
658        ints = get_reg(cpd, LAN91CXX_INTERRUPT);
659        db1_printf(">END: ints at TX: %04x\n", ints);
660        dbg_prefix = "";
661}
662
663void smc91111_txDaemon(void *arg)
664{
665        struct lan91cxx_priv_data *cpd = arg;
666        struct ifnet *ifp = &cpd->arpcom.ac_if;
667        struct mbuf *m;
668        rtems_event_set events;
669        DEBUG_FUNCTION();
670
671        for (;;) {
672                /*
673                 * Wait for packet
674                 */
675
676                rtems_bsdnet_event_receive
677                    (SMC91111_START_TRANSMIT_EVENT,
678                     RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
679
680                /*IF_DEQUEUE (&ifp->if_snd, m);
681                   if (m) {
682                   sendpacket (ifp, m);
683                   } */
684
685                for (;;) {
686                        IF_DEQUEUE(&ifp->if_snd, m);
687                        if (!m)
688                                break;
689                        sendpacket(ifp, m);
690                }
691                ifp->if_flags &= ~IFF_OACTIVE;
692
693        }
694
695}
696
697/* start transmit */
698static void smc91111_start(struct ifnet *ifp)
699{
700        struct lan91cxx_priv_data *cpd = ifp->if_softc;
701
702        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
703                return;
704
705        rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
706        ifp->if_flags |= IFF_OACTIVE;
707
708}
709
710/* called after a tx error interrupt, freet the packet */
711static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
712{
713        unsigned short packet, tcr;
714        int success = 1;
715        int saved_packet;
716
717        DEBUG_FUNCTION();
718
719        INCR_STAT(cpd, tx_complete);
720
721        saved_packet = get_reg(cpd, LAN91CXX_PNR);
722
723        /* Ack and mask TX interrupt set */
724        /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
725           ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
726           ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
727           put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
728
729        /* Get number of completed packet and read the status word */
730        packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
731        db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
732
733        {
734                unsigned short reg;
735
736                reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
737
738                /* Covering each bit in turn... */
739                if (reg & LAN91CXX_STATUS_TX_UNRN)
740                        INCR_STAT(cpd, tx_underrun);
741                if (reg & LAN91CXX_STATUS_LOST_CARR)
742                        INCR_STAT(cpd, tx_carrier_loss);
743                if (reg & LAN91CXX_STATUS_LATCOL)
744                        INCR_STAT(cpd, tx_late_collisions);
745                if (reg & LAN91CXX_STATUS_TX_DEFR)
746                        INCR_STAT(cpd, tx_deferred);
747                if (reg & LAN91CXX_STATUS_SQET)
748                        INCR_STAT(cpd, tx_sqetesterrors);
749                if (reg & LAN91CXX_STATUS_16COL)
750                        INCR_STAT(cpd, tx_max_collisions);
751                if (reg & LAN91CXX_STATUS_MUL_COL)
752                        INCR_STAT(cpd, tx_mult_collisions);
753                if (reg & LAN91CXX_STATUS_SNGL_COL)
754                        INCR_STAT(cpd, tx_single_collisions);
755                if (reg & LAN91CXX_STATUS_TX_SUC)
756                        INCR_STAT(cpd, tx_good);
757
758                cpd->stats.tx_total_collisions =
759                    cpd->stats.tx_late_collisions +
760                    cpd->stats.tx_max_collisions +
761                    cpd->stats.tx_mult_collisions +
762                    cpd->stats.tx_single_collisions;
763
764                /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
765                   because it just mimics the info we already have above. */
766        }
767
768        /* We do not really care about Tx failure.  Ethernet is not a reliable
769           medium.  But we do care about the TX engine stopping. */
770        tcr = get_reg(cpd, LAN91CXX_TCR);
771        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
772                db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
773                tcr |= LAN91CXX_TCR_TXENA;
774                put_reg(cpd, LAN91CXX_TCR, tcr);
775                success = 0;    /* And treat this as an error... */
776        }
777
778        packet &= 0xff;
779
780        /* and then free the packet */
781        put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
782        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
783
784        while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
785        /* Don't change Packet Number Reg until busy bit is cleared */
786        /* Per LAN91C111 Spec, Page 50 */
787        put_reg(cpd, LAN91CXX_PNR, saved_packet);
788
789}
790
791/* \ ------------- Helpers ------------- \ */
792
793/*
794 * Show interface statistics
795 */
796static void smc91111_stats(struct lan91cxx_priv_data *priv)
797{
798        printf("tx_good             :%-8d", priv->stats.tx_good);
799        printf("tx_max_collisions   :%-8d", priv->stats.tx_max_collisions);
800        printf("tx_late_collisions  :%-8d", priv->stats.tx_late_collisions);
801        printf("tx_underrun         :%-8d", priv->stats.tx_underrun);
802        printf("tx_carrier_loss     :%-8d", priv->stats.tx_carrier_loss);
803        printf("tx_deferred         :%-8d", priv->stats.tx_deferred);
804        printf("tx_sqetesterrors    :%-8d", priv->stats.tx_sqetesterrors);
805        printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions);
806        printf("tx_mult_collisions  :%-8d", priv->stats.tx_mult_collisions);
807        printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions);
808        printf("rx_good             :%-8d", priv->stats.rx_good);
809        printf("rx_crc_errors       :%-8d", priv->stats.rx_crc_errors);
810        printf("rx_align_errors     :%-8d", priv->stats.rx_align_errors);
811        printf("rx_resource_errors  :%-8d", priv->stats.rx_resource_errors);
812        printf("rx_overrun_errors   :%-8d", priv->stats.rx_overrun_errors);
813        printf("rx_collisions       :%-8d", priv->stats.rx_collisions);
814        printf("rx_short_frames     :%-8d", priv->stats.rx_short_frames);
815        printf("rx_too_long_frames  :%-8d", priv->stats.rx_too_long_frames);
816        printf("rx_symbol_errors    :%-8d", priv->stats.rx_symbol_errors);
817        printf("interrupts          :%-8d", priv->stats.interrupts);
818        printf("rx_count            :%-8d", priv->stats.rx_count);
819        printf("rx_deliver          :%-8d", priv->stats.rx_deliver);
820        printf("rx_resource         :%-8d", priv->stats.rx_resource);
821        printf("rx_restart          :%-8d", priv->stats.rx_restart);
822        printf("tx_count            :%-8d", priv->stats.tx_count);
823        printf("tx_complete         :%-8d", priv->stats.tx_complete);
824        printf("tx_dropped          :%-8d", priv->stats.tx_dropped);
825}
826
827/*
828 * Driver ioctl handler
829 */
830static int smc91111_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
831{
832        struct lan91cxx_priv_data *cpd = ifp->if_softc;
833        int error = 0;
834        DEBUG_FUNCTION();
835
836        switch (command) {
837        case SIOCGIFADDR:
838        case SIOCSIFADDR:
839                db_printf("SIOCSIFADDR\n");
840                ether_ioctl(ifp, command, data);
841                break;
842
843        case SIOCSIFFLAGS:
844                db_printf("SIOCSIFFLAGS\n");
845                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
846                case IFF_RUNNING:
847                        smc91111_stop(cpd);
848                        break;
849
850                case IFF_UP:
851                        smc91111_init(cpd);
852                        break;
853
854                case IFF_UP | IFF_RUNNING:
855                        smc91111_stop(cpd);
856                        smc91111_init(cpd);
857                        break;
858
859                default:
860                        break;
861                }
862                break;
863
864        case SIO_RTEMS_SHOW_STATS:
865                db_printf("SIO_RTEMS_SHOW_STATS\n");
866                smc91111_stats(cpd);
867                break;
868
869                /*
870                 * FIXME: All sorts of multicast commands need to be added here!
871                 */
872        default:
873                error = EINVAL;
874                break;
875        }
876
877        return error;
878}
879
880/*
881 * Attach an SMC91111 driver to the system
882 */
883int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
884                                  struct scmv91111_configuration * chip)
885{
886        struct ifnet *ifp;
887        struct lan91cxx_priv_data *cpd;
888        int unitNumber;
889        char *unitName;
890        int mtu;
891        DEBUG_FUNCTION();
892
893#if 0
894        /* activate io area */
895        switch (sparc_leon23_get_psr_version()) {
896        case 0:
897        case 2:
898                db_printf("Activating Leon2 io port\n");
899                /*configure pio */
900                *((volatile unsigned int *)0x80000000) |= 0x10f80000;
901                *((volatile unsigned int *)0x800000A8) |=
902                    (0xe0 | chip->vector) << (8 * (chip->pio - 4));
903                break;
904        default:
905                {
906                        unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl;
907                        if ((addr_pio = amba_find_apbslv_addr(VENDOR_GAISLER,
908                                                   GAISLER_PIOPORT, &irq_pio))
909                            && (addr_mctrl =
910                                amba_find_apbslv_addr(VENDOR_ESA, ESA_MCTRL, &irq_mctrl))) {
911                                LEON3_IOPORT_Regs_Map *io =
912                                    (LEON3_IOPORT_Regs_Map *) addr_pio;
913                                db_printf
914                                    ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n",
915                                     (unsigned int)addr_pio,
916                                     (unsigned int)addr_mctrl);
917                                *((volatile unsigned int *)addr_mctrl) |= 0x10f80000;   /*mctrl ctrl 1 */
918                                io->irqmask |= (1 << chip->pio);
919                                io->irqpol |= (1 << chip->pio);
920                                io->irqedge |= (1 << chip->pio);
921                                io->iodir &= ~(1 << chip->pio);
922                        } else {
923                                return 0;
924                        }
925                }
926        }
927#endif
928
929        /* parse driver name */
930        if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
931                db_printf("Unitnumber < 0: %d\n", unitNumber);
932                return 0;
933        }
934
935        db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
936
937        cpd = &smc91111;
938        ifp = &cpd->arpcom.ac_if;
939        memset(cpd, 0, sizeof(*cpd));
940
941        cpd->config = *chip;
942        cpd->base = chip->baseaddr;
943
944        if (smc_probe(cpd)) {
945                return 0;
946        }
947
948        if (config->hardware_address) {
949                memcpy(cpd->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
950        } else {
951                /* dummy default address */
952                cpd->arpcom.ac_enaddr[0] = 0x12;
953                cpd->arpcom.ac_enaddr[1] = 0x13;
954                cpd->arpcom.ac_enaddr[2] = 0x14;
955                cpd->arpcom.ac_enaddr[3] = 0x15;
956                cpd->arpcom.ac_enaddr[4] = 0x16;
957                cpd->arpcom.ac_enaddr[5] = 0x17;
958        }
959
960        cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
961        cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
962        cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
963        cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
964        cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
965        cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
966        cpd->rpc_cur_mode =
967            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
968            LAN91CXX_RPCR_ANEG;
969
970        if (config->mtu)
971                mtu = config->mtu;
972        else
973                mtu = ETHERMTU;
974
975        /*
976         * Set up network interface values
977         */
978        ifp->if_softc = cpd;
979        ifp->if_unit = unitNumber;
980        ifp->if_name = unitName;
981        ifp->if_mtu = mtu;
982        ifp->if_init = smc91111_init;
983        ifp->if_ioctl = smc91111_ioctl;
984        ifp->if_start = smc91111_start;
985        ifp->if_output = ether_output;
986        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
987        if (ifp->if_snd.ifq_maxlen == 0)
988                ifp->if_snd.ifq_maxlen = ifqmaxlen;
989
990        /*
991         * Attach the interface
992         */
993        if_attach(ifp);
994        ether_ifattach(ifp);
995
996#ifdef DEBUG
997        printf("SMC91111 : driver has been attached\n");
998#endif
999
1000        return 1;
1001};
1002
1003/* \ ------------- Initialization ------------- \ */
1004
1005/*
1006 * Initialize and start the device
1007 */
1008static void smc91111_init(void *arg)
1009{
1010        struct lan91cxx_priv_data *cpd = arg;
1011        struct ifnet *ifp = &cpd->arpcom.ac_if;
1012        DEBUG_FUNCTION();
1013
1014        if (cpd->txDaemonTid == 0) {
1015
1016                lan91cxx_hardware_init(cpd);
1017                lan91cxx_start(ifp);
1018
1019                cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
1020                                                        smc91111_rxDaemon, cpd);
1021                cpd->txDaemonTid =
1022                    rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
1023        }
1024
1025        /*
1026         * Tell the world that we're running.
1027         */
1028        ifp->if_flags |= IFF_RUNNING;
1029}
1030
1031/*
1032 * Stop the device
1033 */
1034static void smc91111_stop(struct lan91cxx_priv_data *cpd)
1035{
1036        struct ifnet *ifp = &cpd->arpcom.ac_if;
1037        DEBUG_FUNCTION();
1038
1039        ifp->if_flags &= ~IFF_RUNNING;
1040
1041        /* Reset chip */
1042        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1043        put_reg(cpd, LAN91CXX_RCR, 0);
1044        cpd->txbusy = cpd->within_send = 0;
1045
1046}
1047
1048int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
1049{
1050        unsigned short val;
1051        int i;
1052
1053        DEBUG_FUNCTION();
1054
1055        cpd->txbusy = cpd->within_send = 0;
1056
1057        /* install interrupt vector */
1058        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1059        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1060
1061        /* Reset chip */
1062        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1063        put_reg(cpd, LAN91CXX_RCR, 0);
1064        HAL_DELAY_US(100000);
1065        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1066        put_reg(cpd, LAN91CXX_RCR, 0);
1067        put_reg(cpd, LAN91CXX_TCR, 0);
1068        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1069
1070        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1071        /* probe chip by reading the signature in BS register */
1072        val = get_banksel(cpd);
1073        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1074                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1075
1076        if ((0xff00 & val) != 0x3300) {
1077                printf("No 91Cxx signature");
1078                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1079                return 0;
1080        }
1081
1082        val = get_reg(cpd, LAN91CXX_REVISION);
1083
1084        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1085                   (val >> 4) & 0xf, val & 0xf);
1086
1087        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1088        cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */
1089
1090        /* The controller may provide a function used to set up the ESA */
1091        if (cpd->config_enaddr)
1092                (*cpd->config_enaddr) (cpd);
1093
1094        db9_printf("LAN91CXX - status: %04x\n", val);
1095        /* Use statically configured ESA from the private data */
1096        db9_printf
1097            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1098             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1099             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1100        /* Set up hardware address */
1101        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1102                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1103                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1104
1105        return 1;
1106}
1107
1108/*
1109  This function is called to "start up" the interface.  It may be called
1110  multiple times, even when the hardware is already running.  It will be
1111  called whenever something "hardware oriented" changes and should leave
1112  the hardware ready to send/receive packets.
1113*/
1114static void lan91cxx_start(struct ifnet *ifp)
1115{
1116        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1117
1118        uint16_t intr;
1119        uint16_t phy_ctl;
1120        int delay;
1121        DEBUG_FUNCTION();
1122
1123        HAL_DELAY_US(100000);
1124
1125        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1126        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1127        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1128        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1129
1130        /* Start auto-negotiation */
1131        put_reg(cpd, LAN91CXX_RPCR,
1132                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1133                LAN91CXX_RPCR_ANEG);
1134        cpd->rpc_cur_mode =
1135            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1136            LAN91CXX_RPCR_ANEG;
1137
1138        /* wait for auto-negotiation to finish. */
1139        /* give it ~5 seconds before giving up (no cable?) */
1140        delay = 50;
1141        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1142                if (--delay <= 0) {
1143                        printf("Timeout autonegotiation\n");
1144                        break;
1145                }
1146                HAL_DELAY_US(100000);
1147        }
1148
1149        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1150
1151        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1152        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1153        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1154                (LAN91CXX_INTERRUPT_TX_INT |
1155                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1156                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1157        put_reg(cpd, LAN91CXX_RCR,
1158                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1159                LAN91CXX_RCR_ALMUL);
1160        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1161        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1162        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1163                LAN91CXX_INTERRUPT_RCV_INT_M);
1164
1165        if ((0
1166#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1167             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1168#endif
1169            ) || (ifp->if_flags & IFF_PROMISC)
1170            ) {
1171                /* Then we select promiscuous mode. */
1172                unsigned short rcr;
1173                rcr = get_reg(cpd, LAN91CXX_RCR);
1174                rcr |= LAN91CXX_RCR_PRMS;
1175                put_reg(cpd, LAN91CXX_RCR, rcr);
1176        }
1177}
1178
1179/* \ ------------- Probe ------------- \ */
1180
1181static const char *chip_ids[15] = {
1182        NULL, NULL, NULL,
1183        /* 3 */ "SMC91C90/91C92",
1184        /* 4 */ "SMC91C94",
1185        /* 5 */ "SMC91C95",
1186        /* 6 */ "SMC91C96",
1187        /* 7 */ "SMC91C100",
1188        /* 8 */ "SMC91C100FD",
1189        /* 9 */ "SMC91C11xFD",
1190        NULL, NULL,
1191        NULL, NULL, NULL
1192};
1193
1194static int smc_probe(struct lan91cxx_priv_data *cpd)
1195{
1196        unsigned short bank;
1197        unsigned short revision_register;
1198
1199        DEBUG_FUNCTION();
1200
1201        /* First, see if the high byte is 0x33 */
1202        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1203        bank = CYG_LE16_TO_CPU(bank);
1204        if ((bank & 0xFF00) != 0x3300) {
1205                db_printf("<1>Smc probe bank check 1 failed.\n");
1206                return -ENODEV;
1207        }
1208        /* The above MIGHT indicate a device, but I need to write to further
1209           test this.  */
1210        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1211        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1212        bank = CYG_LE16_TO_CPU(bank);
1213        if ((bank & 0xFF00) != 0x3300) {
1214                db_printf("<1>Smc probe bank check 2 failed.\n");
1215                return -ENODEV;
1216        }
1217#if SMC_DEBUG > 3
1218        {
1219                unsigned short bank16, bank16_0, bank16_1;
1220                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1221                bank = CYG_LE16_TO_CPU(bank);
1222                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1223                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1224
1225                db_printf
1226                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1227                db_printf
1228                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1229                     bank16_0);
1230                db_printf
1231                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1232                     bank16_1);
1233        }
1234#endif
1235
1236        /*  check if the revision register is something that I recognize.
1237           These might need to be added to later, as future revisions
1238           could be added.  */
1239        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1240        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1241                /* I don't recognize this chip, so... */
1242                db_printf
1243                    ("smc_probe: IO %x: Unrecognized revision register:"
1244                     " %x, Contact author. \n", (unsigned int)cpd->base,
1245                     revision_register);
1246
1247                return -ENODEV;
1248        }
1249        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1250                  revision_register,
1251                  chip_ids[(revision_register >> 4) & 0xF],
1252                  revision_register & 0xf);
1253
1254        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1255        if (revision_register == 0x3390) {
1256                db_printf("!Revision A\n");
1257        }
1258
1259        return 0;
1260}
1261
1262#if 0
1263/* \ ------------- PHY read/write ------------- \ */
1264/*Sets the PHY to a configuration as determined by the user*/
1265static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1266{
1267        int my_fixed_caps;
1268        int cfg1;
1269
1270        DEBUG_FUNCTION();
1271        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1272                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1273
1274        /* Enter Link Disable state */
1275        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1276        cfg1 |= PHY_CFG1_LNKDIS;
1277        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1278
1279        /* Set our fixed capabilities, Disable auto-negotiation */
1280        my_fixed_caps = 0;
1281
1282        if (cpd->config.ctl_rfduplx)
1283                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1284
1285        if (cpd->config.ctl_rspeed == 100)
1286                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1287
1288        /* Write capabilities to the phy control register */
1289        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1290
1291        /* Re-Configure the Receive/Phy Control register */
1292        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1293
1294        return (1);
1295}
1296#endif
1297
1298#if 0
1299/*Configures the specified PHY using Autonegotiation. */
1300static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1301{
1302
1303        unsigned int phyaddr;
1304        unsigned int my_phy_caps;       /* My PHY capabilities */
1305        unsigned int my_ad_caps;        /* My Advertised capabilities */
1306        unsigned int status = 0;
1307        int failed = 0, delay;
1308
1309        DEBUG_FUNCTION();
1310
1311        /* Set the blocking flag */
1312        cpd->autoneg_active = 1;
1313
1314        /* Get the detected phy address */
1315        phyaddr = cpd->phyaddr;
1316
1317        /* Reset the PHY, setting all other bits to zero */
1318        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1319
1320        /* Wait for the reset to complete, or time out */
1321        delay = 50;
1322        while (delay--) {
1323                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1324                      & PHY_CNTL_RST)) {
1325                        break;
1326                }
1327                HAL_DELAY_US(100000);
1328        }
1329
1330        if (delay < 1) {
1331                db_printf("smc91111:!PHY reset timed out\n");
1332                goto smc_phy_configure_exit;
1333        }
1334
1335        /* Read PHY Register 18, Status Output */
1336        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1337
1338        /* Enable PHY Interrupts (for register 18) */
1339        /* Interrupts listed here are disabled */
1340        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1341                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1342                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1343                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1344
1345        /* Configure the Receive/Phy Control register */
1346        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1347
1348        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1349        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1350        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1351
1352        if (my_phy_caps & PHY_STAT_CAP_T4)
1353                my_ad_caps |= PHY_AD_T4;
1354
1355        if (my_phy_caps & PHY_STAT_CAP_TXF)
1356                my_ad_caps |= PHY_AD_TX_FDX;
1357
1358        if (my_phy_caps & PHY_STAT_CAP_TXH)
1359                my_ad_caps |= PHY_AD_TX_HDX;
1360
1361        if (my_phy_caps & PHY_STAT_CAP_TF)
1362                my_ad_caps |= PHY_AD_10_FDX;
1363
1364        if (my_phy_caps & PHY_STAT_CAP_TH)
1365                my_ad_caps |= PHY_AD_10_HDX;
1366
1367        /* Disable capabilities not selected by our user */
1368        if (cpd->config.ctl_rspeed != 100) {
1369                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1370        }
1371
1372        if (!cpd->config.ctl_rfduplx) {
1373                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1374        }
1375
1376        /* Update our Auto-Neg Advertisement Register */
1377        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1378
1379        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1380        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1381
1382        /* If the user requested no auto neg, then go set his request */
1383        if (!(cpd->config.ctl_autoneg)) {
1384                lan91cxx_phy_fixed(cpd);
1385
1386                goto smc_phy_configure_exit;
1387        }
1388
1389        /* Restart auto-negotiation process in order to advertise my caps */
1390        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1391                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1392
1393        /* wait for auto-negotiation to finish. */
1394        /* give it ~5 seconds before giving up (no cable?) */
1395        delay = 50;
1396        while (!
1397               ((status =
1398                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1399                if (--delay <= 0) {
1400                        printf("Timeout autonegotiation\n");
1401                        failed = 1;
1402                        break;
1403                }
1404
1405                /* Restart auto-negotiation if remote fault */
1406                if (status & PHY_STAT_REM_FLT) {
1407                        db_printf("smc91111:PHY remote fault detected\n");
1408
1409                        /* Restart auto-negotiation */
1410                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1411                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1412                                           PHY_CNTL_ANEG_EN |
1413                                           PHY_CNTL_ANEG_RST |
1414                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1415                }
1416                HAL_DELAY_US(100000);
1417        }
1418
1419        /* Fail if we detected an auto-negotiate remote fault */
1420        if (status & PHY_STAT_REM_FLT) {
1421                db_printf("smc91111:PHY remote fault detected\n");
1422                failed = 1;
1423        }
1424
1425        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1426
1427        /* Set our sysctl parameters to match auto-negotiation results */
1428        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1429                db_printf("smc91111:PHY 100BaseT\n");
1430                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1431        } else {
1432                db_printf("smc91111:PHY 10BaseT\n");
1433                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1434        }
1435
1436        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1437                db_printf("smc91111:PHY Full Duplex\n");
1438                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1439        } else {
1440                db_printf("smc91111:PHY Half Duplex\n");
1441                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1442        }
1443
1444        /* Re-Configure the Receive/Phy Control register */
1445        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1446
1447      smc_phy_configure_exit:
1448
1449        /* Exit auto-negotiation */
1450        cpd->autoneg_active = 0;
1451}
1452#endif
1453
1454static uint16_t
1455lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1456                  uint8_t phyreg)
1457{
1458        int i, mask, input_idx, clk_idx = 0;
1459        uint16_t mii_reg, value;
1460        uint8_t bits[64];
1461
1462        /* 32 consecutive ones on MDO to establish sync */
1463        for (i = 0; i < 32; ++i)
1464                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1465
1466        /* Start code <01> */
1467        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1468        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1469
1470        /* Read command <10> */
1471        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1472        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1473
1474        /* Output the PHY address, msb first */
1475        for (mask = 0x10; mask; mask >>= 1) {
1476                if (phyaddr & mask)
1477                        bits[clk_idx++] =
1478                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1479                else
1480                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1481        }
1482
1483        /* Output the phy register number, msb first */
1484        for (mask = 0x10; mask; mask >>= 1) {
1485                if (phyreg & mask)
1486                        bits[clk_idx++] =
1487                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1488                else
1489                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1490        }
1491
1492        /* Tristate and turnaround (1 bit times) */
1493        bits[clk_idx++] = 0;
1494
1495        /* Input starts at this bit time */
1496        input_idx = clk_idx;
1497
1498        /* Will input 16 bits */
1499        for (i = 0; i < 16; ++i)
1500                bits[clk_idx++] = 0;
1501
1502        /* Final clock bit */
1503        bits[clk_idx++] = 0;
1504
1505        /* Get the current MII register value */
1506        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1507
1508        /* Turn off all MII Interface bits */
1509        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1510                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1511        HAL_DELAY_US(50);
1512
1513        /* Clock all 64 cycles */
1514        for (i = 0; i < sizeof(bits); ++i) {
1515                /* Clock Low - output data */
1516                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1517                HAL_DELAY_US(50);
1518
1519                /* Clock Hi - input data */
1520                put_reg(cpd, LAN91CXX_MGMT,
1521                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1522                HAL_DELAY_US(50);
1523
1524                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1525        }
1526
1527        /* Return to idle state */
1528        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1529        HAL_DELAY_US(50);
1530
1531        /* Recover input data */
1532        for (value = 0, i = 0; i < 16; ++i) {
1533                value <<= 1;
1534                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1535                        value |= 1;
1536        }
1537
1538        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1539        return value;
1540}
1541
1542static void
1543lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1544                   uint8_t phyreg, uint16_t value)
1545{
1546        int i, mask, clk_idx = 0;
1547        uint16_t mii_reg;
1548        uint8_t bits[65];
1549
1550        /* 32 consecutive ones on MDO to establish sync */
1551        for (i = 0; i < 32; ++i)
1552                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1553
1554        /* Start code <01> */
1555        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1556        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1557
1558        /* Write command <01> */
1559        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1560        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1561
1562        /* Output the PHY address, msb first */
1563        for (mask = 0x10; mask; mask >>= 1) {
1564                if (phyaddr & mask)
1565                        bits[clk_idx++] =
1566                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1567                else
1568                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1569        }
1570
1571        /* Output the phy register number, msb first */
1572        for (mask = 0x10; mask; mask >>= 1) {
1573                if (phyreg & mask)
1574                        bits[clk_idx++] =
1575                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1576                else
1577                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1578        }
1579
1580        /* Tristate and turnaround (2 bit times) */
1581        bits[clk_idx++] = 0;
1582        bits[clk_idx++] = 0;
1583
1584        /* Write out 16 bits of data, msb first */
1585        for (mask = 0x8000; mask; mask >>= 1) {
1586                if (value & mask)
1587                        bits[clk_idx++] =
1588                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1589                else
1590                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1591        }
1592
1593        /* Final clock bit (tristate) */
1594        bits[clk_idx++] = 0;
1595
1596        /* Get the current MII register value */
1597        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1598
1599        /* Turn off all MII Interface bits */
1600        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1601                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1602        HAL_DELAY_US(50);
1603
1604        /* Clock all cycles */
1605        for (i = 0; i < sizeof(bits); ++i) {
1606                /* Clock Low - output data */
1607                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1608                HAL_DELAY_US(50);
1609
1610                /* Clock Hi - input data */
1611                put_reg(cpd, LAN91CXX_MGMT,
1612                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1613                HAL_DELAY_US(50);
1614
1615/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1616        }
1617
1618        /* Return to idle state */
1619        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1620        HAL_DELAY_US(50);
1621
1622        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1623}
1624
1625#endif
1626
1627#if 0
1628void lan91cxx_print_bank(int bank){
1629        struct lan91cxx_priv_data *cpd = &smc91111;
1630        int regno;
1631        unsigned short regval[8];
1632        int i;
1633
1634        if ( bank >= 4 )
1635                return;
1636        for(i=0; i<8; i++){
1637                regno=i+bank<<3;
1638                regval[i] = get_reg(cpd, regno);
1639        }
1640        printk("---- BANK %d ----\n\r",bank);   
1641        for(i=0; i<8; i++){
1642                printk("0x%x: 0x%x\n\r",i,regval[i]);
1643        }
1644
1645}
1646#endif
Note: See TracBrowser for help on using the repository browser.