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

4.115
Last change on this file since f619250 was 26e90fb1, checked in by Sebastian Huber <sebastian.huber@…>, on 10/30/12 at 16:42:17

libnetworking: Use system events

Add reserved system events RTEMS_EVENT_SYSTEM_NETWORK_SBWAIT and
RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP.

Add and use rtems_bsdnet_event_send().

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