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

4.115
Last change on this file since b9d8cd33 was b9d8cd33, checked in by Daniel Hellstrom <daniel@…>, on 03/29/12 at 11:52:12

SMC91111: remove old unused LEON2/LEON3 intialization code

Signed-off-by: Daniel Hellstrom <daniel@…>

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