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

4.115
Last change on this file since d1dbd228 was d1dbd228, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/11/11 at 05:19:13

2011-10-11 Ralf Corsépius <ralf.corsepius@…>

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