source: rtems/c/src/libchip/network/smc91111.c @ 324e311

4.104.114.84.9
Last change on this file since 324e311 was 324e311, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 13, 2007 at 7:29:13 PM

2007-09-13 Daniel Hellstrom <daniel@…>

  • libchip/network/smc91111.c: Eliminate a stray DEBUG_puts().
  • Property mode set to 100644
File size: 43.7 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->
445                                                                 m_data),
446                                                  (unsigned int)(n->m_len));
447                                        n = n->m_next;
448                                }
449                                db_printf("\n");
450                        }
451
452                        if (m) {
453                                /* fetch packet data into mbuf chain */
454                                lan91cxx_recv(cpd, m);
455                                return 1;
456                        }
457                }
458                /*(sc->funs->eth_drv->recv)(sc, len); */
459        }
460
461        /* Not OK for one reason or another... */
462        db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);
463
464        /* ############ free packet ############ */
465        /* Free packet */
466        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
467        return 1;
468
469}
470
471static void smc91111_rxDaemon(void *arg)
472{
473        struct lan91cxx_priv_data *cpd = arg;
474        rtems_event_set events;
475        DEBUG_FUNCTION();
476
477        for (;;) {
478                rtems_bsdnet_event_receive(INTERRUPT_EVENT,
479                                           RTEMS_WAIT | RTEMS_EVENT_ANY,
480                                           RTEMS_NO_TIMEOUT, &events);
481
482                /* read until read fifo is empty */
483                while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {
484                        readpacket(cpd);
485                }
486        }
487}
488
489/* \ ------------- Tx send ------------- \ */
490
491static void sendpacket(struct ifnet *ifp, struct mbuf *m)
492{
493        struct lan91cxx_priv_data *cpd = ifp->if_softc;
494        int i, len, plen, tcr, odd;
495        struct mbuf *n = m;
496        unsigned short *sdata = NULL;
497        unsigned short ints, control;
498        uint16_t packet, status;
499        dbg_prefix = ">";
500        DEBUG_FUNCTION();
501
502        cpd->txbusy = 1;
503
504        /* Worry about the TX engine stopping. */
505        tcr = get_reg(cpd, LAN91CXX_TCR);
506        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
507                db1_printf("> ENGINE RESTART: tcr %x\n", tcr);
508                tcr |= LAN91CXX_TCR_TXENA;
509                put_reg(cpd, LAN91CXX_TCR, tcr);
510        }
511
512        /* ############ packet allocation ############ */
513
514        /* Find packet length */
515        plen = 0;
516        while (n) {
517                plen += n->m_len;
518                n = n->m_next;
519        }
520
521        /* Alloc new TX packet */
522        do {
523                put_reg(cpd, LAN91CXX_MMU_COMMAND,
524                        LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));
525
526                i = 1024 * 1024;
527                do {
528                        status = get_reg(cpd, LAN91CXX_INTERRUPT);
529                } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)
530                         && (--i > 0));
531                if (i)
532                        packet = get_reg(cpd, LAN91CXX_PNR);
533                else
534                        packet = 0xffff;
535                db1_printf(">+allocated packet %04x\n", packet);
536
537                packet = packet >> 8;
538                if (packet & 0x80) {
539                        /* Hm.. Isn't this a dead end? */
540                        db1_printf("Allocation failed! Retrying...\n");
541                        continue;
542                }
543        } while (0);
544
545        db4_printf(">+Tx packet allocated %x (previous %x)\n",
546                   packet, cpd->txpacket);
547
548        cpd->txpacket = packet;
549
550        /* ############ assemble packet data ############ */
551
552        /* prepare send */
553        put_reg(cpd, LAN91CXX_PNR, packet);
554        /* Note: Check FIFO state here before continuing? */
555        put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);
556        /* Pointer is now set, and the proper bank is selected for */
557        /* data writes. */
558
559        /* Prepare header: */
560        put_data(cpd, CYG_CPU_TO_LE16(0));      /* reserve space for status word */
561        /* packet length (includes status, byte-count and control shorts) */
562        put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6)));     /* Always even, always < 15xx(dec) */
563
564        /* Put data into buffer */
565        odd = 0;
566        n = m;
567        while (n) {
568                sdata = (unsigned short *)n->m_data;
569                len = n->m_len;
570
571                CYG_ASSERT(sdata, "!No sg data pointer here");
572
573                /* start on an odd offset?
574                 * If last byte also (1byte mbuf with different pointer should not occur)
575                 * let following code handle it
576                 */
577                if ( ((unsigned int)sdata & 1) && (len>1) ){
578                        put_data8(cpd,*(unsigned char *)sdata);
579                        sdata = (unsigned short *)((unsigned int)sdata + 1);
580                        odd = ~odd;
581                        len--;
582                }
583               
584                /* speed up copying a bit, never copy last word */
585                while(len >= 17){
586                        put_data(cpd, *(sdata));
587                        put_data(cpd, *(sdata+1));
588                        put_data(cpd, *(sdata+2));
589                        put_data(cpd, *(sdata+3));
590                        put_data(cpd, *(sdata+4));
591                        put_data(cpd, *(sdata+5));
592                        put_data(cpd, *(sdata+6));
593                        put_data(cpd, *(sdata+7));
594                        sdata += 8;
595                        len -= 16;
596                }
597               
598                /* copy word wise, skip last word */
599                while (len >= 3) {
600                        put_data(cpd, *sdata++);
601                        len -= sizeof(*sdata);
602                }
603               
604                /* one or two bytes left to put into fifo */
605                if ( len > 1 ){
606                        /* the last 2bytes */
607                        if ( !odd || n->m_next ){
608                                put_data(cpd, *sdata++);
609                                len -= sizeof(*sdata);
610                        }else{
611                                /* write next byte, mark that we are not at an odd offset any more,
612                                 * remaining byte will be written outside while together with control byte.
613                                 */
614                                put_data8(cpd,*(unsigned char *)sdata);
615                                sdata = (unsigned short *)((unsigned int)sdata + 1);
616                                odd = 0;
617                                len--;
618                                /*break;*/
619                        }
620                }else if ( (len>0) && (n->m_next) ){
621                        /* one byte left to write, and more bytes is comming in next mbuf */
622                        put_data8(cpd,*(unsigned char *)sdata);
623                        odd = ~odd;
624                }
625
626                n = n->m_next;
627        }
628
629        /* Lay down the control short unconditionally at the end. */
630        /* (or it might use random memory contents) */
631        control = 0;
632        if ( len > 0 ){
633                if ( !odd ) {
634                        /* Need to set ODD flag and insert the data */
635                        unsigned char onebyte = *(unsigned char *)sdata;
636                        control = onebyte;
637                        control |= LAN91CXX_CONTROLBYTE_ODD;
638                }else{
639                        put_data8(cpd,*(unsigned char *)sdata);
640                }
641        }
642        control |= LAN91CXX_CONTROLBYTE_CRC;    /* Just in case... */
643        put_data(cpd, CYG_CPU_TO_LE16(control));
644
645        m_freem(m);
646        CYG_ASSERT(sdata, "!No sg data pointer outside");
647
648        /* ############ start transmit ############ */
649
650        /* Ack TX empty int and unmask it. */
651        ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
652        put_reg(cpd, LAN91CXX_INTERRUPT,
653                ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
654        put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M);   /* notify on error only (Autorelease) */
655
656        /* Enqueue the packet */
657        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
658
659        ints = get_reg(cpd, LAN91CXX_INTERRUPT);
660        db1_printf(">END: ints at TX: %04x\n", ints);
661        dbg_prefix = "";
662}
663
664void smc91111_txDaemon(void *arg)
665{
666        struct lan91cxx_priv_data *cpd = arg;
667        struct ifnet *ifp = &cpd->arpcom.ac_if;
668        struct mbuf *m;
669        rtems_event_set events;
670        DEBUG_FUNCTION();
671
672        for (;;) {
673                /*
674                 * Wait for packet
675                 */
676
677                rtems_bsdnet_event_receive
678                    (SMC91111_START_TRANSMIT_EVENT,
679                     RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
680
681                /*IF_DEQUEUE (&ifp->if_snd, m);
682                   if (m) {
683                   sendpacket (ifp, m);
684                   } */
685
686                for (;;) {
687                        IF_DEQUEUE(&ifp->if_snd, m);
688                        if (!m)
689                                break;
690                        sendpacket(ifp, m);
691                }
692                ifp->if_flags &= ~IFF_OACTIVE;
693
694        }
695
696}
697
698/* start transmit */
699static void smc91111_start(struct ifnet *ifp)
700{
701        struct lan91cxx_priv_data *cpd = ifp->if_softc;
702
703        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
704                return;
705
706        rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
707        ifp->if_flags |= IFF_OACTIVE;
708
709}
710
711/* called after a tx error interrupt, freet the packet */
712static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
713{
714        unsigned short packet, tcr;
715        int success = 1;
716        int saved_packet;
717
718        DEBUG_FUNCTION();
719
720        INCR_STAT(cpd, tx_complete);
721
722        saved_packet = get_reg(cpd, LAN91CXX_PNR);
723
724        /* Ack and mask TX interrupt set */
725        /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
726           ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
727           ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
728           put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
729
730        /* Get number of completed packet and read the status word */
731        packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
732        db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
733
734        {
735                unsigned short reg;
736
737                reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
738
739                /* Covering each bit in turn... */
740                if (reg & LAN91CXX_STATUS_TX_UNRN)
741                        INCR_STAT(cpd, tx_underrun);
742                if (reg & LAN91CXX_STATUS_LOST_CARR)
743                        INCR_STAT(cpd, tx_carrier_loss);
744                if (reg & LAN91CXX_STATUS_LATCOL)
745                        INCR_STAT(cpd, tx_late_collisions);
746                if (reg & LAN91CXX_STATUS_TX_DEFR)
747                        INCR_STAT(cpd, tx_deferred);
748                if (reg & LAN91CXX_STATUS_SQET)
749                        INCR_STAT(cpd, tx_sqetesterrors);
750                if (reg & LAN91CXX_STATUS_16COL)
751                        INCR_STAT(cpd, tx_max_collisions);
752                if (reg & LAN91CXX_STATUS_MUL_COL)
753                        INCR_STAT(cpd, tx_mult_collisions);
754                if (reg & LAN91CXX_STATUS_SNGL_COL)
755                        INCR_STAT(cpd, tx_single_collisions);
756                if (reg & LAN91CXX_STATUS_TX_SUC)
757                        INCR_STAT(cpd, tx_good);
758
759                cpd->stats.tx_total_collisions =
760                    cpd->stats.tx_late_collisions +
761                    cpd->stats.tx_max_collisions +
762                    cpd->stats.tx_mult_collisions +
763                    cpd->stats.tx_single_collisions;
764
765                /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
766                   because it just mimics the info we already have above. */
767        }
768
769        /* We do not really care about Tx failure.  Ethernet is not a reliable
770           medium.  But we do care about the TX engine stopping. */
771        tcr = get_reg(cpd, LAN91CXX_TCR);
772        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
773                db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
774                tcr |= LAN91CXX_TCR_TXENA;
775                put_reg(cpd, LAN91CXX_TCR, tcr);
776                success = 0;    /* And treat this as an error... */
777        }
778
779        packet &= 0xff;
780
781        /* and then free the packet */
782        put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
783        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
784
785        while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
786        /* Don't change Packet Number Reg until busy bit is cleared */
787        /* Per LAN91C111 Spec, Page 50 */
788        put_reg(cpd, LAN91CXX_PNR, saved_packet);
789
790}
791
792/* \ ------------- Helpers ------------- \ */
793
794/*
795 * Show interface statistics
796 */
797static void smc91111_stats(struct lan91cxx_priv_data *priv)
798{
799        printf("tx_good             :%-8d", priv->stats.tx_good);
800        printf("tx_max_collisions   :%-8d", priv->stats.tx_max_collisions);
801        printf("tx_late_collisions  :%-8d", priv->stats.tx_late_collisions);
802        printf("tx_underrun         :%-8d", priv->stats.tx_underrun);
803        printf("tx_carrier_loss     :%-8d", priv->stats.tx_carrier_loss);
804        printf("tx_deferred         :%-8d", priv->stats.tx_deferred);
805        printf("tx_sqetesterrors    :%-8d", priv->stats.tx_sqetesterrors);
806        printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions);
807        printf("tx_mult_collisions  :%-8d", priv->stats.tx_mult_collisions);
808        printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions);
809        printf("rx_good             :%-8d", priv->stats.rx_good);
810        printf("rx_crc_errors       :%-8d", priv->stats.rx_crc_errors);
811        printf("rx_align_errors     :%-8d", priv->stats.rx_align_errors);
812        printf("rx_resource_errors  :%-8d", priv->stats.rx_resource_errors);
813        printf("rx_overrun_errors   :%-8d", priv->stats.rx_overrun_errors);
814        printf("rx_collisions       :%-8d", priv->stats.rx_collisions);
815        printf("rx_short_frames     :%-8d", priv->stats.rx_short_frames);
816        printf("rx_too_long_frames  :%-8d", priv->stats.rx_too_long_frames);
817        printf("rx_symbol_errors    :%-8d", priv->stats.rx_symbol_errors);
818        printf("interrupts          :%-8d", priv->stats.interrupts);
819        printf("rx_count            :%-8d", priv->stats.rx_count);
820        printf("rx_deliver          :%-8d", priv->stats.rx_deliver);
821        printf("rx_resource         :%-8d", priv->stats.rx_resource);
822        printf("rx_restart          :%-8d", priv->stats.rx_restart);
823        printf("tx_count            :%-8d", priv->stats.tx_count);
824        printf("tx_complete         :%-8d", priv->stats.tx_complete);
825        printf("tx_dropped          :%-8d", priv->stats.tx_dropped);
826}
827
828/*
829 * Driver ioctl handler
830 */
831static int smc91111_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
832{
833        struct lan91cxx_priv_data *cpd = ifp->if_softc;
834        int error = 0;
835        DEBUG_FUNCTION();
836
837        switch (command) {
838        case SIOCGIFADDR:
839        case SIOCSIFADDR:
840                db_printf("SIOCSIFADDR\n");
841                ether_ioctl(ifp, command, data);
842                break;
843
844        case SIOCSIFFLAGS:
845                db_printf("SIOCSIFFLAGS\n");
846                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
847                case IFF_RUNNING:
848                        smc91111_stop(cpd);
849                        break;
850
851                case IFF_UP:
852                        smc91111_init(cpd);
853                        break;
854
855                case IFF_UP | IFF_RUNNING:
856                        smc91111_stop(cpd);
857                        smc91111_init(cpd);
858                        break;
859
860                default:
861                        break;
862                }
863                break;
864
865        case SIO_RTEMS_SHOW_STATS:
866                db_printf("SIO_RTEMS_SHOW_STATS\n");
867                smc91111_stats(cpd);
868                break;
869
870                /*
871                 * FIXME: All sorts of multicast commands need to be added here!
872                 */
873        default:
874                error = EINVAL;
875                break;
876        }
877
878        return error;
879}
880
881/*
882 * Attach an SMC91111 driver to the system
883 */
884int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
885                                  struct scmv91111_configuration * chip)
886{
887        struct ifnet *ifp;
888        struct lan91cxx_priv_data *cpd;
889        int unitNumber;
890        char *unitName;
891        int mtu;
892        DEBUG_FUNCTION();
893
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 = */
908/*                           amba_find_apbslv_addr(VENDOR_GAISLER, */
909/*                                                 GAISLER_PIOPORT, &irq_pio)) */
910/*                          && (addr_mctrl = */
911/*                              amba_find_apbslv_addr(VENDOR_ESA, */
912/*                                                    ESA_MCTRL, &irq_mctrl))) { */
913/*                              LEON3_IOPORT_Regs_Map *io = */
914/*                                  (LEON3_IOPORT_Regs_Map *) addr_pio; */
915/*                              db_printf */
916/*                                  ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n", */
917/*                                   (unsigned int)addr_pio, */
918/*                                   (unsigned int)addr_mctrl); */
919/*                              *((volatile unsigned int *)addr_mctrl) |= 0x10f80000;   /\*mctrl ctrl 1 *\/ */
920/*                              io->irqmask |= (1 << chip->pio); */
921/*                              io->irqpol |= (1 << chip->pio); */
922/*                              io->irqedge |= (1 << chip->pio); */
923/*                              io->iodir &= ~(1 << chip->pio); */
924/*                      } else { */
925/*                              return 0; */
926/*                      } */
927/*              } */
928/*      } */
929
930        /* parse driver name */
931        if ((unitNumber =
932             rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
933                db_printf("Unitnumber < 0: %d\n", unitNumber);
934                return 0;
935        }
936
937        db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
938
939        cpd = &smc91111;
940        ifp = &cpd->arpcom.ac_if;
941        memset(cpd, 0, sizeof(*cpd));
942
943        cpd->config = *chip;
944        cpd->base = chip->baseaddr;
945
946        if (smc_probe(cpd)) {
947                return 0;
948        }
949
950        if (config->hardware_address) {
951                memcpy(cpd->arpcom.ac_enaddr, config->hardware_address,
952                       ETHER_ADDR_LEN);
953        } else {
954                /* dummy default address */
955                cpd->arpcom.ac_enaddr[0] = 0x12;
956                cpd->arpcom.ac_enaddr[1] = 0x13;
957                cpd->arpcom.ac_enaddr[2] = 0x14;
958                cpd->arpcom.ac_enaddr[3] = 0x15;
959                cpd->arpcom.ac_enaddr[4] = 0x16;
960                cpd->arpcom.ac_enaddr[5] = 0x17;
961        }
962
963        cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
964        cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
965        cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
966        cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
967        cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
968        cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
969        cpd->rpc_cur_mode =
970            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
971            LAN91CXX_RPCR_ANEG;
972
973        if (config->mtu)
974                mtu = config->mtu;
975        else
976                mtu = ETHERMTU;
977
978        /*
979         * Set up network interface values
980         */
981        ifp->if_softc = cpd;
982        ifp->if_unit = unitNumber;
983        ifp->if_name = unitName;
984        ifp->if_mtu = mtu;
985        ifp->if_init = smc91111_init;
986        ifp->if_ioctl = smc91111_ioctl;
987        ifp->if_start = smc91111_start;
988        ifp->if_output = ether_output;
989        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
990        if (ifp->if_snd.ifq_maxlen == 0)
991                ifp->if_snd.ifq_maxlen = ifqmaxlen;
992
993        /*
994         * Attach the interface
995         */
996        if_attach(ifp);
997        ether_ifattach(ifp);
998
999#ifdef DEBUG
1000        printf("SMC91111 : driver has been attached\n");
1001#endif
1002
1003        return 1;
1004};
1005
1006/* \ ------------- Initialization ------------- \ */
1007
1008/*
1009 * Initialize and start the device
1010 */
1011static void smc91111_init(void *arg)
1012{
1013        struct lan91cxx_priv_data *cpd = arg;
1014        struct ifnet *ifp = &cpd->arpcom.ac_if;
1015        DEBUG_FUNCTION();
1016
1017        if (cpd->txDaemonTid == 0) {
1018
1019                lan91cxx_hardware_init(cpd);
1020                lan91cxx_start(ifp);
1021
1022                cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
1023                                                        smc91111_rxDaemon, cpd);
1024                cpd->txDaemonTid =
1025                    rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
1026        }
1027
1028        /*
1029         * Tell the world that we're running.
1030         */
1031        ifp->if_flags |= IFF_RUNNING;
1032}
1033
1034/*
1035 * Stop the device
1036 */
1037static void smc91111_stop(struct lan91cxx_priv_data *cpd)
1038{
1039        struct ifnet *ifp = &cpd->arpcom.ac_if;
1040        DEBUG_FUNCTION();
1041
1042        ifp->if_flags &= ~IFF_RUNNING;
1043
1044        /* Reset chip */
1045        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1046        put_reg(cpd, LAN91CXX_RCR, 0);
1047        cpd->txbusy = cpd->within_send = 0;
1048
1049}
1050
1051int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
1052{
1053        unsigned short val;
1054        int i;
1055
1056        DEBUG_FUNCTION();
1057
1058        cpd->txbusy = cpd->within_send = 0;
1059
1060        /* install interrupt vector */
1061        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1062        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1063
1064        /* Reset chip */
1065        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1066        put_reg(cpd, LAN91CXX_RCR, 0);
1067        HAL_DELAY_US(100000);
1068        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1069        put_reg(cpd, LAN91CXX_RCR, 0);
1070        put_reg(cpd, LAN91CXX_TCR, 0);
1071        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1072
1073        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1074        /* probe chip by reading the signature in BS register */
1075        val = get_banksel(cpd);
1076        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1077                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1078
1079        if ((0xff00 & val) != 0x3300) {
1080                printf("No 91Cxx signature");
1081                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1082                return 0;
1083        }
1084
1085        val = get_reg(cpd, LAN91CXX_REVISION);
1086
1087        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1088                   (val >> 4) & 0xf, val & 0xf);
1089
1090        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1091        cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */
1092
1093        /* The controller may provide a function used to set up the ESA */
1094        if (cpd->config_enaddr)
1095                (*cpd->config_enaddr) (cpd);
1096
1097        db9_printf("LAN91CXX - status: %04x\n", val);
1098        /* Use statically configured ESA from the private data */
1099        db9_printf
1100            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1101             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1102             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1103        /* Set up hardware address */
1104        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1105                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1106                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1107
1108        return 1;
1109}
1110
1111/*
1112  This function is called to "start up" the interface.  It may be called
1113  multiple times, even when the hardware is already running.  It will be
1114  called whenever something "hardware oriented" changes and should leave
1115  the hardware ready to send/receive packets.
1116*/
1117static void lan91cxx_start(struct ifnet *ifp)
1118{
1119        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1120
1121        uint16_t intr;
1122        uint16_t phy_ctl;
1123        int delay;
1124        DEBUG_FUNCTION();
1125
1126        HAL_DELAY_US(100000);
1127
1128        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1129        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1130        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1131        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1132
1133        /* Start auto-negotiation */
1134        put_reg(cpd, LAN91CXX_RPCR,
1135                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1136                LAN91CXX_RPCR_ANEG);
1137        cpd->rpc_cur_mode =
1138            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1139            LAN91CXX_RPCR_ANEG;
1140
1141        /* wait for auto-negotiation to finish. */
1142        /* give it ~5 seconds before giving up (no cable?) */
1143        delay = 50;
1144        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1145                if (--delay <= 0) {
1146                        printf("Timeout autonegotiation\n");
1147                        break;
1148                }
1149                HAL_DELAY_US(100000);
1150        }
1151
1152        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1153
1154        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1155        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1156        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1157                (LAN91CXX_INTERRUPT_TX_INT |
1158                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1159                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1160        put_reg(cpd, LAN91CXX_RCR,
1161                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1162                LAN91CXX_RCR_ALMUL);
1163        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1164        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1165        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1166                LAN91CXX_INTERRUPT_RCV_INT_M);
1167
1168        if ((0
1169#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1170             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1171#endif
1172            ) || (ifp->if_flags & IFF_PROMISC)
1173            ) {
1174                /* Then we select promiscuous mode. */
1175                unsigned short rcr;
1176                rcr = get_reg(cpd, LAN91CXX_RCR);
1177                rcr |= LAN91CXX_RCR_PRMS;
1178                put_reg(cpd, LAN91CXX_RCR, rcr);
1179        }
1180}
1181
1182/* \ ------------- Probe ------------- \ */
1183
1184static const char *chip_ids[15] = {
1185        NULL, NULL, NULL,
1186        /* 3 */ "SMC91C90/91C92",
1187        /* 4 */ "SMC91C94",
1188        /* 5 */ "SMC91C95",
1189        /* 6 */ "SMC91C96",
1190        /* 7 */ "SMC91C100",
1191        /* 8 */ "SMC91C100FD",
1192        /* 9 */ "SMC91C11xFD",
1193        NULL, NULL,
1194        NULL, NULL, NULL
1195};
1196
1197static int smc_probe(struct lan91cxx_priv_data *cpd)
1198{
1199        unsigned short bank;
1200        unsigned short revision_register;
1201
1202        DEBUG_FUNCTION();
1203
1204        /* First, see if the high byte is 0x33 */
1205        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1206        bank = CYG_LE16_TO_CPU(bank);
1207        if ((bank & 0xFF00) != 0x3300) {
1208                db_printf("<1>Smc probe bank check 1 failed.\n");
1209                return -ENODEV;
1210        }
1211        /* The above MIGHT indicate a device, but I need to write to further
1212           test this.  */
1213        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1214        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1215        bank = CYG_LE16_TO_CPU(bank);
1216        if ((bank & 0xFF00) != 0x3300) {
1217                db_printf("<1>Smc probe bank check 2 failed.\n");
1218                return -ENODEV;
1219        }
1220#if SMC_DEBUG > 3
1221        {
1222                unsigned short bank16, bank16_0, bank16_1;
1223                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1224                bank = CYG_LE16_TO_CPU(bank);
1225                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1226                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1227
1228                db_printf
1229                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1230                db_printf
1231                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1232                     bank16_0);
1233                db_printf
1234                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1235                     bank16_1);
1236        }
1237#endif
1238
1239        /*  check if the revision register is something that I recognize.
1240           These might need to be added to later, as future revisions
1241           could be added.  */
1242        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1243        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1244                /* I don't recognize this chip, so... */
1245                db_printf
1246                    ("smc_probe: IO %x: Unrecognized revision register:"
1247                     " %x, Contact author. \n", (unsigned int)cpd->base,
1248                     revision_register);
1249
1250                return -ENODEV;
1251        }
1252        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1253                  revision_register,
1254                  chip_ids[(revision_register >> 4) & 0xF],
1255                  revision_register & 0xf);
1256
1257        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1258        if (revision_register == 0x3390) {
1259                db_printf("!Revision A\n");
1260        }
1261
1262        return 0;
1263}
1264
1265#if 0
1266/* \ ------------- PHY read/write ------------- \ */
1267/*Sets the PHY to a configuration as determined by the user*/
1268static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1269{
1270        int my_fixed_caps;
1271        int cfg1;
1272
1273        DEBUG_FUNCTION();
1274        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1275                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1276
1277        /* Enter Link Disable state */
1278        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1279        cfg1 |= PHY_CFG1_LNKDIS;
1280        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1281
1282        /* Set our fixed capabilities, Disable auto-negotiation */
1283        my_fixed_caps = 0;
1284
1285        if (cpd->config.ctl_rfduplx)
1286                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1287
1288        if (cpd->config.ctl_rspeed == 100)
1289                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1290
1291        /* Write capabilities to the phy control register */
1292        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1293
1294        /* Re-Configure the Receive/Phy Control register */
1295        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1296
1297        return (1);
1298}
1299#endif
1300
1301#if 0
1302/*Configures the specified PHY using Autonegotiation. */
1303static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1304{
1305
1306        unsigned int phyaddr;
1307        unsigned int my_phy_caps;       /* My PHY capabilities */
1308        unsigned int my_ad_caps;        /* My Advertised capabilities */
1309        unsigned int status = 0;
1310        int failed = 0, delay;
1311
1312        DEBUG_FUNCTION();
1313
1314        /* Set the blocking flag */
1315        cpd->autoneg_active = 1;
1316
1317        /* Get the detected phy address */
1318        phyaddr = cpd->phyaddr;
1319
1320        /* Reset the PHY, setting all other bits to zero */
1321        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1322
1323        /* Wait for the reset to complete, or time out */
1324        delay = 50;
1325        while (delay--) {
1326                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1327                      & PHY_CNTL_RST)) {
1328                        break;
1329                }
1330                HAL_DELAY_US(100000);
1331        }
1332
1333        if (delay < 1) {
1334                db_printf("smc91111:!PHY reset timed out\n");
1335                goto smc_phy_configure_exit;
1336        }
1337
1338        /* Read PHY Register 18, Status Output */
1339        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1340
1341        /* Enable PHY Interrupts (for register 18) */
1342        /* Interrupts listed here are disabled */
1343        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1344                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1345                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1346                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1347
1348        /* Configure the Receive/Phy Control register */
1349        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1350
1351        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1352        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1353        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1354
1355        if (my_phy_caps & PHY_STAT_CAP_T4)
1356                my_ad_caps |= PHY_AD_T4;
1357
1358        if (my_phy_caps & PHY_STAT_CAP_TXF)
1359                my_ad_caps |= PHY_AD_TX_FDX;
1360
1361        if (my_phy_caps & PHY_STAT_CAP_TXH)
1362                my_ad_caps |= PHY_AD_TX_HDX;
1363
1364        if (my_phy_caps & PHY_STAT_CAP_TF)
1365                my_ad_caps |= PHY_AD_10_FDX;
1366
1367        if (my_phy_caps & PHY_STAT_CAP_TH)
1368                my_ad_caps |= PHY_AD_10_HDX;
1369
1370        /* Disable capabilities not selected by our user */
1371        if (cpd->config.ctl_rspeed != 100) {
1372                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1373        }
1374
1375        if (!cpd->config.ctl_rfduplx) {
1376                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1377        }
1378
1379        /* Update our Auto-Neg Advertisement Register */
1380        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1381
1382        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1383        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1384
1385        /* If the user requested no auto neg, then go set his request */
1386        if (!(cpd->config.ctl_autoneg)) {
1387                lan91cxx_phy_fixed(cpd);
1388
1389                goto smc_phy_configure_exit;
1390        }
1391
1392        /* Restart auto-negotiation process in order to advertise my caps */
1393        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1394                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1395
1396        /* wait for auto-negotiation to finish. */
1397        /* give it ~5 seconds before giving up (no cable?) */
1398        delay = 50;
1399        while (!
1400               ((status =
1401                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1402                if (--delay <= 0) {
1403                        printf("Timeout autonegotiation\n");
1404                        failed = 1;
1405                        break;
1406                }
1407
1408                /* Restart auto-negotiation if remote fault */
1409                if (status & PHY_STAT_REM_FLT) {
1410                        db_printf("smc91111:PHY remote fault detected\n");
1411
1412                        /* Restart auto-negotiation */
1413                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1414                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1415                                           PHY_CNTL_ANEG_EN |
1416                                           PHY_CNTL_ANEG_RST |
1417                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1418                }
1419                HAL_DELAY_US(100000);
1420        }
1421
1422        /* Fail if we detected an auto-negotiate remote fault */
1423        if (status & PHY_STAT_REM_FLT) {
1424                db_printf("smc91111:PHY remote fault detected\n");
1425                failed = 1;
1426        }
1427
1428        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1429
1430        /* Set our sysctl parameters to match auto-negotiation results */
1431        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1432                db_printf("smc91111:PHY 100BaseT\n");
1433                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1434        } else {
1435                db_printf("smc91111:PHY 10BaseT\n");
1436                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1437        }
1438
1439        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1440                db_printf("smc91111:PHY Full Duplex\n");
1441                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1442        } else {
1443                db_printf("smc91111:PHY Half Duplex\n");
1444                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1445        }
1446
1447        /* Re-Configure the Receive/Phy Control register */
1448        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1449
1450      smc_phy_configure_exit:
1451
1452        /* Exit auto-negotiation */
1453        cpd->autoneg_active = 0;
1454}
1455#endif
1456
1457static uint16_t
1458lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1459                  uint8_t phyreg)
1460{
1461        int i, mask, input_idx, clk_idx = 0;
1462        uint16_t mii_reg, value;
1463        uint8_t bits[64];
1464
1465        /* 32 consecutive ones on MDO to establish sync */
1466        for (i = 0; i < 32; ++i)
1467                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1468
1469        /* Start code <01> */
1470        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1471        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1472
1473        /* Read command <10> */
1474        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1475        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1476
1477        /* Output the PHY address, msb first */
1478        for (mask = 0x10; mask; mask >>= 1) {
1479                if (phyaddr & mask)
1480                        bits[clk_idx++] =
1481                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1482                else
1483                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1484        }
1485
1486        /* Output the phy register number, msb first */
1487        for (mask = 0x10; mask; mask >>= 1) {
1488                if (phyreg & mask)
1489                        bits[clk_idx++] =
1490                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1491                else
1492                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1493        }
1494
1495        /* Tristate and turnaround (1 bit times) */
1496        bits[clk_idx++] = 0;
1497
1498        /* Input starts at this bit time */
1499        input_idx = clk_idx;
1500
1501        /* Will input 16 bits */
1502        for (i = 0; i < 16; ++i)
1503                bits[clk_idx++] = 0;
1504
1505        /* Final clock bit */
1506        bits[clk_idx++] = 0;
1507
1508        /* Get the current MII register value */
1509        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1510
1511        /* Turn off all MII Interface bits */
1512        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1513                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1514        HAL_DELAY_US(50);
1515
1516        /* Clock all 64 cycles */
1517        for (i = 0; i < sizeof(bits); ++i) {
1518                /* Clock Low - output data */
1519                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1520                HAL_DELAY_US(50);
1521
1522                /* Clock Hi - input data */
1523                put_reg(cpd, LAN91CXX_MGMT,
1524                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1525                HAL_DELAY_US(50);
1526
1527                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1528        }
1529
1530        /* Return to idle state */
1531        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1532        HAL_DELAY_US(50);
1533
1534        /* Recover input data */
1535        for (value = 0, i = 0; i < 16; ++i) {
1536                value <<= 1;
1537                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1538                        value |= 1;
1539        }
1540
1541        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1542        return value;
1543}
1544
1545static void
1546lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1547                   uint8_t phyreg, uint16_t value)
1548{
1549        int i, mask, clk_idx = 0;
1550        uint16_t mii_reg;
1551        uint8_t bits[65];
1552
1553        /* 32 consecutive ones on MDO to establish sync */
1554        for (i = 0; i < 32; ++i)
1555                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1556
1557        /* Start code <01> */
1558        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1559        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1560
1561        /* Write command <01> */
1562        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1563        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1564
1565        /* Output the PHY address, msb first */
1566        for (mask = 0x10; mask; mask >>= 1) {
1567                if (phyaddr & mask)
1568                        bits[clk_idx++] =
1569                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1570                else
1571                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1572        }
1573
1574        /* Output the phy register number, msb first */
1575        for (mask = 0x10; mask; mask >>= 1) {
1576                if (phyreg & mask)
1577                        bits[clk_idx++] =
1578                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1579                else
1580                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1581        }
1582
1583        /* Tristate and turnaround (2 bit times) */
1584        bits[clk_idx++] = 0;
1585        bits[clk_idx++] = 0;
1586
1587        /* Write out 16 bits of data, msb first */
1588        for (mask = 0x8000; mask; mask >>= 1) {
1589                if (value & mask)
1590                        bits[clk_idx++] =
1591                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1592                else
1593                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1594        }
1595
1596        /* Final clock bit (tristate) */
1597        bits[clk_idx++] = 0;
1598
1599        /* Get the current MII register value */
1600        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1601
1602        /* Turn off all MII Interface bits */
1603        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1604                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1605        HAL_DELAY_US(50);
1606
1607        /* Clock all cycles */
1608        for (i = 0; i < sizeof(bits); ++i) {
1609                /* Clock Low - output data */
1610                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1611                HAL_DELAY_US(50);
1612
1613                /* Clock Hi - input data */
1614                put_reg(cpd, LAN91CXX_MGMT,
1615                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1616                HAL_DELAY_US(50);
1617
1618/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1619        }
1620
1621        /* Return to idle state */
1622        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1623        HAL_DELAY_US(50);
1624
1625        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1626}
1627
1628#endif
1629
1630#if 0
1631void lan91cxx_print_bank(int bank){
1632        struct lan91cxx_priv_data *cpd = &smc91111;
1633        int regno;
1634        unsigned short regval[8];
1635        int i;
1636
1637        if ( bank >= 4 )
1638                return;
1639        for(i=0; i<8; i++){
1640                regno=i+bank<<3;
1641                regval[i] = get_reg(cpd, regno);
1642        }
1643        printk("---- BANK %d ----\n\r",bank);   
1644        for(i=0; i<8; i++){
1645                printk("0x%x: 0x%x\n\r",i,regval[i]);
1646        }
1647
1648}
1649#endif
Note: See TracBrowser for help on using the repository browser.