source: rtems/c/src/libchip/network/smc91111.c @ 7f247f3

4.104.114.84.95
Last change on this file since 7f247f3 was 7f247f3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/06 at 13:00:15

2006-09-04 Joel Sherrill <joel@…>

  • libchip/network/greth.c, libchip/network/open_eth.c, libchip/network/smc91111.c, libchip/network/sonic.c: Fix error introduced by warning removal.
  • Property mode set to 100644
File size: 42.3 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                        DEBUG_puts("#tx error\n");
122                        db_printf("#*tx irq\n");
123                        lan91cxx_finish_sent(cpd);
124                        put_reg(cpd, LAN91CXX_INTERRUPT,
125                                (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);
126
127                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */
128                        /*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */
129                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */
130                }
131                if (event & LAN91CXX_INTERRUPT_RCV_INT) {
132                        db_printf("#*rx irq\n");
133                        rtems_event_send(cpd->rxDaemonTid,
134                                         SMC91111_INTERRUPT_EVENT);
135                }
136                if (event &
137                    ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
138                        db_printf("Unknown interrupt\n");
139        }
140        db_printf("out %s\n", __FUNCTION__);
141
142        put_reg(cpd, LAN91CXX_POINTER, oldpointer);
143        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
144}
145
146/* \ ------------- Rx receive ------------- \ */
147
148 /**/
149/* This function is called as a result of the "readpacket()" call.*/
150/* Its job is to actually fetch data for a packet from the hardware once*/
151/* memory buffers have been allocated for the packet.  Note that the buffers*/
152/* may come in pieces, using a mbuf list.  */
153static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m)
154{
155        struct ifnet *ifp = &cpd->arpcom.ac_if;
156        struct ether_header *eh;
157        short mlen = 0, plen;
158        char *start;
159        rxd_t *data = NULL, val, lp;
160        struct mbuf *n;
161        lp = 0;
162        dbg_prefix = "<";
163
164        DEBUG_FUNCTION();
165        INCR_STAT(cpd, rx_deliver);
166
167        /* ############ read packet ############ */
168
169        put_reg(cpd, LAN91CXX_POINTER,
170                (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
171                 LAN91CXX_POINTER_AUTO_INCR));
172        val = get_data(cpd);
173
174        /* packet length (minus header/footer) */
175#ifdef LAN91CXX_32BIT_RX
176        val = CYG_LE32_TO_CPU(val);
177        plen = (val >> 16) - 6;
178#else
179        val = CYG_LE16_TO_CPU(val);
180        plen = get_data(cpd);
181        plen = CYG_LE16_TO_CPU(plen) - 6;
182#endif
183
184        if (LAN91CXX_RX_STATUS_IS_ODD(cpd, val))
185                plen++;
186
187        for (n = m; n; n = n->m_next) {
188#ifdef LAN91CXX_32BIT_RX
189                if (mlen == 2) {
190#if DEBUG & 64
191                        db_printf("Appending to last apacket\n");
192#endif
193
194                        val = get_data(cpd);
195                        *((unsigned short *)data) = (val >> 16) & 0xffff;
196                        plen -= 2;
197                        data = (rxd_t *) n->m_data;
198                        start = (char *)data;
199                        mlen = n->m_len;
200                        if ((data) && (mlen > 1)) {
201                                *(unsigned short *)data = (val & 0xffff);
202                                data = (rxd_t *)((unsigned short *)data + 1);
203                                plen -= 2;
204                                mlen -= 2;
205                        }
206                } else {
207                        data = (rxd_t *) n->m_data;
208                        start = (char *)data;
209                        mlen = n->m_len;
210                }
211#else
212                data = (rxd_t *) n->m_data;
213                start = (char *)data;
214                mlen = n->m_len;
215#endif
216
217                db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);
218
219                if (data) {
220                        while (mlen >= sizeof(*data)) {
221#ifdef LAN91CXX_32BIT_RX
222                                val = get_data(cpd);
223                                *(unsigned short *)data = (val >> 16) & 0xffff;
224                                data = (rxd_t *)((unsigned short *)data + 1);
225                                *(unsigned short *)data = (val & 0xffff);
226                                data = (rxd_t *)((unsigned short *)data + 1);
227#else
228                                *data++ = get_data(cpd);
229#endif
230                                mlen -= sizeof(*data);
231                                plen -= sizeof(*data);
232                        }
233                } else {        /* must actively discard ie. read it from the chip anyway. */
234                        while (mlen >= sizeof(*data)) {
235                                (void)get_data(cpd);
236                                mlen -= sizeof(*data);
237                                plen -= sizeof(*data);
238                        }
239                }
240
241#if DEBUG & 64
242                lp = 0;
243                while (((int)start) < ((int)data)) {
244                        unsigned char a = *(start++);
245                        unsigned char b = *(start++);
246                        db64_printf("%02x %02x ", a, b);
247                        lp += 2;
248                        if (lp >= 16) {
249                                db64_printf("\n");
250                                lp = 0;
251                        }
252                }
253                db64_printf(" \n");
254
255#endif
256        }
257        val = get_data(cpd);    /* Read control word (and potential data) unconditionally */
258#ifdef LAN91CXX_32BIT_RX
259        if (plen & 2) {
260                if (data) {
261                        *(unsigned short *)data = (val >> 16) & 0xffff;
262            data = (rxd_t *)((unsigned short *)data + 1);
263                        val <<= 16;
264                }
265        }
266        if (plen & 1)
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 (LAN91CXX_RX_STATUS_IS_ODD(cpd, stat))
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;
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        n = m;
566        while (n) {
567                sdata = (unsigned short *)n->m_data;
568                len = n->m_len;
569
570                CYG_ASSERT((0 == (len & 1)
571                            || !(n->m_next)), "!odd length");
572                CYG_ASSERT(sdata, "!No sg data pointer here");
573
574                while (len >= sizeof(*sdata)) {
575                        put_data(cpd, *sdata++);
576                        len -= sizeof(*sdata);
577                }
578                n = n->m_next;
579        }
580#if DEBUG & 64
581        n = m;
582        while (n) {
583                int lp = 0;
584                unsigned char *start = (unsigned char *)n->m_data;
585                len = n->m_len;
586                while (len > 0) {
587                        unsigned char a = *(start++);
588                        unsigned char b = *(start++);
589                        db64_printf("%02x %02x ", a, b);
590                        lp += 2;
591                        if (lp >= 16) {
592                                db64_printf("\n");
593                                lp = 0;
594                        }
595                        len -= 2;
596                }
597                n = n->m_next;
598        }
599        db64_printf(" \n");
600#endif
601
602        m_freem(m);
603        CYG_ASSERT(sdata, "!No sg data pointer outside");
604
605        /* Lay down the control short unconditionally at the end. */
606        /* (or it might use random memory contents) */
607        control = 0;
608        if (1 & plen) {
609                /* Need to set ODD flag and insert the data */
610                unsigned char onebyte = *(unsigned char *)sdata;
611                control = onebyte;
612                control |= LAN91CXX_CONTROLBYTE_ODD;
613        }
614        control |= LAN91CXX_CONTROLBYTE_CRC;    /* Just in case... */
615        put_data(cpd, CYG_CPU_TO_LE16(control));
616
617        /* ############ start transmit ############ */
618
619        /* Ack TX empty int and unmask it. */
620        ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
621        put_reg(cpd, LAN91CXX_INTERRUPT,
622                ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
623        put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M);   /* notify on error only (Autorelease) */
624
625        /* Enqueue the packet */
626        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
627
628        ints = get_reg(cpd, LAN91CXX_INTERRUPT);
629        db1_printf(">END: ints at TX: %04x\n", ints);
630        dbg_prefix = "";
631}
632
633void smc91111_txDaemon(void *arg)
634{
635        struct lan91cxx_priv_data *cpd = arg;
636        struct ifnet *ifp = &cpd->arpcom.ac_if;
637        struct mbuf *m;
638        rtems_event_set events;
639        DEBUG_FUNCTION();
640
641        for (;;) {
642                /*
643                 * Wait for packet
644                 */
645
646                rtems_bsdnet_event_receive
647                    (SMC91111_START_TRANSMIT_EVENT,
648                     RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
649
650                /*IF_DEQUEUE (&ifp->if_snd, m);
651                   if (m) {
652                   sendpacket (ifp, m);
653                   } */
654
655                for (;;) {
656                        IF_DEQUEUE(&ifp->if_snd, m);
657                        if (!m)
658                                break;
659                        sendpacket(ifp, m);
660                }
661                ifp->if_flags &= ~IFF_OACTIVE;
662
663        }
664
665}
666
667/* start transmit */
668static void smc91111_start(struct ifnet *ifp)
669{
670        struct lan91cxx_priv_data *cpd = ifp->if_softc;
671
672        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
673                return;
674
675        rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
676        ifp->if_flags |= IFF_OACTIVE;
677
678}
679
680/* called after a tx error interrupt, freet the packet */
681static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
682{
683        unsigned short packet, tcr;
684        int success = 1;
685        int saved_packet;
686
687        DEBUG_FUNCTION();
688
689        INCR_STAT(cpd, tx_complete);
690
691        saved_packet = get_reg(cpd, LAN91CXX_PNR);
692
693        /* Ack and mask TX interrupt set */
694        /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
695           ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
696           ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
697           put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
698
699        /* Get number of completed packet and read the status word */
700        packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
701        db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
702
703        {
704                unsigned short reg;
705
706                reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
707
708                /* Covering each bit in turn... */
709                if (reg & LAN91CXX_STATUS_TX_UNRN)
710                        INCR_STAT(cpd, tx_underrun);
711                if (reg & LAN91CXX_STATUS_LOST_CARR)
712                        INCR_STAT(cpd, tx_carrier_loss);
713                if (reg & LAN91CXX_STATUS_LATCOL)
714                        INCR_STAT(cpd, tx_late_collisions);
715                if (reg & LAN91CXX_STATUS_TX_DEFR)
716                        INCR_STAT(cpd, tx_deferred);
717                if (reg & LAN91CXX_STATUS_SQET)
718                        INCR_STAT(cpd, tx_sqetesterrors);
719                if (reg & LAN91CXX_STATUS_16COL)
720                        INCR_STAT(cpd, tx_max_collisions);
721                if (reg & LAN91CXX_STATUS_MUL_COL)
722                        INCR_STAT(cpd, tx_mult_collisions);
723                if (reg & LAN91CXX_STATUS_SNGL_COL)
724                        INCR_STAT(cpd, tx_single_collisions);
725                if (reg & LAN91CXX_STATUS_TX_SUC)
726                        INCR_STAT(cpd, tx_good);
727
728                cpd->stats.tx_total_collisions =
729                    cpd->stats.tx_late_collisions +
730                    cpd->stats.tx_max_collisions +
731                    cpd->stats.tx_mult_collisions +
732                    cpd->stats.tx_single_collisions;
733
734                /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
735                   because it just mimics the info we already have above. */
736        }
737
738        /* We do not really care about Tx failure.  Ethernet is not a reliable
739           medium.  But we do care about the TX engine stopping. */
740        tcr = get_reg(cpd, LAN91CXX_TCR);
741        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
742                db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
743                tcr |= LAN91CXX_TCR_TXENA;
744                put_reg(cpd, LAN91CXX_TCR, tcr);
745                success = 0;    /* And treat this as an error... */
746        }
747
748        packet &= 0xff;
749
750        /* and then free the packet */
751        put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
752        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
753
754        while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
755        /* Don't change Packet Number Reg until busy bit is cleared */
756        /* Per LAN91C111 Spec, Page 50 */
757        put_reg(cpd, LAN91CXX_PNR, saved_packet);
758
759}
760
761/* \ ------------- Helpers ------------- \ */
762
763/*
764 * Show interface statistics
765 */
766static void smc91111_stats(struct lan91cxx_priv_data *priv)
767{
768        printf("tx_good             :%-8d", priv->stats.tx_good);
769        printf("tx_max_collisions   :%-8d", priv->stats.tx_max_collisions);
770        printf("tx_late_collisions  :%-8d", priv->stats.tx_late_collisions);
771        printf("tx_underrun         :%-8d", priv->stats.tx_underrun);
772        printf("tx_carrier_loss     :%-8d", priv->stats.tx_carrier_loss);
773        printf("tx_deferred         :%-8d", priv->stats.tx_deferred);
774        printf("tx_sqetesterrors    :%-8d", priv->stats.tx_sqetesterrors);
775        printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions);
776        printf("tx_mult_collisions  :%-8d", priv->stats.tx_mult_collisions);
777        printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions);
778        printf("rx_good             :%-8d", priv->stats.rx_good);
779        printf("rx_crc_errors       :%-8d", priv->stats.rx_crc_errors);
780        printf("rx_align_errors     :%-8d", priv->stats.rx_align_errors);
781        printf("rx_resource_errors  :%-8d", priv->stats.rx_resource_errors);
782        printf("rx_overrun_errors   :%-8d", priv->stats.rx_overrun_errors);
783        printf("rx_collisions       :%-8d", priv->stats.rx_collisions);
784        printf("rx_short_frames     :%-8d", priv->stats.rx_short_frames);
785        printf("rx_too_long_frames  :%-8d", priv->stats.rx_too_long_frames);
786        printf("rx_symbol_errors    :%-8d", priv->stats.rx_symbol_errors);
787        printf("interrupts          :%-8d", priv->stats.interrupts);
788        printf("rx_count            :%-8d", priv->stats.rx_count);
789        printf("rx_deliver          :%-8d", priv->stats.rx_deliver);
790        printf("rx_resource         :%-8d", priv->stats.rx_resource);
791        printf("rx_restart          :%-8d", priv->stats.rx_restart);
792        printf("tx_count            :%-8d", priv->stats.tx_count);
793        printf("tx_complete         :%-8d", priv->stats.tx_complete);
794        printf("tx_dropped          :%-8d", priv->stats.tx_dropped);
795}
796
797/*
798 * Driver ioctl handler
799 */
800static int smc91111_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
801{
802        struct lan91cxx_priv_data *cpd = ifp->if_softc;
803        int error = 0;
804        DEBUG_FUNCTION();
805
806        switch (command) {
807        case SIOCGIFADDR:
808        case SIOCSIFADDR:
809                db_printf("SIOCSIFADDR\n");
810                ether_ioctl(ifp, command, data);
811                break;
812
813        case SIOCSIFFLAGS:
814                db_printf("SIOCSIFFLAGS\n");
815                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
816                case IFF_RUNNING:
817                        smc91111_stop(cpd);
818                        break;
819
820                case IFF_UP:
821                        smc91111_init(cpd);
822                        break;
823
824                case IFF_UP | IFF_RUNNING:
825                        smc91111_stop(cpd);
826                        smc91111_init(cpd);
827                        break;
828
829                default:
830                        break;
831                }
832                break;
833
834        case SIO_RTEMS_SHOW_STATS:
835                db_printf("SIO_RTEMS_SHOW_STATS\n");
836                smc91111_stats(cpd);
837                break;
838
839                /*
840                 * FIXME: All sorts of multicast commands need to be added here!
841                 */
842        default:
843                error = EINVAL;
844                break;
845        }
846
847        return error;
848}
849
850/*
851 * Attach an SMC91111 driver to the system
852 */
853int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
854                                  struct scmv91111_configuration * chip)
855{
856        struct ifnet *ifp;
857        struct lan91cxx_priv_data *cpd;
858        int unitNumber;
859        char *unitName;
860        int mtu;
861        DEBUG_FUNCTION();
862
863/*      /\* activate io area *\/ */
864/*      switch (sparc_leon23_get_psr_version()) { */
865/*      case 0: */
866/*      case 2: */
867/*              db_printf("Activating Leon2 io port\n"); */
868/*              /\*configure pio *\/ */
869/*              *((volatile unsigned int *)0x80000000) |= 0x10f80000; */
870/*              *((volatile unsigned int *)0x800000A8) |= */
871/*                  (0xe0 | chip->vector) << (8 * (chip->pio - 4)); */
872/*              break; */
873/*      default: */
874/*              { */
875/*                      unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl; */
876/*                      if ((addr_pio = */
877/*                           amba_find_apbslv_addr(VENDOR_GAISLER, */
878/*                                                 GAISLER_PIOPORT, &irq_pio)) */
879/*                          && (addr_mctrl = */
880/*                              amba_find_apbslv_addr(VENDOR_ESA, */
881/*                                                    ESA_MCTRL, &irq_mctrl))) { */
882/*                              LEON3_IOPORT_Regs_Map *io = */
883/*                                  (LEON3_IOPORT_Regs_Map *) addr_pio; */
884/*                              db_printf */
885/*                                  ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n", */
886/*                                   (unsigned int)addr_pio, */
887/*                                   (unsigned int)addr_mctrl); */
888/*                              *((volatile unsigned int *)addr_mctrl) |= 0x10f80000;   /\*mctrl ctrl 1 *\/ */
889/*                              io->irqmask |= (1 << chip->pio); */
890/*                              io->irqpol |= (1 << chip->pio); */
891/*                              io->irqedge |= (1 << chip->pio); */
892/*                              io->iodir &= ~(1 << chip->pio); */
893/*                      } else { */
894/*                              return 0; */
895/*                      } */
896/*              } */
897/*      } */
898
899        /* parse driver name */
900        if ((unitNumber =
901             rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
902                db_printf("Unitnumber < 0: %d\n", unitNumber);
903                return 0;
904        }
905
906        db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
907
908        cpd = &smc91111;
909        ifp = &cpd->arpcom.ac_if;
910        memset(cpd, 0, sizeof(*cpd));
911
912        cpd->config = *chip;
913        cpd->base = chip->baseaddr;
914
915        if (smc_probe(cpd)) {
916                return 0;
917        }
918
919        if (config->hardware_address) {
920                memcpy(cpd->arpcom.ac_enaddr, config->hardware_address,
921                       ETHER_ADDR_LEN);
922        } else {
923                /* dummy default address */
924                cpd->arpcom.ac_enaddr[0] = 0x12;
925                cpd->arpcom.ac_enaddr[1] = 0x13;
926                cpd->arpcom.ac_enaddr[2] = 0x14;
927                cpd->arpcom.ac_enaddr[3] = 0x15;
928                cpd->arpcom.ac_enaddr[4] = 0x16;
929                cpd->arpcom.ac_enaddr[5] = 0x17;
930        }
931
932        cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
933        cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
934        cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
935        cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
936        cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
937        cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
938        cpd->rpc_cur_mode =
939            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
940            LAN91CXX_RPCR_ANEG;
941
942        if (config->mtu)
943                mtu = config->mtu;
944        else
945                mtu = ETHERMTU;
946
947        /*
948         * Set up network interface values
949         */
950        ifp->if_softc = cpd;
951        ifp->if_unit = unitNumber;
952        ifp->if_name = unitName;
953        ifp->if_mtu = mtu;
954        ifp->if_init = smc91111_init;
955        ifp->if_ioctl = smc91111_ioctl;
956        ifp->if_start = smc91111_start;
957        ifp->if_output = ether_output;
958        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
959        if (ifp->if_snd.ifq_maxlen == 0)
960                ifp->if_snd.ifq_maxlen = ifqmaxlen;
961
962        /*
963         * Attach the interface
964         */
965        if_attach(ifp);
966        ether_ifattach(ifp);
967
968#ifdef DEBUG
969        printf("SMC91111 : driver has been attached\n");
970#endif
971
972        return 1;
973};
974
975/* \ ------------- Initialization ------------- \ */
976
977/*
978 * Initialize and start the device
979 */
980static void smc91111_init(void *arg)
981{
982        struct lan91cxx_priv_data *cpd = arg;
983        struct ifnet *ifp = &cpd->arpcom.ac_if;
984        DEBUG_FUNCTION();
985
986        if (cpd->txDaemonTid == 0) {
987
988                lan91cxx_hardware_init(cpd);
989                lan91cxx_start(ifp);
990
991                cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
992                                                        smc91111_rxDaemon, cpd);
993                cpd->txDaemonTid =
994                    rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
995        }
996
997        /*
998         * Tell the world that we're running.
999         */
1000        ifp->if_flags |= IFF_RUNNING;
1001}
1002
1003/*
1004 * Stop the device
1005 */
1006static void smc91111_stop(struct lan91cxx_priv_data *cpd)
1007{
1008        struct ifnet *ifp = &cpd->arpcom.ac_if;
1009        DEBUG_FUNCTION();
1010
1011        ifp->if_flags &= ~IFF_RUNNING;
1012
1013        /* Reset chip */
1014        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1015        put_reg(cpd, LAN91CXX_RCR, 0);
1016        cpd->txbusy = cpd->within_send = 0;
1017
1018}
1019
1020int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
1021{
1022        unsigned short val;
1023        int i;
1024
1025        DEBUG_FUNCTION();
1026
1027        cpd->txbusy = cpd->within_send = 0;
1028
1029        /* install interrupt vector */
1030        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1031        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1032
1033        /* Reset chip */
1034        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1035        put_reg(cpd, LAN91CXX_RCR, 0);
1036        HAL_DELAY_US(100000);
1037        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1038        put_reg(cpd, LAN91CXX_RCR, 0);
1039        put_reg(cpd, LAN91CXX_TCR, 0);
1040        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1041
1042        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1043        /* probe chip by reading the signature in BS register */
1044        val = get_banksel(cpd);
1045        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1046                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1047
1048        if ((0xff00 & val) != 0x3300) {
1049                printf("No 91Cxx signature");
1050                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1051                return 0;
1052        }
1053
1054        val = get_reg(cpd, LAN91CXX_REVISION);
1055
1056        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1057                   (val >> 4) & 0xf, val & 0xf);
1058
1059        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1060        cpd->c111_reva = (val == 0x3390);
1061
1062        /* The controller may provide a function used to set up the ESA */
1063        if (cpd->config_enaddr)
1064                (*cpd->config_enaddr) (cpd);
1065
1066        db9_printf("LAN91CXX - status: %04x\n", val);
1067        /* Use statically configured ESA from the private data */
1068        db9_printf
1069            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1070             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1071             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1072        /* Set up hardware address */
1073        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1074                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1075                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1076
1077        return 1;
1078}
1079
1080/*
1081  This function is called to "start up" the interface.  It may be called
1082  multiple times, even when the hardware is already running.  It will be
1083  called whenever something "hardware oriented" changes and should leave
1084  the hardware ready to send/receive packets.
1085*/
1086static void lan91cxx_start(struct ifnet *ifp)
1087{
1088        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1089
1090        uint16_t intr;
1091        uint16_t phy_ctl;
1092        int delay;
1093        DEBUG_FUNCTION();
1094
1095        HAL_DELAY_US(100000);
1096
1097        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1098        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1099        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1100        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1101
1102        /* Start auto-negotiation */
1103        put_reg(cpd, LAN91CXX_RPCR,
1104                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1105                LAN91CXX_RPCR_ANEG);
1106        cpd->rpc_cur_mode =
1107            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1108            LAN91CXX_RPCR_ANEG;
1109
1110        /* wait for auto-negotiation to finish. */
1111        /* give it ~5 seconds before giving up (no cable?) */
1112        delay = 50;
1113        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1114                if (--delay <= 0) {
1115                        printf("Timeout autonegotiation\n");
1116                        break;
1117                }
1118                HAL_DELAY_US(100000);
1119        }
1120
1121        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1122
1123        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1124        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1125        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1126                (LAN91CXX_INTERRUPT_TX_INT |
1127                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1128                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1129        put_reg(cpd, LAN91CXX_RCR,
1130                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1131                LAN91CXX_RCR_ALMUL);
1132        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1133        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1134        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1135                LAN91CXX_INTERRUPT_RCV_INT_M);
1136
1137        if ((0
1138#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1139             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1140#endif
1141            ) || (ifp->if_flags & IFF_PROMISC)
1142            ) {
1143                /* Then we select promiscuous mode. */
1144                unsigned short rcr;
1145                rcr = get_reg(cpd, LAN91CXX_RCR);
1146                rcr |= LAN91CXX_RCR_PRMS;
1147                put_reg(cpd, LAN91CXX_RCR, rcr);
1148        }
1149}
1150
1151/* \ ------------- Probe ------------- \ */
1152
1153static const char *chip_ids[15] = {
1154        NULL, NULL, NULL,
1155        /* 3 */ "SMC91C90/91C92",
1156        /* 4 */ "SMC91C94",
1157        /* 5 */ "SMC91C95",
1158        /* 6 */ "SMC91C96",
1159        /* 7 */ "SMC91C100",
1160        /* 8 */ "SMC91C100FD",
1161        /* 9 */ "SMC91C11xFD",
1162        NULL, NULL,
1163        NULL, NULL, NULL
1164};
1165
1166static int smc_probe(struct lan91cxx_priv_data *cpd)
1167{
1168        unsigned short bank;
1169        unsigned short revision_register;
1170
1171        DEBUG_FUNCTION();
1172
1173        /* First, see if the high byte is 0x33 */
1174        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1175        bank = CYG_LE16_TO_CPU(bank);
1176        if ((bank & 0xFF00) != 0x3300) {
1177                db_printf("<1>Smc probe bank check 1 failed.\n");
1178                return -ENODEV;
1179        }
1180        /* The above MIGHT indicate a device, but I need to write to further
1181           test this.  */
1182        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1183        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1184        bank = CYG_LE16_TO_CPU(bank);
1185        if ((bank & 0xFF00) != 0x3300) {
1186                db_printf("<1>Smc probe bank check 2 failed.\n");
1187                return -ENODEV;
1188        }
1189#if SMC_DEBUG > 3
1190        {
1191                unsigned short bank16, bank16_0, bank16_1;
1192                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1193                bank = CYG_LE16_TO_CPU(bank);
1194                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1195                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1196
1197                db_printf
1198                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1199                db_printf
1200                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1201                     bank16_0);
1202                db_printf
1203                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1204                     bank16_1);
1205        }
1206#endif
1207
1208        /*  check if the revision register is something that I recognize.
1209           These might need to be added to later, as future revisions
1210           could be added.  */
1211        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1212        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1213                /* I don't recognize this chip, so... */
1214                db_printf
1215                    ("smc_probe: IO %x: Unrecognized revision register:"
1216                     " %x, Contact author. \n", (unsigned int)cpd->base,
1217                     revision_register);
1218
1219                return -ENODEV;
1220        }
1221        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1222                  revision_register,
1223                  chip_ids[(revision_register >> 4) & 0xF],
1224                  revision_register & 0xf);
1225
1226        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1227        if (revision_register == 0x3390) {
1228                db_printf("!Revision A\n");
1229        }
1230
1231        return 0;
1232}
1233
1234#if 0
1235/* \ ------------- PHY read/write ------------- \ */
1236/*Sets the PHY to a configuration as determined by the user*/
1237static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1238{
1239        int my_fixed_caps;
1240        int cfg1;
1241
1242        DEBUG_FUNCTION();
1243        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1244                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1245
1246        /* Enter Link Disable state */
1247        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1248        cfg1 |= PHY_CFG1_LNKDIS;
1249        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1250
1251        /* Set our fixed capabilities, Disable auto-negotiation */
1252        my_fixed_caps = 0;
1253
1254        if (cpd->config.ctl_rfduplx)
1255                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1256
1257        if (cpd->config.ctl_rspeed == 100)
1258                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1259
1260        /* Write capabilities to the phy control register */
1261        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1262
1263        /* Re-Configure the Receive/Phy Control register */
1264        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1265
1266        return (1);
1267}
1268#endif
1269
1270#if 0
1271/*Configures the specified PHY using Autonegotiation. */
1272static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1273{
1274
1275        unsigned int phyaddr;
1276        unsigned int my_phy_caps;       /* My PHY capabilities */
1277        unsigned int my_ad_caps;        /* My Advertised capabilities */
1278        unsigned int status = 0;
1279        int failed = 0, delay;
1280
1281        DEBUG_FUNCTION();
1282
1283        /* Set the blocking flag */
1284        cpd->autoneg_active = 1;
1285
1286        /* Get the detected phy address */
1287        phyaddr = cpd->phyaddr;
1288
1289        /* Reset the PHY, setting all other bits to zero */
1290        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1291
1292        /* Wait for the reset to complete, or time out */
1293        delay = 50;
1294        while (delay--) {
1295                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1296                      & PHY_CNTL_RST)) {
1297                        break;
1298                }
1299                HAL_DELAY_US(100000);
1300        }
1301
1302        if (delay < 1) {
1303                db_printf("smc91111:!PHY reset timed out\n");
1304                goto smc_phy_configure_exit;
1305        }
1306
1307        /* Read PHY Register 18, Status Output */
1308        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1309
1310        /* Enable PHY Interrupts (for register 18) */
1311        /* Interrupts listed here are disabled */
1312        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1313                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1314                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1315                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1316
1317        /* Configure the Receive/Phy Control register */
1318        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1319
1320        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1321        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1322        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1323
1324        if (my_phy_caps & PHY_STAT_CAP_T4)
1325                my_ad_caps |= PHY_AD_T4;
1326
1327        if (my_phy_caps & PHY_STAT_CAP_TXF)
1328                my_ad_caps |= PHY_AD_TX_FDX;
1329
1330        if (my_phy_caps & PHY_STAT_CAP_TXH)
1331                my_ad_caps |= PHY_AD_TX_HDX;
1332
1333        if (my_phy_caps & PHY_STAT_CAP_TF)
1334                my_ad_caps |= PHY_AD_10_FDX;
1335
1336        if (my_phy_caps & PHY_STAT_CAP_TH)
1337                my_ad_caps |= PHY_AD_10_HDX;
1338
1339        /* Disable capabilities not selected by our user */
1340        if (cpd->config.ctl_rspeed != 100) {
1341                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1342        }
1343
1344        if (!cpd->config.ctl_rfduplx) {
1345                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1346        }
1347
1348        /* Update our Auto-Neg Advertisement Register */
1349        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1350
1351        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1352        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1353
1354        /* If the user requested no auto neg, then go set his request */
1355        if (!(cpd->config.ctl_autoneg)) {
1356                lan91cxx_phy_fixed(cpd);
1357
1358                goto smc_phy_configure_exit;
1359        }
1360
1361        /* Restart auto-negotiation process in order to advertise my caps */
1362        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1363                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1364
1365        /* wait for auto-negotiation to finish. */
1366        /* give it ~5 seconds before giving up (no cable?) */
1367        delay = 50;
1368        while (!
1369               ((status =
1370                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1371                if (--delay <= 0) {
1372                        printf("Timeout autonegotiation\n");
1373                        failed = 1;
1374                        break;
1375                }
1376
1377                /* Restart auto-negotiation if remote fault */
1378                if (status & PHY_STAT_REM_FLT) {
1379                        db_printf("smc91111:PHY remote fault detected\n");
1380
1381                        /* Restart auto-negotiation */
1382                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1383                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1384                                           PHY_CNTL_ANEG_EN |
1385                                           PHY_CNTL_ANEG_RST |
1386                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1387                }
1388                HAL_DELAY_US(100000);
1389        }
1390
1391        /* Fail if we detected an auto-negotiate remote fault */
1392        if (status & PHY_STAT_REM_FLT) {
1393                db_printf("smc91111:PHY remote fault detected\n");
1394                failed = 1;
1395        }
1396
1397        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1398
1399        /* Set our sysctl parameters to match auto-negotiation results */
1400        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1401                db_printf("smc91111:PHY 100BaseT\n");
1402                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1403        } else {
1404                db_printf("smc91111:PHY 10BaseT\n");
1405                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1406        }
1407
1408        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1409                db_printf("smc91111:PHY Full Duplex\n");
1410                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1411        } else {
1412                db_printf("smc91111:PHY Half Duplex\n");
1413                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1414        }
1415
1416        /* Re-Configure the Receive/Phy Control register */
1417        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1418
1419      smc_phy_configure_exit:
1420
1421        /* Exit auto-negotiation */
1422        cpd->autoneg_active = 0;
1423}
1424#endif
1425
1426static uint16_t
1427lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1428                  uint8_t phyreg)
1429{
1430        int i, mask, input_idx, clk_idx = 0;
1431        uint16_t mii_reg, value;
1432        uint8_t bits[64];
1433
1434        /* 32 consecutive ones on MDO to establish sync */
1435        for (i = 0; i < 32; ++i)
1436                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1437
1438        /* Start code <01> */
1439        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1440        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1441
1442        /* Read command <10> */
1443        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1444        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1445
1446        /* Output the PHY address, msb first */
1447        for (mask = 0x10; mask; mask >>= 1) {
1448                if (phyaddr & mask)
1449                        bits[clk_idx++] =
1450                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1451                else
1452                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1453        }
1454
1455        /* Output the phy register number, msb first */
1456        for (mask = 0x10; mask; mask >>= 1) {
1457                if (phyreg & mask)
1458                        bits[clk_idx++] =
1459                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1460                else
1461                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1462        }
1463
1464        /* Tristate and turnaround (1 bit times) */
1465        bits[clk_idx++] = 0;
1466
1467        /* Input starts at this bit time */
1468        input_idx = clk_idx;
1469
1470        /* Will input 16 bits */
1471        for (i = 0; i < 16; ++i)
1472                bits[clk_idx++] = 0;
1473
1474        /* Final clock bit */
1475        bits[clk_idx++] = 0;
1476
1477        /* Get the current MII register value */
1478        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1479
1480        /* Turn off all MII Interface bits */
1481        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1482                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1483        HAL_DELAY_US(50);
1484
1485        /* Clock all 64 cycles */
1486        for (i = 0; i < sizeof(bits); ++i) {
1487                /* Clock Low - output data */
1488                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1489                HAL_DELAY_US(50);
1490
1491                /* Clock Hi - input data */
1492                put_reg(cpd, LAN91CXX_MGMT,
1493                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1494                HAL_DELAY_US(50);
1495
1496                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1497        }
1498
1499        /* Return to idle state */
1500        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1501        HAL_DELAY_US(50);
1502
1503        /* Recover input data */
1504        for (value = 0, i = 0; i < 16; ++i) {
1505                value <<= 1;
1506                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1507                        value |= 1;
1508        }
1509
1510        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1511        return value;
1512}
1513
1514static void
1515lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1516                   uint8_t phyreg, uint16_t value)
1517{
1518        int i, mask, clk_idx = 0;
1519        uint16_t mii_reg;
1520        uint8_t bits[65];
1521
1522        /* 32 consecutive ones on MDO to establish sync */
1523        for (i = 0; i < 32; ++i)
1524                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1525
1526        /* Start code <01> */
1527        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1528        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1529
1530        /* Write command <01> */
1531        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1532        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1533
1534        /* Output the PHY address, msb first */
1535        for (mask = 0x10; mask; mask >>= 1) {
1536                if (phyaddr & mask)
1537                        bits[clk_idx++] =
1538                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1539                else
1540                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1541        }
1542
1543        /* Output the phy register number, msb first */
1544        for (mask = 0x10; mask; mask >>= 1) {
1545                if (phyreg & mask)
1546                        bits[clk_idx++] =
1547                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1548                else
1549                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1550        }
1551
1552        /* Tristate and turnaround (2 bit times) */
1553        bits[clk_idx++] = 0;
1554        bits[clk_idx++] = 0;
1555
1556        /* Write out 16 bits of data, msb first */
1557        for (mask = 0x8000; mask; mask >>= 1) {
1558                if (value & mask)
1559                        bits[clk_idx++] =
1560                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1561                else
1562                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1563        }
1564
1565        /* Final clock bit (tristate) */
1566        bits[clk_idx++] = 0;
1567
1568        /* Get the current MII register value */
1569        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1570
1571        /* Turn off all MII Interface bits */
1572        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1573                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1574        HAL_DELAY_US(50);
1575
1576        /* Clock all cycles */
1577        for (i = 0; i < sizeof(bits); ++i) {
1578                /* Clock Low - output data */
1579                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1580                HAL_DELAY_US(50);
1581
1582                /* Clock Hi - input data */
1583                put_reg(cpd, LAN91CXX_MGMT,
1584                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1585                HAL_DELAY_US(50);
1586
1587/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1588        }
1589
1590        /* Return to idle state */
1591        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1592        HAL_DELAY_US(50);
1593
1594        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1595}
1596
1597#endif
Note: See TracBrowser for help on using the repository browser.