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

4.115
Last change on this file since b907a78b was b907a78b, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 30, 2011 at 1:16:35 PM

2011-08-30 Sebastian Huber <sebastian.huber@…>

  • libchip/network/smc91111exp.h, libchip/network/smc91111.c: Use BSP_FEATURE_IRQ_EXTENSION define.
  • 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 success = 1;
720        int saved_packet;
721
722        DEBUG_FUNCTION();
723
724        INCR_STAT(cpd, tx_complete);
725
726        saved_packet = get_reg(cpd, LAN91CXX_PNR);
727
728        /* Ack and mask TX interrupt set */
729        /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
730           ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
731           ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
732           put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
733
734        /* Get number of completed packet and read the status word */
735        packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
736        db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
737
738        {
739                unsigned short reg;
740
741                reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
742
743                /* Covering each bit in turn... */
744                if (reg & LAN91CXX_STATUS_TX_UNRN)
745                        INCR_STAT(cpd, tx_underrun);
746                if (reg & LAN91CXX_STATUS_LOST_CARR)
747                        INCR_STAT(cpd, tx_carrier_loss);
748                if (reg & LAN91CXX_STATUS_LATCOL)
749                        INCR_STAT(cpd, tx_late_collisions);
750                if (reg & LAN91CXX_STATUS_TX_DEFR)
751                        INCR_STAT(cpd, tx_deferred);
752                if (reg & LAN91CXX_STATUS_SQET)
753                        INCR_STAT(cpd, tx_sqetesterrors);
754                if (reg & LAN91CXX_STATUS_16COL)
755                        INCR_STAT(cpd, tx_max_collisions);
756                if (reg & LAN91CXX_STATUS_MUL_COL)
757                        INCR_STAT(cpd, tx_mult_collisions);
758                if (reg & LAN91CXX_STATUS_SNGL_COL)
759                        INCR_STAT(cpd, tx_single_collisions);
760                if (reg & LAN91CXX_STATUS_TX_SUC)
761                        INCR_STAT(cpd, tx_good);
762
763                cpd->stats.tx_total_collisions =
764                    cpd->stats.tx_late_collisions +
765                    cpd->stats.tx_max_collisions +
766                    cpd->stats.tx_mult_collisions +
767                    cpd->stats.tx_single_collisions;
768
769                /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
770                   because it just mimics the info we already have above. */
771        }
772
773        /* We do not really care about Tx failure.  Ethernet is not a reliable
774           medium.  But we do care about the TX engine stopping. */
775        tcr = get_reg(cpd, LAN91CXX_TCR);
776        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
777                db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
778                tcr |= LAN91CXX_TCR_TXENA;
779                put_reg(cpd, LAN91CXX_TCR, tcr);
780                success = 0;    /* And treat this as an error... */
781        }
782
783        packet &= 0xff;
784
785        /* and then free the packet */
786        put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
787        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
788
789        while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
790        /* Don't change Packet Number Reg until busy bit is cleared */
791        /* Per LAN91C111 Spec, Page 50 */
792        put_reg(cpd, LAN91CXX_PNR, saved_packet);
793
794}
795
796/* \ ------------- Helpers ------------- \ */
797
798/*
799 * Show interface statistics
800 */
801static void smc91111_stats(struct lan91cxx_priv_data *priv)
802{
803        printf("tx_good             :%-8d\n", priv->stats.tx_good);
804        printf("tx_max_collisions   :%-8d\n", priv->stats.tx_max_collisions);
805        printf("tx_late_collisions  :%-8d\n", priv->stats.tx_late_collisions);
806        printf("tx_underrun         :%-8d\n", priv->stats.tx_underrun);
807        printf("tx_carrier_loss     :%-8d\n", priv->stats.tx_carrier_loss);
808        printf("tx_deferred         :%-8d\n", priv->stats.tx_deferred);
809        printf("tx_sqetesterrors    :%-8d\n", priv->stats.tx_sqetesterrors);
810        printf("tx_single_collisions:%-8d\n", priv->stats.tx_single_collisions);
811        printf("tx_mult_collisions  :%-8d\n", priv->stats.tx_mult_collisions);
812        printf("tx_total_collisions :%-8d\n", priv->stats.tx_total_collisions);
813        printf("rx_good             :%-8d\n", priv->stats.rx_good);
814        printf("rx_crc_errors       :%-8d\n", priv->stats.rx_crc_errors);
815        printf("rx_align_errors     :%-8d\n", priv->stats.rx_align_errors);
816        printf("rx_resource_errors  :%-8d\n", priv->stats.rx_resource_errors);
817        printf("rx_overrun_errors   :%-8d\n", priv->stats.rx_overrun_errors);
818        printf("rx_collisions       :%-8d\n", priv->stats.rx_collisions);
819        printf("rx_short_frames     :%-8d\n", priv->stats.rx_short_frames);
820        printf("rx_too_long_frames  :%-8d\n", priv->stats.rx_too_long_frames);
821        printf("rx_symbol_errors    :%-8d\n", priv->stats.rx_symbol_errors);
822        printf("interrupts          :%-8d\n", priv->stats.interrupts);
823        printf("rx_count            :%-8d\n", priv->stats.rx_count);
824        printf("rx_deliver          :%-8d\n", priv->stats.rx_deliver);
825        printf("rx_resource         :%-8d\n", priv->stats.rx_resource);
826        printf("rx_restart          :%-8d\n", priv->stats.rx_restart);
827        printf("tx_count            :%-8d\n", priv->stats.tx_count);
828        printf("tx_complete         :%-8d\n", priv->stats.tx_complete);
829        printf("tx_dropped          :%-8d\n", priv->stats.tx_dropped);
830}
831
832/*
833 * Driver ioctl handler
834 */
835static int smc91111_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
836{
837        struct lan91cxx_priv_data *cpd = ifp->if_softc;
838        int error = 0;
839        DEBUG_FUNCTION();
840
841        switch (command) {
842        case SIOCGIFADDR:
843        case SIOCSIFADDR:
844                db_printf("SIOCSIFADDR\n");
845                ether_ioctl(ifp, command, data);
846                break;
847
848        case SIOCSIFFLAGS:
849                db_printf("SIOCSIFFLAGS\n");
850                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
851                case IFF_RUNNING:
852                        smc91111_stop(cpd);
853                        break;
854
855                case IFF_UP:
856                        smc91111_init(cpd);
857                        break;
858
859                case IFF_UP | IFF_RUNNING:
860                        smc91111_stop(cpd);
861                        smc91111_init(cpd);
862                        break;
863
864                default:
865                        break;
866                }
867                break;
868
869        case SIO_RTEMS_SHOW_STATS:
870                db_printf("SIO_RTEMS_SHOW_STATS\n");
871                smc91111_stats(cpd);
872                break;
873
874                /*
875                 * FIXME: All sorts of multicast commands need to be added here!
876                 */
877        default:
878                error = EINVAL;
879                break;
880        }
881
882        return error;
883}
884
885/*
886 * Attach an SMC91111 driver to the system
887 */
888int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
889                                  struct scmv91111_configuration * chip)
890{
891        struct ifnet *ifp;
892        struct lan91cxx_priv_data *cpd;
893        int unitNumber;
894        char *unitName;
895        int mtu;
896        DEBUG_FUNCTION();
897
898#if 0
899        /* activate io area */
900        switch (sparc_leon23_get_psr_version()) {
901        case 0:
902        case 2:
903                db_printf("Activating Leon2 io port\n");
904                /*configure pio */
905                *((volatile unsigned int *)0x80000000) |= 0x10f80000;
906                *((volatile unsigned int *)0x800000A8) |=
907                    (0xe0 | chip->vector) << (8 * (chip->pio - 4));
908                break;
909        default:
910                {
911                        unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl;
912                        if ((addr_pio = amba_find_apbslv_addr(VENDOR_GAISLER,
913                                                   GAISLER_PIOPORT, &irq_pio))
914                            && (addr_mctrl =
915                                amba_find_apbslv_addr(VENDOR_ESA, ESA_MCTRL, &irq_mctrl))) {
916                                LEON3_IOPORT_Regs_Map *io =
917                                    (LEON3_IOPORT_Regs_Map *) addr_pio;
918                                db_printf
919                                    ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n",
920                                     (unsigned int)addr_pio,
921                                     (unsigned int)addr_mctrl);
922                                *((volatile unsigned int *)addr_mctrl) |= 0x10f80000;   /*mctrl ctrl 1 */
923                                io->irqmask |= (1 << chip->pio);
924                                io->irqpol |= (1 << chip->pio);
925                                io->irqedge |= (1 << chip->pio);
926                                io->iodir &= ~(1 << chip->pio);
927                        } else {
928                                return 0;
929                        }
930                }
931        }
932#endif
933
934        /* parse driver name */
935        if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
936                db_printf("Unitnumber < 0: %d\n", unitNumber);
937                return 0;
938        }
939
940        db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
941
942        cpd = &smc91111;
943        ifp = &cpd->arpcom.ac_if;
944        memset(cpd, 0, sizeof(*cpd));
945
946        cpd->config = *chip;
947        cpd->base = chip->baseaddr;
948
949        if (smc_probe(cpd)) {
950                return 0;
951        }
952
953        if (config->hardware_address) {
954                memcpy(cpd->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
955        } else {
956#ifdef SMC91111_ENADDR_IS_SETUP
957        /* The address was put in the chip at reset time.  Retrieve it. */
958        int i;
959        for (i = 0; i < sizeof(cpd->enaddr); i += 2) {
960            unsigned short r = get_reg(cpd, LAN91CXX_IA01 + i / 2);
961            cpd->arpcom.ac_enaddr[i] = r;
962            cpd->arpcom.ac_enaddr[i+1] = r >> 8;
963        }
964#else
965                /* dummy default address */
966                cpd->arpcom.ac_enaddr[0] = 0x12;
967                cpd->arpcom.ac_enaddr[1] = 0x13;
968                cpd->arpcom.ac_enaddr[2] = 0x14;
969                cpd->arpcom.ac_enaddr[3] = 0x15;
970                cpd->arpcom.ac_enaddr[4] = 0x16;
971                cpd->arpcom.ac_enaddr[5] = 0x17;
972#endif
973        }
974
975        cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
976        cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
977        cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
978        cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
979        cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
980        cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
981        cpd->rpc_cur_mode =
982            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
983            LAN91CXX_RPCR_ANEG;
984
985        if (config->mtu)
986                mtu = config->mtu;
987        else
988                mtu = ETHERMTU;
989
990        /*
991         * Set up network interface values
992         */
993        ifp->if_softc = cpd;
994        ifp->if_unit = unitNumber;
995        ifp->if_name = unitName;
996        ifp->if_mtu = mtu;
997        ifp->if_init = smc91111_init;
998        ifp->if_ioctl = smc91111_ioctl;
999        ifp->if_start = smc91111_start;
1000        ifp->if_output = ether_output;
1001        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1002        if (ifp->if_snd.ifq_maxlen == 0)
1003                ifp->if_snd.ifq_maxlen = ifqmaxlen;
1004
1005        /*
1006         * Attach the interface
1007         */
1008        if_attach(ifp);
1009        ether_ifattach(ifp);
1010
1011#ifdef DEBUG
1012        printf("SMC91111 : driver has been attached\n");
1013#endif
1014
1015        return 1;
1016};
1017
1018/* \ ------------- Initialization ------------- \ */
1019
1020/*
1021 * Initialize and start the device
1022 */
1023static void smc91111_init(void *arg)
1024{
1025        struct lan91cxx_priv_data *cpd = arg;
1026        struct ifnet *ifp = &cpd->arpcom.ac_if;
1027        DEBUG_FUNCTION();
1028
1029        if (cpd->txDaemonTid == 0) {
1030
1031                lan91cxx_hardware_init(cpd);
1032                lan91cxx_start(ifp);
1033
1034                cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
1035                                                        smc91111_rxDaemon, cpd);
1036                cpd->txDaemonTid =
1037                    rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
1038        } else {
1039                lan91cxx_start(ifp);
1040        }
1041
1042        /*
1043         * Tell the world that we're running.
1044         */
1045        ifp->if_flags |= IFF_RUNNING;
1046}
1047
1048/*
1049 * Stop the device
1050 */
1051static void smc91111_stop(struct lan91cxx_priv_data *cpd)
1052{
1053        struct ifnet *ifp = &cpd->arpcom.ac_if;
1054        DEBUG_FUNCTION();
1055
1056        ifp->if_flags &= ~IFF_RUNNING;
1057
1058        /* Reset chip */
1059        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1060        put_reg(cpd, LAN91CXX_RCR, 0);
1061        cpd->txbusy = cpd->within_send = 0;
1062
1063}
1064
1065int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
1066{
1067        unsigned short val;
1068        int i;
1069
1070        DEBUG_FUNCTION();
1071
1072        cpd->txbusy = cpd->within_send = 0;
1073
1074        /* install interrupt vector */
1075#ifdef BSP_FEATURE_IRQ_EXTENSION
1076        {
1077                rtems_status_code sc = RTEMS_SUCCESSFUL;
1078
1079                sc = rtems_interrupt_handler_install(
1080                        cpd->config.vector,
1081                        cpd->config.info,
1082                        cpd->config.options,
1083                        cpd->config.interrupt_wrapper,
1084                        cpd->config.arg
1085                );
1086                if (sc != RTEMS_SUCCESSFUL) {
1087                        printf("rtems_interrupt_handler_install returned %d.\n", sc);
1088                        return 0;
1089                }
1090        }
1091#else
1092        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1093        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1094#endif
1095
1096        /* Reset chip */
1097        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1098        put_reg(cpd, LAN91CXX_RCR, 0);
1099        HAL_DELAY_US(100000);
1100        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1101        put_reg(cpd, LAN91CXX_RCR, 0);
1102        put_reg(cpd, LAN91CXX_TCR, 0);
1103        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1104
1105        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1106        /* probe chip by reading the signature in BS register */
1107        val = get_banksel(cpd);
1108        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1109                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1110
1111        if ((0xff00 & val) != 0x3300) {
1112                printf("No 91Cxx signature");
1113                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1114                return 0;
1115        }
1116
1117        val = get_reg(cpd, LAN91CXX_REVISION);
1118
1119        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1120                   (val >> 4) & 0xf, val & 0xf);
1121
1122        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1123        cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */
1124
1125        /* The controller may provide a function used to set up the ESA */
1126        if (cpd->config_enaddr)
1127                (*cpd->config_enaddr) (cpd);
1128
1129        db9_printf("LAN91CXX - status: %04x\n", val);
1130        /* Use statically configured ESA from the private data */
1131        db9_printf
1132            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1133             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1134             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1135        /* Set up hardware address */
1136        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1137                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1138                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1139
1140        return 1;
1141}
1142
1143/*
1144  This function is called to "start up" the interface.  It may be called
1145  multiple times, even when the hardware is already running.  It will be
1146  called whenever something "hardware oriented" changes and should leave
1147  the hardware ready to send/receive packets.
1148*/
1149static void lan91cxx_start(struct ifnet *ifp)
1150{
1151        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1152
1153        uint16_t intr;
1154        uint16_t phy_ctl;
1155        int delay;
1156        DEBUG_FUNCTION();
1157
1158        HAL_DELAY_US(100000);
1159
1160        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1161        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1162        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1163        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1164
1165        /* Start auto-negotiation */
1166        put_reg(cpd, LAN91CXX_RPCR,
1167                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1168                LAN91CXX_RPCR_ANEG);
1169        cpd->rpc_cur_mode =
1170            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1171            LAN91CXX_RPCR_ANEG;
1172
1173        /* wait for auto-negotiation to finish. */
1174        /* give it ~5 seconds before giving up (no cable?) */
1175        delay = 50;
1176        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1177                if (--delay <= 0) {
1178                        printf("Timeout autonegotiation\n");
1179                        break;
1180                }
1181                HAL_DELAY_US(100000);
1182        }
1183
1184        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1185
1186        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1187        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1188        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1189                (LAN91CXX_INTERRUPT_TX_INT |
1190                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1191                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1192        put_reg(cpd, LAN91CXX_RCR,
1193                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1194                LAN91CXX_RCR_ALMUL);
1195        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1196        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1197        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1198                LAN91CXX_INTERRUPT_RCV_INT_M);
1199
1200        if ((0
1201#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1202             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1203#endif
1204            ) || (ifp->if_flags & IFF_PROMISC)
1205            ) {
1206                /* Then we select promiscuous mode. */
1207                unsigned short rcr;
1208                rcr = get_reg(cpd, LAN91CXX_RCR);
1209                rcr |= LAN91CXX_RCR_PRMS;
1210                put_reg(cpd, LAN91CXX_RCR, rcr);
1211        }
1212}
1213
1214/* \ ------------- Probe ------------- \ */
1215
1216static const char *chip_ids[15] = {
1217        NULL, NULL, NULL,
1218        /* 3 */ "SMC91C90/91C92",
1219        /* 4 */ "SMC91C94",
1220        /* 5 */ "SMC91C95",
1221        /* 6 */ "SMC91C96",
1222        /* 7 */ "SMC91C100",
1223        /* 8 */ "SMC91C100FD",
1224        /* 9 */ "SMC91C11xFD",
1225        NULL, NULL,
1226        NULL, NULL, NULL
1227};
1228
1229static int smc_probe(struct lan91cxx_priv_data *cpd)
1230{
1231        unsigned short bank;
1232        unsigned short revision_register;
1233
1234        DEBUG_FUNCTION();
1235
1236        /* First, see if the high byte is 0x33 */
1237        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1238        bank = CYG_LE16_TO_CPU(bank);
1239        if ((bank & 0xFF00) != 0x3300) {
1240                db_printf("<1>Smc probe bank check 1 failed.\n");
1241                return -ENODEV;
1242        }
1243        /* The above MIGHT indicate a device, but I need to write to further
1244           test this.  */
1245        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1246        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1247        bank = CYG_LE16_TO_CPU(bank);
1248        if ((bank & 0xFF00) != 0x3300) {
1249                db_printf("<1>Smc probe bank check 2 failed.\n");
1250                return -ENODEV;
1251        }
1252#if SMC_DEBUG > 3
1253        {
1254                unsigned short bank16, bank16_0, bank16_1;
1255                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1256                bank = CYG_LE16_TO_CPU(bank);
1257                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1258                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1259
1260                db_printf
1261                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1262                db_printf
1263                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1264                     bank16_0);
1265                db_printf
1266                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1267                     bank16_1);
1268        }
1269#endif
1270
1271        /*  check if the revision register is something that I recognize.
1272           These might need to be added to later, as future revisions
1273           could be added.  */
1274        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1275        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1276                /* I don't recognize this chip, so... */
1277                db_printf
1278                    ("smc_probe: IO %x: Unrecognized revision register:"
1279                     " %x, Contact author. \n", (unsigned int)cpd->base,
1280                     revision_register);
1281
1282                return -ENODEV;
1283        }
1284        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1285                  revision_register,
1286                  chip_ids[(revision_register >> 4) & 0xF],
1287                  revision_register & 0xf);
1288
1289        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1290        if (revision_register == 0x3390) {
1291                db_printf("!Revision A\n");
1292        }
1293
1294        return 0;
1295}
1296
1297#if 0
1298/* \ ------------- PHY read/write ------------- \ */
1299/*Sets the PHY to a configuration as determined by the user*/
1300static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1301{
1302        int my_fixed_caps;
1303        int cfg1;
1304
1305        DEBUG_FUNCTION();
1306        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1307                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1308
1309        /* Enter Link Disable state */
1310        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1311        cfg1 |= PHY_CFG1_LNKDIS;
1312        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1313
1314        /* Set our fixed capabilities, Disable auto-negotiation */
1315        my_fixed_caps = 0;
1316
1317        if (cpd->config.ctl_rfduplx)
1318                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1319
1320        if (cpd->config.ctl_rspeed == 100)
1321                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1322
1323        /* Write capabilities to the phy control register */
1324        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1325
1326        /* Re-Configure the Receive/Phy Control register */
1327        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1328
1329        return (1);
1330}
1331#endif
1332
1333#if 0
1334/*Configures the specified PHY using Autonegotiation. */
1335static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1336{
1337
1338        unsigned int phyaddr;
1339        unsigned int my_phy_caps;       /* My PHY capabilities */
1340        unsigned int my_ad_caps;        /* My Advertised capabilities */
1341        unsigned int status = 0;
1342        int failed = 0, delay;
1343
1344        DEBUG_FUNCTION();
1345
1346        /* Set the blocking flag */
1347        cpd->autoneg_active = 1;
1348
1349        /* Get the detected phy address */
1350        phyaddr = cpd->phyaddr;
1351
1352        /* Reset the PHY, setting all other bits to zero */
1353        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1354
1355        /* Wait for the reset to complete, or time out */
1356        delay = 50;
1357        while (delay--) {
1358                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1359                      & PHY_CNTL_RST)) {
1360                        break;
1361                }
1362                HAL_DELAY_US(100000);
1363        }
1364
1365        if (delay < 1) {
1366                db_printf("smc91111:!PHY reset timed out\n");
1367                goto smc_phy_configure_exit;
1368        }
1369
1370        /* Read PHY Register 18, Status Output */
1371        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1372
1373        /* Enable PHY Interrupts (for register 18) */
1374        /* Interrupts listed here are disabled */
1375        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1376                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1377                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1378                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1379
1380        /* Configure the Receive/Phy Control register */
1381        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1382
1383        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1384        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1385        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1386
1387        if (my_phy_caps & PHY_STAT_CAP_T4)
1388                my_ad_caps |= PHY_AD_T4;
1389
1390        if (my_phy_caps & PHY_STAT_CAP_TXF)
1391                my_ad_caps |= PHY_AD_TX_FDX;
1392
1393        if (my_phy_caps & PHY_STAT_CAP_TXH)
1394                my_ad_caps |= PHY_AD_TX_HDX;
1395
1396        if (my_phy_caps & PHY_STAT_CAP_TF)
1397                my_ad_caps |= PHY_AD_10_FDX;
1398
1399        if (my_phy_caps & PHY_STAT_CAP_TH)
1400                my_ad_caps |= PHY_AD_10_HDX;
1401
1402        /* Disable capabilities not selected by our user */
1403        if (cpd->config.ctl_rspeed != 100) {
1404                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1405        }
1406
1407        if (!cpd->config.ctl_rfduplx) {
1408                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1409        }
1410
1411        /* Update our Auto-Neg Advertisement Register */
1412        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1413
1414        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1415        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1416
1417        /* If the user requested no auto neg, then go set his request */
1418        if (!(cpd->config.ctl_autoneg)) {
1419                lan91cxx_phy_fixed(cpd);
1420
1421                goto smc_phy_configure_exit;
1422        }
1423
1424        /* Restart auto-negotiation process in order to advertise my caps */
1425        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1426                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1427
1428        /* wait for auto-negotiation to finish. */
1429        /* give it ~5 seconds before giving up (no cable?) */
1430        delay = 50;
1431        while (!
1432               ((status =
1433                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1434                if (--delay <= 0) {
1435                        printf("Timeout autonegotiation\n");
1436                        failed = 1;
1437                        break;
1438                }
1439
1440                /* Restart auto-negotiation if remote fault */
1441                if (status & PHY_STAT_REM_FLT) {
1442                        db_printf("smc91111:PHY remote fault detected\n");
1443
1444                        /* Restart auto-negotiation */
1445                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1446                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1447                                           PHY_CNTL_ANEG_EN |
1448                                           PHY_CNTL_ANEG_RST |
1449                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1450                }
1451                HAL_DELAY_US(100000);
1452        }
1453
1454        /* Fail if we detected an auto-negotiate remote fault */
1455        if (status & PHY_STAT_REM_FLT) {
1456                db_printf("smc91111:PHY remote fault detected\n");
1457                failed = 1;
1458        }
1459
1460        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1461
1462        /* Set our sysctl parameters to match auto-negotiation results */
1463        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1464                db_printf("smc91111:PHY 100BaseT\n");
1465                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1466        } else {
1467                db_printf("smc91111:PHY 10BaseT\n");
1468                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1469        }
1470
1471        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1472                db_printf("smc91111:PHY Full Duplex\n");
1473                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1474        } else {
1475                db_printf("smc91111:PHY Half Duplex\n");
1476                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1477        }
1478
1479        /* Re-Configure the Receive/Phy Control register */
1480        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1481
1482      smc_phy_configure_exit:
1483
1484        /* Exit auto-negotiation */
1485        cpd->autoneg_active = 0;
1486}
1487#endif
1488
1489static uint16_t
1490lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1491                  uint8_t phyreg)
1492{
1493        int i, mask, input_idx, clk_idx = 0;
1494        uint16_t mii_reg, value;
1495        uint8_t bits[64];
1496
1497        /* 32 consecutive ones on MDO to establish sync */
1498        for (i = 0; i < 32; ++i)
1499                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1500
1501        /* Start code <01> */
1502        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1503        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1504
1505        /* Read command <10> */
1506        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1507        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1508
1509        /* Output the PHY address, msb first */
1510        for (mask = 0x10; mask; mask >>= 1) {
1511                if (phyaddr & mask)
1512                        bits[clk_idx++] =
1513                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1514                else
1515                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1516        }
1517
1518        /* Output the phy register number, msb first */
1519        for (mask = 0x10; mask; mask >>= 1) {
1520                if (phyreg & mask)
1521                        bits[clk_idx++] =
1522                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1523                else
1524                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1525        }
1526
1527        /* Tristate and turnaround (1 bit times) */
1528        bits[clk_idx++] = 0;
1529
1530        /* Input starts at this bit time */
1531        input_idx = clk_idx;
1532
1533        /* Will input 16 bits */
1534        for (i = 0; i < 16; ++i)
1535                bits[clk_idx++] = 0;
1536
1537        /* Final clock bit */
1538        bits[clk_idx++] = 0;
1539
1540        /* Get the current MII register value */
1541        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1542
1543        /* Turn off all MII Interface bits */
1544        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1545                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1546        HAL_DELAY_US(50);
1547
1548        /* Clock all 64 cycles */
1549        for (i = 0; i < sizeof(bits); ++i) {
1550                /* Clock Low - output data */
1551                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1552                HAL_DELAY_US(50);
1553
1554                /* Clock Hi - input data */
1555                put_reg(cpd, LAN91CXX_MGMT,
1556                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1557                HAL_DELAY_US(50);
1558
1559                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1560        }
1561
1562        /* Return to idle state */
1563        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1564        HAL_DELAY_US(50);
1565
1566        /* Recover input data */
1567        for (value = 0, i = 0; i < 16; ++i) {
1568                value <<= 1;
1569                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1570                        value |= 1;
1571        }
1572
1573        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1574        return value;
1575}
1576
1577static void
1578lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1579                   uint8_t phyreg, uint16_t value)
1580{
1581        int i, mask, clk_idx = 0;
1582        uint16_t mii_reg;
1583        uint8_t bits[65];
1584
1585        /* 32 consecutive ones on MDO to establish sync */
1586        for (i = 0; i < 32; ++i)
1587                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1588
1589        /* Start code <01> */
1590        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1591        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1592
1593        /* Write command <01> */
1594        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1595        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1596
1597        /* Output the PHY address, msb first */
1598        for (mask = 0x10; mask; mask >>= 1) {
1599                if (phyaddr & mask)
1600                        bits[clk_idx++] =
1601                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1602                else
1603                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1604        }
1605
1606        /* Output the phy register number, msb first */
1607        for (mask = 0x10; mask; mask >>= 1) {
1608                if (phyreg & mask)
1609                        bits[clk_idx++] =
1610                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1611                else
1612                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1613        }
1614
1615        /* Tristate and turnaround (2 bit times) */
1616        bits[clk_idx++] = 0;
1617        bits[clk_idx++] = 0;
1618
1619        /* Write out 16 bits of data, msb first */
1620        for (mask = 0x8000; mask; mask >>= 1) {
1621                if (value & mask)
1622                        bits[clk_idx++] =
1623                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1624                else
1625                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1626        }
1627
1628        /* Final clock bit (tristate) */
1629        bits[clk_idx++] = 0;
1630
1631        /* Get the current MII register value */
1632        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1633
1634        /* Turn off all MII Interface bits */
1635        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1636                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1637        HAL_DELAY_US(50);
1638
1639        /* Clock all cycles */
1640        for (i = 0; i < sizeof(bits); ++i) {
1641                /* Clock Low - output data */
1642                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1643                HAL_DELAY_US(50);
1644
1645                /* Clock Hi - input data */
1646                put_reg(cpd, LAN91CXX_MGMT,
1647                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1648                HAL_DELAY_US(50);
1649
1650/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1651        }
1652
1653        /* Return to idle state */
1654        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1655        HAL_DELAY_US(50);
1656
1657        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1658}
1659
1660#if 0
1661void lan91cxx_print_bank(int bank){
1662        struct lan91cxx_priv_data *cpd = &smc91111;
1663        int regno;
1664        unsigned short regval[8];
1665        int i;
1666
1667        if ( bank >= 4 )
1668                return;
1669        for(i=0; i<8; i++){
1670                regno=i+bank<<3;
1671                regval[i] = get_reg(cpd, regno);
1672        }
1673        printk("---- BANK %d ----\n\r",bank);
1674        for(i=0; i<8; i++){
1675                printk("0x%x: 0x%x\n\r",i,regval[i]);
1676        }
1677
1678}
1679#endif
1680
1681#endif
Note: See TracBrowser for help on using the repository browser.