source: rtems/c/src/libchip/network/smc91111.c @ 2174c66

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

2011-08-30 Peter Dufault <dufault@…>

  • libchip/network/smc91111.c: Modify to support the MPC5554 using new exceptions. Fix where the networking status is being dumped to a single thousand-character line. Add support for when the chip loaded it's MAC address from a serial chip at reset (the SMC91111_ENADDR_IS_SETUP option). Call lan91cxx_start() every time the the device is initialized. Without this change the chip can not be "upped" once it has been downed.
  • c/src/libchip/network/smc91111.h: Change the "#ifdef expression" to "#if expression".
  • c/src/libchip/network/smc91111exp.h: Add support for new exceptions.
  • 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 _OLD_EXCEPTIONS
63#if defined(__m68k__)
64extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
65#else
66extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
67#endif
68#else
69#include <rtems/irq-extension.h>
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 _OLD_EXCEPTIONS
1076        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1077        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1078#else
1079    {
1080        int r;
1081        if ((r = rtems_interrupt_handler_install(cpd->config.vector,
1082        cpd->config.info,
1083        cpd->config.options,
1084        cpd->config.interrupt_wrapper,
1085        cpd->config.arg) )) {
1086                printf("rtems_interrupt_handler_install returned %d.\n", r);
1087                return 0;
1088        }
1089    }
1090#endif
1091
1092        /* Reset chip */
1093        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1094        put_reg(cpd, LAN91CXX_RCR, 0);
1095        HAL_DELAY_US(100000);
1096        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1097        put_reg(cpd, LAN91CXX_RCR, 0);
1098        put_reg(cpd, LAN91CXX_TCR, 0);
1099        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1100
1101        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1102        /* probe chip by reading the signature in BS register */
1103        val = get_banksel(cpd);
1104        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1105                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1106
1107        if ((0xff00 & val) != 0x3300) {
1108                printf("No 91Cxx signature");
1109                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1110                return 0;
1111        }
1112
1113        val = get_reg(cpd, LAN91CXX_REVISION);
1114
1115        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1116                   (val >> 4) & 0xf, val & 0xf);
1117
1118        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1119        cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */
1120
1121        /* The controller may provide a function used to set up the ESA */
1122        if (cpd->config_enaddr)
1123                (*cpd->config_enaddr) (cpd);
1124
1125        db9_printf("LAN91CXX - status: %04x\n", val);
1126        /* Use statically configured ESA from the private data */
1127        db9_printf
1128            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1129             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1130             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1131        /* Set up hardware address */
1132        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1133                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1134                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1135
1136        return 1;
1137}
1138
1139/*
1140  This function is called to "start up" the interface.  It may be called
1141  multiple times, even when the hardware is already running.  It will be
1142  called whenever something "hardware oriented" changes and should leave
1143  the hardware ready to send/receive packets.
1144*/
1145static void lan91cxx_start(struct ifnet *ifp)
1146{
1147        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1148
1149        uint16_t intr;
1150        uint16_t phy_ctl;
1151        int delay;
1152        DEBUG_FUNCTION();
1153
1154        HAL_DELAY_US(100000);
1155
1156        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1157        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1158        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1159        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1160
1161        /* Start auto-negotiation */
1162        put_reg(cpd, LAN91CXX_RPCR,
1163                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1164                LAN91CXX_RPCR_ANEG);
1165        cpd->rpc_cur_mode =
1166            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1167            LAN91CXX_RPCR_ANEG;
1168
1169        /* wait for auto-negotiation to finish. */
1170        /* give it ~5 seconds before giving up (no cable?) */
1171        delay = 50;
1172        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1173                if (--delay <= 0) {
1174                        printf("Timeout autonegotiation\n");
1175                        break;
1176                }
1177                HAL_DELAY_US(100000);
1178        }
1179
1180        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1181
1182        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1183        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1184        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1185                (LAN91CXX_INTERRUPT_TX_INT |
1186                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1187                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1188        put_reg(cpd, LAN91CXX_RCR,
1189                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1190                LAN91CXX_RCR_ALMUL);
1191        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1192        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1193        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1194                LAN91CXX_INTERRUPT_RCV_INT_M);
1195
1196        if ((0
1197#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1198             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1199#endif
1200            ) || (ifp->if_flags & IFF_PROMISC)
1201            ) {
1202                /* Then we select promiscuous mode. */
1203                unsigned short rcr;
1204                rcr = get_reg(cpd, LAN91CXX_RCR);
1205                rcr |= LAN91CXX_RCR_PRMS;
1206                put_reg(cpd, LAN91CXX_RCR, rcr);
1207        }
1208}
1209
1210/* \ ------------- Probe ------------- \ */
1211
1212static const char *chip_ids[15] = {
1213        NULL, NULL, NULL,
1214        /* 3 */ "SMC91C90/91C92",
1215        /* 4 */ "SMC91C94",
1216        /* 5 */ "SMC91C95",
1217        /* 6 */ "SMC91C96",
1218        /* 7 */ "SMC91C100",
1219        /* 8 */ "SMC91C100FD",
1220        /* 9 */ "SMC91C11xFD",
1221        NULL, NULL,
1222        NULL, NULL, NULL
1223};
1224
1225static int smc_probe(struct lan91cxx_priv_data *cpd)
1226{
1227        unsigned short bank;
1228        unsigned short revision_register;
1229
1230        DEBUG_FUNCTION();
1231
1232        /* First, see if the high byte is 0x33 */
1233        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1234        bank = CYG_LE16_TO_CPU(bank);
1235        if ((bank & 0xFF00) != 0x3300) {
1236                db_printf("<1>Smc probe bank check 1 failed.\n");
1237                return -ENODEV;
1238        }
1239        /* The above MIGHT indicate a device, but I need to write to further
1240           test this.  */
1241        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1242        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1243        bank = CYG_LE16_TO_CPU(bank);
1244        if ((bank & 0xFF00) != 0x3300) {
1245                db_printf("<1>Smc probe bank check 2 failed.\n");
1246                return -ENODEV;
1247        }
1248#if SMC_DEBUG > 3
1249        {
1250                unsigned short bank16, bank16_0, bank16_1;
1251                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1252                bank = CYG_LE16_TO_CPU(bank);
1253                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1254                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1255
1256                db_printf
1257                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1258                db_printf
1259                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1260                     bank16_0);
1261                db_printf
1262                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1263                     bank16_1);
1264        }
1265#endif
1266
1267        /*  check if the revision register is something that I recognize.
1268           These might need to be added to later, as future revisions
1269           could be added.  */
1270        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1271        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1272                /* I don't recognize this chip, so... */
1273                db_printf
1274                    ("smc_probe: IO %x: Unrecognized revision register:"
1275                     " %x, Contact author. \n", (unsigned int)cpd->base,
1276                     revision_register);
1277
1278                return -ENODEV;
1279        }
1280        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1281                  revision_register,
1282                  chip_ids[(revision_register >> 4) & 0xF],
1283                  revision_register & 0xf);
1284
1285        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1286        if (revision_register == 0x3390) {
1287                db_printf("!Revision A\n");
1288        }
1289
1290        return 0;
1291}
1292
1293#if 0
1294/* \ ------------- PHY read/write ------------- \ */
1295/*Sets the PHY to a configuration as determined by the user*/
1296static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1297{
1298        int my_fixed_caps;
1299        int cfg1;
1300
1301        DEBUG_FUNCTION();
1302        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1303                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1304
1305        /* Enter Link Disable state */
1306        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1307        cfg1 |= PHY_CFG1_LNKDIS;
1308        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1309
1310        /* Set our fixed capabilities, Disable auto-negotiation */
1311        my_fixed_caps = 0;
1312
1313        if (cpd->config.ctl_rfduplx)
1314                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1315
1316        if (cpd->config.ctl_rspeed == 100)
1317                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1318
1319        /* Write capabilities to the phy control register */
1320        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1321
1322        /* Re-Configure the Receive/Phy Control register */
1323        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1324
1325        return (1);
1326}
1327#endif
1328
1329#if 0
1330/*Configures the specified PHY using Autonegotiation. */
1331static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1332{
1333
1334        unsigned int phyaddr;
1335        unsigned int my_phy_caps;       /* My PHY capabilities */
1336        unsigned int my_ad_caps;        /* My Advertised capabilities */
1337        unsigned int status = 0;
1338        int failed = 0, delay;
1339
1340        DEBUG_FUNCTION();
1341
1342        /* Set the blocking flag */
1343        cpd->autoneg_active = 1;
1344
1345        /* Get the detected phy address */
1346        phyaddr = cpd->phyaddr;
1347
1348        /* Reset the PHY, setting all other bits to zero */
1349        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1350
1351        /* Wait for the reset to complete, or time out */
1352        delay = 50;
1353        while (delay--) {
1354                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1355                      & PHY_CNTL_RST)) {
1356                        break;
1357                }
1358                HAL_DELAY_US(100000);
1359        }
1360
1361        if (delay < 1) {
1362                db_printf("smc91111:!PHY reset timed out\n");
1363                goto smc_phy_configure_exit;
1364        }
1365
1366        /* Read PHY Register 18, Status Output */
1367        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1368
1369        /* Enable PHY Interrupts (for register 18) */
1370        /* Interrupts listed here are disabled */
1371        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1372                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1373                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1374                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1375
1376        /* Configure the Receive/Phy Control register */
1377        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1378
1379        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1380        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1381        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1382
1383        if (my_phy_caps & PHY_STAT_CAP_T4)
1384                my_ad_caps |= PHY_AD_T4;
1385
1386        if (my_phy_caps & PHY_STAT_CAP_TXF)
1387                my_ad_caps |= PHY_AD_TX_FDX;
1388
1389        if (my_phy_caps & PHY_STAT_CAP_TXH)
1390                my_ad_caps |= PHY_AD_TX_HDX;
1391
1392        if (my_phy_caps & PHY_STAT_CAP_TF)
1393                my_ad_caps |= PHY_AD_10_FDX;
1394
1395        if (my_phy_caps & PHY_STAT_CAP_TH)
1396                my_ad_caps |= PHY_AD_10_HDX;
1397
1398        /* Disable capabilities not selected by our user */
1399        if (cpd->config.ctl_rspeed != 100) {
1400                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1401        }
1402
1403        if (!cpd->config.ctl_rfduplx) {
1404                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1405        }
1406
1407        /* Update our Auto-Neg Advertisement Register */
1408        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1409
1410        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1411        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1412
1413        /* If the user requested no auto neg, then go set his request */
1414        if (!(cpd->config.ctl_autoneg)) {
1415                lan91cxx_phy_fixed(cpd);
1416
1417                goto smc_phy_configure_exit;
1418        }
1419
1420        /* Restart auto-negotiation process in order to advertise my caps */
1421        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1422                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1423
1424        /* wait for auto-negotiation to finish. */
1425        /* give it ~5 seconds before giving up (no cable?) */
1426        delay = 50;
1427        while (!
1428               ((status =
1429                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1430                if (--delay <= 0) {
1431                        printf("Timeout autonegotiation\n");
1432                        failed = 1;
1433                        break;
1434                }
1435
1436                /* Restart auto-negotiation if remote fault */
1437                if (status & PHY_STAT_REM_FLT) {
1438                        db_printf("smc91111:PHY remote fault detected\n");
1439
1440                        /* Restart auto-negotiation */
1441                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1442                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1443                                           PHY_CNTL_ANEG_EN |
1444                                           PHY_CNTL_ANEG_RST |
1445                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1446                }
1447                HAL_DELAY_US(100000);
1448        }
1449
1450        /* Fail if we detected an auto-negotiate remote fault */
1451        if (status & PHY_STAT_REM_FLT) {
1452                db_printf("smc91111:PHY remote fault detected\n");
1453                failed = 1;
1454        }
1455
1456        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1457
1458        /* Set our sysctl parameters to match auto-negotiation results */
1459        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1460                db_printf("smc91111:PHY 100BaseT\n");
1461                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1462        } else {
1463                db_printf("smc91111:PHY 10BaseT\n");
1464                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1465        }
1466
1467        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1468                db_printf("smc91111:PHY Full Duplex\n");
1469                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1470        } else {
1471                db_printf("smc91111:PHY Half Duplex\n");
1472                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1473        }
1474
1475        /* Re-Configure the Receive/Phy Control register */
1476        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1477
1478      smc_phy_configure_exit:
1479
1480        /* Exit auto-negotiation */
1481        cpd->autoneg_active = 0;
1482}
1483#endif
1484
1485static uint16_t
1486lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1487                  uint8_t phyreg)
1488{
1489        int i, mask, input_idx, clk_idx = 0;
1490        uint16_t mii_reg, value;
1491        uint8_t bits[64];
1492
1493        /* 32 consecutive ones on MDO to establish sync */
1494        for (i = 0; i < 32; ++i)
1495                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1496
1497        /* Start code <01> */
1498        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1499        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1500
1501        /* Read command <10> */
1502        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1503        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1504
1505        /* Output the PHY address, msb first */
1506        for (mask = 0x10; mask; mask >>= 1) {
1507                if (phyaddr & mask)
1508                        bits[clk_idx++] =
1509                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1510                else
1511                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1512        }
1513
1514        /* Output the phy register number, msb first */
1515        for (mask = 0x10; mask; mask >>= 1) {
1516                if (phyreg & mask)
1517                        bits[clk_idx++] =
1518                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1519                else
1520                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1521        }
1522
1523        /* Tristate and turnaround (1 bit times) */
1524        bits[clk_idx++] = 0;
1525
1526        /* Input starts at this bit time */
1527        input_idx = clk_idx;
1528
1529        /* Will input 16 bits */
1530        for (i = 0; i < 16; ++i)
1531                bits[clk_idx++] = 0;
1532
1533        /* Final clock bit */
1534        bits[clk_idx++] = 0;
1535
1536        /* Get the current MII register value */
1537        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1538
1539        /* Turn off all MII Interface bits */
1540        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1541                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1542        HAL_DELAY_US(50);
1543
1544        /* Clock all 64 cycles */
1545        for (i = 0; i < sizeof(bits); ++i) {
1546                /* Clock Low - output data */
1547                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1548                HAL_DELAY_US(50);
1549
1550                /* Clock Hi - input data */
1551                put_reg(cpd, LAN91CXX_MGMT,
1552                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1553                HAL_DELAY_US(50);
1554
1555                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1556        }
1557
1558        /* Return to idle state */
1559        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1560        HAL_DELAY_US(50);
1561
1562        /* Recover input data */
1563        for (value = 0, i = 0; i < 16; ++i) {
1564                value <<= 1;
1565                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1566                        value |= 1;
1567        }
1568
1569        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1570        return value;
1571}
1572
1573static void
1574lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
1575                   uint8_t phyreg, uint16_t value)
1576{
1577        int i, mask, clk_idx = 0;
1578        uint16_t mii_reg;
1579        uint8_t bits[65];
1580
1581        /* 32 consecutive ones on MDO to establish sync */
1582        for (i = 0; i < 32; ++i)
1583                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1584
1585        /* Start code <01> */
1586        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1587        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1588
1589        /* Write command <01> */
1590        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1591        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1592
1593        /* Output the PHY address, msb first */
1594        for (mask = 0x10; mask; mask >>= 1) {
1595                if (phyaddr & mask)
1596                        bits[clk_idx++] =
1597                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1598                else
1599                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1600        }
1601
1602        /* Output the phy register number, msb first */
1603        for (mask = 0x10; mask; mask >>= 1) {
1604                if (phyreg & mask)
1605                        bits[clk_idx++] =
1606                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1607                else
1608                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1609        }
1610
1611        /* Tristate and turnaround (2 bit times) */
1612        bits[clk_idx++] = 0;
1613        bits[clk_idx++] = 0;
1614
1615        /* Write out 16 bits of data, msb first */
1616        for (mask = 0x8000; mask; mask >>= 1) {
1617                if (value & mask)
1618                        bits[clk_idx++] =
1619                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1620                else
1621                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1622        }
1623
1624        /* Final clock bit (tristate) */
1625        bits[clk_idx++] = 0;
1626
1627        /* Get the current MII register value */
1628        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1629
1630        /* Turn off all MII Interface bits */
1631        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1632                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1633        HAL_DELAY_US(50);
1634
1635        /* Clock all cycles */
1636        for (i = 0; i < sizeof(bits); ++i) {
1637                /* Clock Low - output data */
1638                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1639                HAL_DELAY_US(50);
1640
1641                /* Clock Hi - input data */
1642                put_reg(cpd, LAN91CXX_MGMT,
1643                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1644                HAL_DELAY_US(50);
1645
1646/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1647        }
1648
1649        /* Return to idle state */
1650        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1651        HAL_DELAY_US(50);
1652
1653        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1654}
1655
1656#if 0
1657void lan91cxx_print_bank(int bank){
1658        struct lan91cxx_priv_data *cpd = &smc91111;
1659        int regno;
1660        unsigned short regval[8];
1661        int i;
1662
1663        if ( bank >= 4 )
1664                return;
1665        for(i=0; i<8; i++){
1666                regno=i+bank<<3;
1667                regval[i] = get_reg(cpd, regno);
1668        }
1669        printk("---- BANK %d ----\n\r",bank);
1670        for(i=0; i<8; i++){
1671                printk("0x%x: 0x%x\n\r",i,regval[i]);
1672        }
1673
1674}
1675#endif
1676
1677#endif
Note: See TracBrowser for help on using the repository browser.