source: rtems/c/src/libchip/network/smc91111.c @ ac5b81c3

4.104.114.84.95
Last change on this file since ac5b81c3 was ac5b81c3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/01/06 at 21:20:47

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

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