source: rtems/c/src/libchip/network/greth.c @ a67f44c

5
Last change on this file since a67f44c was a20c114, checked in by Daniel Hellstrom <daniel@…>, on 05/27/14 at 09:42:44

GRETH: remove TCP/UDP HW checksum generation

The GRETH doesn't support IP fragments.

  • Property mode set to 100644
File size: 33.7 KB
RevLine 
[81d914d8]1/*
[050249d]2 * Gaisler Research ethernet MAC driver
3 * adapted from Opencores driver by Marko Isomaki
[81d914d8]4 *
5 *  The license and distribution terms for this file may be
[3e25dfc8]6 *  found in the file LICENSE in this distribution or at
[c499856]7 *  http://www.rtems.org/license/LICENSE.
[81d914d8]8 *
[050249d]9 * 2007-09-07, Ported GBIT support from 4.6.5
[81d914d8]10 */
11
12#include <rtems.h>
13#include <bsp.h>
14
[39671330]15#ifdef GRETH_SUPPORTED
16
[81d914d8]17#include <inttypes.h>
18#include <errno.h>
[050249d]19#include <rtems/bspIo.h>
[81d914d8]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 "greth.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#ifdef malloc
37#undef malloc
38#endif
39#ifdef free
40#undef free
41#endif
42
[050249d]43/* #define GRETH_DEBUG */
[81d914d8]44
45#ifdef CPU_U32_FIX
46extern void ipalign(struct mbuf *m);
47#endif
48
[39671330]49/* Used when reading from memory written by GRETH DMA unit */
50#ifndef GRETH_MEM_LOAD
51#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
52#endif
53
[81d914d8]54/*
55 * Number of OCs supported by this driver
56 */
57#define NOCDRIVER       1
58
59/*
60 * Receive buffer size -- Allow for a full ethernet packet including CRC
61 */
62#define RBUF_SIZE 1518
63
64#define ET_MINLEN 64            /* minimum message length */
65
66/*
67 * RTEMS event used by interrupt handler to signal driver tasks.
68 * This must not be any of the events used by the network task synchronization.
69 */
70#define INTERRUPT_EVENT RTEMS_EVENT_1
71
72/*
73 * RTEMS event used to start transmit daemon.
74 * This must not be the same as INTERRUPT_EVENT.
75 */
76#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
77
78 /* event to send when tx buffers become available */
79#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
80
81#if (MCLBYTES < RBUF_SIZE)
82# error "Driver must have MCLBYTES > RBUF_SIZE"
83#endif
84
[050249d]85/* 4s Autonegotiation Timeout */
86#ifndef GRETH_AUTONEGO_TIMEOUT_MS
87#define GRETH_AUTONEGO_TIMEOUT_MS 4000
88#endif
[e6f327c]89const struct timespec greth_tan = {
90   GRETH_AUTONEGO_TIMEOUT_MS/1000,
[e4b50853]91   (GRETH_AUTONEGO_TIMEOUT_MS % 1000) *1000000
[e6f327c]92};
[050249d]93
94/* For optimizing the autonegotiation time */
95#define GRETH_AUTONEGO_PRINT_TIME
96
[81d914d8]97/* Ethernet buffer descriptor */
98
99typedef struct _greth_rxtxdesc {
100   volatile uint32_t ctrl; /* Length and status */
101   uint32_t *addr;         /* Buffer pointer */
102} greth_rxtxdesc;
103
[050249d]104
[81d914d8]105/*
106 * Per-device data
107 */
108struct greth_softc
109{
110
111   struct arpcom arpcom;
[3495c57]112
[81d914d8]113   greth_regs *regs;
[3495c57]114
[81d914d8]115   int acceptBroadcast;
[0f700ffc]116   rtems_id daemonTid;
[3495c57]117
[81d914d8]118   unsigned int tx_ptr;
[050249d]119   unsigned int tx_dptr;
120   unsigned int tx_cnt;
[81d914d8]121   unsigned int rx_ptr;
122   unsigned int txbufs;
123   unsigned int rxbufs;
124   greth_rxtxdesc *txdesc;
125   greth_rxtxdesc *rxdesc;
126   struct mbuf **rxmbuf;
[050249d]127   struct mbuf **txmbuf;
[81d914d8]128   rtems_vector_number vector;
[3495c57]129
[0f700ffc]130   /* TX descriptor interrupt generation */
131   int tx_int_gen;
132   int tx_int_gen_cur;
133   struct mbuf *next_tx_mbuf;
134   int max_fragsize;
135
[050249d]136   /*Status*/
137   struct phy_device_info phydev;
138   int fd;
139   int sp;
140   int gb;
141   int gbit_mac;
142   int auto_neg;
[e6f327c]143   struct timespec auto_neg_time;
[3495c57]144
[81d914d8]145   /*
146    * Statistics
147    */
148   unsigned long rxInterrupts;
[3495c57]149
[81d914d8]150   unsigned long rxPackets;
151   unsigned long rxLengthError;
152   unsigned long rxNonOctet;
153   unsigned long rxBadCRC;
154   unsigned long rxOverrun;
[3495c57]155
[81d914d8]156   unsigned long txInterrupts;
[3495c57]157
[81d914d8]158   unsigned long txDeferred;
159   unsigned long txHeartbeat;
160   unsigned long txLateCollision;
161   unsigned long txRetryLimit;
162   unsigned long txUnderrun;
[050249d]163
[81d914d8]164};
165
166static struct greth_softc greth;
167
[0f700ffc]168int greth_process_tx_gbit(struct greth_softc *sc);
169int greth_process_tx(struct greth_softc *sc);
170
[81d914d8]171static char *almalloc(int sz)
172{
173        char *tmp;
174        tmp = calloc(1,2*sz);
[c48572d9]175        tmp = (char *) (((uintptr_t)tmp+sz) & ~(sz -1));
[81d914d8]176        return(tmp);
177}
178
179/* GRETH interrupt handler */
180
[e4b50853]181static void greth_interrupt_handler (void *arg)
[81d914d8]182{
[050249d]183        uint32_t status;
[0f700ffc]184        uint32_t ctrl;
185        rtems_event_set events = 0;
[7499b84]186        struct greth_softc *greth = arg;
[3495c57]187
[0f700ffc]188        /* read and clear interrupt cause */
[7499b84]189        status = greth->regs->status;
190        greth->regs->status = status;
191        ctrl = greth->regs->ctrl;
[3495c57]192
[050249d]193        /* Frame received? */
[0f700ffc]194        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
[050249d]195        {
[7499b84]196                greth->rxInterrupts++;
[0f700ffc]197                /* Stop RX-Error and RX-Packet interrupts */
198                ctrl &= ~GRETH_CTRL_RXIRQ;
199                events |= INTERRUPT_EVENT;
[050249d]200        }
[0f700ffc]201       
202        if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
[050249d]203        {
[7499b84]204                greth->txInterrupts++;
[0f700ffc]205                ctrl &= ~GRETH_CTRL_TXIRQ;
206                events |= GRETH_TX_WAIT_EVENT;
[050249d]207        }
[7499b84]208
[0f700ffc]209        /* Clear interrupt sources */
[7499b84]210        greth->regs->ctrl = ctrl;
211
[0f700ffc]212        /* Send the event(s) */
213        if ( events )
[26e90fb1]214                rtems_bsdnet_event_send (greth->daemonTid, events);
[81d914d8]215}
216
[050249d]217static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
[81d914d8]218{
219    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
[050249d]220    greth.regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
[81d914d8]221    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
222    if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
223        return((greth.regs->mdio_ctrl >> 16) & 0xFFFF);
224    else {
225        printf("greth: failed to read mii\n");
226        return (0);
227    }
228}
229
[050249d]230static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
[81d914d8]231{
232    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
[050249d]233    greth.regs->mdio_ctrl =
234     ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
[81d914d8]235    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
236}
[050249d]237
[3495c57]238static void print_init_info(struct greth_softc *sc)
[050249d]239{
240        printf("greth: driver attached\n");
[0f700ffc]241                if ( sc->auto_neg == -1 ){
242                        printf("Auto negotiation timed out. Selecting default config\n");
243                }
[050249d]244        printf("**** PHY ****\n");
245        printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
246        printf("Current Operating Mode: ");
247        if (sc->gb) {
248                printf("1000 Mbit ");
249        } else if (sc->sp) {
250                printf("100 Mbit ");
251        } else {
252                printf("10 Mbit ");
253        }
254        if (sc->fd) {
255                printf("Full Duplex\n");
256        } else {
257                printf("Half Duplex\n");
258        }
259#ifdef GRETH_AUTONEGO_PRINT_TIME
[e6f327c]260        if ( sc->auto_neg ) {
[e4b50853]261          printf("Autonegotiation Time: %ldms\n", sc->auto_neg_time.tv_sec*1000 +
[e6f327c]262                 sc->auto_neg_time.tv_nsec/1000000);
[050249d]263        }
264#endif
265}
266
267
[81d914d8]268/*
269 * Initialize the ethernet hardware
270 */
271static void
272greth_initialize_hardware (struct greth_softc *sc)
273{
274    struct mbuf *m;
275    int i;
[050249d]276    int phyaddr;
277    int phyctrl;
278    int phystatus;
279    int tmp1;
280    int tmp2;
[e6f327c]281    struct timespec tstart, tnow;
[050249d]282
[81d914d8]283    greth_regs *regs;
284
285    regs = sc->regs;
[3495c57]286
[81d914d8]287    /* Reset the controller.  */
288    greth.rxInterrupts = 0;
289    greth.rxPackets = 0;
290
291    regs->ctrl = 0;
292    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
293    regs->ctrl = 0;                     /* Reset OFF */
[3495c57]294
[050249d]295    /* Check if mac is gbit capable*/
[3495c57]296    sc->gbit_mac = (regs->ctrl >> 27) & 1;
297
[050249d]298    /* Get the phy address which assumed to have been set
299       correctly with the reset value in hardware*/
300    phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
301
302    /* get phy control register default values */
303    while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {}
[3495c57]304
[050249d]305    /* reset PHY and wait for completion */
306    write_mii(phyaddr, 0, 0x8000 | phyctrl);
307
308    while ((read_mii(phyaddr, 0)) & 0x8000) {}
[45fecbb6]309    phystatus = read_mii(phyaddr, 1);
310
311    /* Disable Gbit auto-neg advertisement if MAC does not support it */
312
313    if ((!sc->gbit_mac) && (phystatus & 0x100)) write_mii(phyaddr, 9, 0);
314
315    /* Restart auto-negotiation if available */
316    if (phystatus & 0x08) {
317        write_mii(phyaddr, 0, phyctrl | 0x1200);
318        phyctrl = read_mii(phyaddr, 0);
319    }
[3495c57]320
321    /* Check if PHY is autoneg capable and then determine operating mode,
[050249d]322       otherwise force it to 10 Mbit halfduplex */
323    sc->gb = 0;
324    sc->fd = 0;
325    sc->sp = 0;
326    sc->auto_neg = 0;
[e6f327c]327    _Timespec_Set_to_zero(&sc->auto_neg_time);
[050249d]328    if ((phyctrl >> 12) & 1) {
329            /*wait for auto negotiation to complete*/
330            sc->auto_neg = 1;
[e6f327c]331            if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
332                    printk("rtems_clock_get_uptime failed\n");
[050249d]333            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
[e6f327c]334                    if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
335                            printk("rtems_clock_get_uptime failed\n");
336                    _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
337                    if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
[0f700ffc]338                            sc->auto_neg = -1; /* Failed */
[050249d]339                            tmp1 = read_mii(phyaddr, 0);
340                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
341                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
342                            sc->fd = (phyctrl >> 8) & 1;
343                            goto auto_neg_done;
344                    }
[e6f327c]345                    /* Wait about 30ms, time is PHY dependent */
346                    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
[050249d]347            }
348            sc->phydev.adv = read_mii(phyaddr, 4);
349            sc->phydev.part = read_mii(phyaddr, 5);
350            if ((phystatus >> 8) & 1) {
351                    sc->phydev.extadv = read_mii(phyaddr, 9);
352                    sc->phydev.extpart = read_mii(phyaddr, 10);
353                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
354                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
355                               sc->gb = 1;
356                               sc->fd = 1;
357                       }
[1bdc6d1]358                       else if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
[050249d]359                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
360                               sc->gb = 1;
361                               sc->fd = 0;
362                       }
363            }
364            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
365                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
366                         (sc->phydev.part & GRETH_MII_100TXFD)) {
367                            sc->sp = 1;
368                            sc->fd = 1;
369                    }
[1bdc6d1]370                    else if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
[050249d]371                         (sc->phydev.part & GRETH_MII_100TXHD)) {
372                            sc->sp = 1;
373                            sc->fd = 0;
374                    }
[1bdc6d1]375                    else if ( (sc->phydev.adv & GRETH_MII_10FD) &&
[050249d]376                         (sc->phydev.part & GRETH_MII_10FD)) {
377                            sc->fd = 1;
378                    }
379            }
380    }
381auto_neg_done:
382    sc->phydev.vendor = 0;
383    sc->phydev.device = 0;
384    sc->phydev.rev = 0;
385    phystatus = read_mii(phyaddr, 1);
[3495c57]386
[050249d]387    /*Read out PHY info if extended registers are available */
[0f700ffc]388    if (phystatus & 1) { 
[050249d]389            tmp1 = read_mii(phyaddr, 2);
390            tmp2 = read_mii(phyaddr, 3);
391
392            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
393            sc->phydev.rev = tmp2 & 0xF;
394            sc->phydev.device = (tmp2 >> 4) & 0x3F;
395    }
396
397    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
398    /*check if marvell 88EE1111 PHY. Needs special reset handling */
399    if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
400            if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
401                    write_mii(phyaddr, 0, sc->sp << 13);
402                    write_mii(phyaddr, 0, 0x8000);
403                    sc->gb = 0;
404                    sc->sp = 0;
405                    sc->fd = 0;
406            }
407    } else {
408            if (((sc->gb) && !(sc->gbit_mac))  || !((phyctrl >> 12) & 1)) {
409                    write_mii(phyaddr, 0, sc->sp << 13);
410                    sc->gb = 0;
411                    sc->sp = 0;
412                    sc->fd = 0;
413            }
414    }
415    while ((read_mii(phyaddr, 0)) & 0x8000) {}
416
417    regs->ctrl = 0;
418    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
419    regs->ctrl = 0;
[81d914d8]420
421    /* Initialize rx/tx descriptor pointers */
422    sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
423    sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
424    sc->tx_ptr = 0;
[050249d]425    sc->tx_dptr = 0;
426    sc->tx_cnt = 0;
[81d914d8]427    sc->rx_ptr = 0;
[c48572d9]428    regs->txdesc = (uintptr_t) sc->txdesc;
429    regs->rxdesc = (uintptr_t) sc->rxdesc;
[3495c57]430
[81d914d8]431    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
[050249d]432    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
[81d914d8]433
434    for (i = 0; i < sc->txbufs; i++)
435      {
[050249d]436              sc->txdesc[i].ctrl = 0;
437              if (!(sc->gbit_mac)) {
438                      sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN);
439              }
[81d914d8]440#ifdef GRETH_DEBUG
[050249d]441              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
[81d914d8]442#endif
443      }
444    for (i = 0; i < sc->rxbufs; i++)
445      {
446
447          MGETHDR (m, M_WAIT, MT_DATA);
448          MCLGET (m, M_WAIT);
[050249d]449          if (sc->gbit_mac)
450                  m->m_data += 2;
[81d914d8]451          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
452          sc->rxmbuf[i] = m;
453          sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
454          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
455#ifdef GRETH_DEBUG
[050249d]456/*        printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
[81d914d8]457#endif
458      }
459    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
460
461    /* set ethernet address.  */
[3495c57]462    regs->mac_addr_msb =
[81d914d8]463      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
[c48572d9]464
465    uint32_t mac_addr_lsb;
466    mac_addr_lsb = sc->arpcom.ac_enaddr[2];
467    mac_addr_lsb <<= 8;
468    mac_addr_lsb |= sc->arpcom.ac_enaddr[3];
469    mac_addr_lsb <<= 8;
470    mac_addr_lsb |= sc->arpcom.ac_enaddr[4];
471    mac_addr_lsb <<= 8;
472    mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
473    regs->mac_addr_lsb = mac_addr_lsb;
[81d914d8]474
[0f700ffc]475    if ( sc->rxbufs < 10 ) {
476        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
477    }else{
478        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
479    }
480    sc->next_tx_mbuf = NULL;
481   
482    if ( !sc->gbit_mac )
483        sc->max_fragsize = 1;
[81d914d8]484
485    /* clear all pending interrupts */
486    regs->status = 0xffffffff;
[0f700ffc]487   
[7499b84]488    /* install interrupt handler */
489    rtems_interrupt_handler_install(sc->vector, "greth", RTEMS_INTERRUPT_SHARED,
490                                    greth_interrupt_handler, sc);
[81d914d8]491
[050249d]492    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
[0f700ffc]493
[050249d]494    print_init_info(sc);
[81d914d8]495}
496
[39671330]497#ifdef CPU_U32_FIX
498
499/*
500 * Routine to align the received packet so that the ip header
501 * is on a 32-bit boundary. Necessary for cpu's that do not
502 * allow unaligned loads and stores and when the 32-bit DMA
503 * mode is used.
504 *
505 * Transfers are done on word basis to avoid possibly slow byte
506 * and half-word writes.
507 */
508
509void ipalign(struct mbuf *m)
510{
511  unsigned int *first, *last, data;
512  unsigned int tmp;
513
514  if ((((int) m->m_data) & 2) && (m->m_len)) {
515    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
516    first = (unsigned int *) (((int) m->m_data) & ~3);
517    tmp = GRETH_MEM_LOAD(first);
518    tmp = tmp << 16;
519    first++;
520    do {
521      /* When snooping is not available the LDA instruction must be used
522       * to avoid the cache to return an illegal value.
523       * Load with forced cache miss
524       */
525      data = GRETH_MEM_LOAD(first);
526      *first = tmp | (data >> 16);
527      tmp = data << 16;
528      first++;
529    } while (first <= last);
530
531    m->m_data = (caddr_t)(((int) m->m_data) + 2);
532  }
533}
534#endif
535
[e4b50853]536static void
[0f700ffc]537greth_Daemon (void *arg)
[81d914d8]538{
539    struct ether_header *eh;
540    struct greth_softc *dp = (struct greth_softc *) &greth;
541    struct ifnet *ifp = &dp->arpcom.ac_if;
542    struct mbuf *m;
543    unsigned int len, len_status, bad;
544    rtems_event_set events;
[0f700ffc]545    rtems_interrupt_level level;
546    int first;
[e4b50853]547#ifdef CPU_U32_FIX
[39671330]548    unsigned int tmp;
[e4b50853]549#endif
[3495c57]550
[81d914d8]551    for (;;)
552      {
[0f700ffc]553        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
[81d914d8]554                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
555                                    RTEMS_NO_TIMEOUT, &events);
[3495c57]556
[0f700ffc]557        if ( events & GRETH_TX_WAIT_EVENT ){
558            /* TX interrupt.
559             * We only end up here when all TX descriptors has been used,
560             * and
561             */
562            if ( dp->gbit_mac )
563                greth_process_tx_gbit(dp);
564            else
565                greth_process_tx(dp);
566           
567            /* If we didn't get a RX interrupt we don't process it */
568            if ( (events & INTERRUPT_EVENT) == 0 )
569                continue;
570        }
571
[81d914d8]572#ifdef GRETH_ETH_DEBUG
573    printf ("r\n");
574#endif
[0f700ffc]575    first=1;
576    /* Scan for Received packets */
577again:
[050249d]578    while (!((len_status =
[39671330]579                    GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
[81d914d8]580            {
[050249d]581                    bad = 0;
582                    if (len_status & GRETH_RXD_TOOLONG)
583                    {
584                            dp->rxLengthError++;
585                            bad = 1;
586                    }
587                    if (len_status & GRETH_RXD_DRIBBLE)
588                    {
589                            dp->rxNonOctet++;
590                            bad = 1;
591                    }
592                    if (len_status & GRETH_RXD_CRCERR)
593                    {
594                            dp->rxBadCRC++;
595                            bad = 1;
596                    }
597                    if (len_status & GRETH_RXD_OVERRUN)
598                    {
599                            dp->rxOverrun++;
600                            bad = 1;
601                    }
602                    if (len_status & GRETH_RXD_LENERR)
603                    {
604                            dp->rxLengthError++;
605                            bad = 1;
606                    }
607                    if (!bad)
608                    {
609                            /* pass on the packet in the receive buffer */
610                            len = len_status & 0x7FF;
611                            m = dp->rxmbuf[dp->rx_ptr];
612#ifdef GRETH_DEBUG
613                            int i;
614                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
615                            for (i=0; i<len; i++)
616                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
617                            printf("\n");
618#endif
619                            m->m_len = m->m_pkthdr.len =
620                                    len - sizeof (struct ether_header);
621
622                            eh = mtod (m, struct ether_header *);
[39671330]623
[050249d]624                            m->m_data += sizeof (struct ether_header);
[81d914d8]625#ifdef CPU_U32_FIX
[39671330]626                            if(!dp->gbit_mac) {
627                                    /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
628                                    tmp = GRETH_MEM_LOAD((uintptr_t)eh);
629                                    tmp = GRETH_MEM_LOAD(4+(uintptr_t)eh);
630                                    tmp = GRETH_MEM_LOAD(8+(uintptr_t)eh);
631                                    tmp = GRETH_MEM_LOAD(12+(uintptr_t)eh);
[e4b50853]632                                    (void)tmp;
[050249d]633                                    ipalign(m); /* Align packet on 32-bit boundary */
[39671330]634                            }
[81d914d8]635#endif
[050249d]636
637                            ether_input (ifp, eh, m);
638                            MGETHDR (m, M_WAIT, MT_DATA);
639                            MCLGET (m, M_WAIT);
640                            if (dp->gbit_mac)
641                                    m->m_data += 2;
642                            dp->rxmbuf[dp->rx_ptr] = m;
643                            m->m_pkthdr.rcvif = ifp;
644                            dp->rxdesc[dp->rx_ptr].addr =
645                                    (uint32_t *) mtod (m, uint32_t *);
646                            dp->rxPackets++;
647                    }
648                    if (dp->rx_ptr == dp->rxbufs - 1) {
649                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
650                    } else {
651                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
652                    }
[0f700ffc]653                    rtems_interrupt_disable(level);
[050249d]654                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
[0f700ffc]655                    rtems_interrupt_enable(level);
[050249d]656                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
[81d914d8]657            }
[0f700ffc]658
659        /* Always scan twice to avoid deadlock */
660        if ( first ){
661            first=0;
662            rtems_interrupt_disable(level);
663            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
664            rtems_interrupt_enable(level);
665            goto again;
666        }
667
[81d914d8]668      }
[3495c57]669
[81d914d8]670}
671
672static int inside = 0;
[0f700ffc]673static int
[81d914d8]674sendpacket (struct ifnet *ifp, struct mbuf *m)
675{
676    struct greth_softc *dp = ifp->if_softc;
677    unsigned char *temp;
678    struct mbuf *n;
679    unsigned int len;
[0f700ffc]680    rtems_interrupt_level level;
[3495c57]681
[81d914d8]682    /*printf("Send packet entered\n");*/
683    if (inside) printf ("error: sendpacket re-entered!!\n");
684    inside = 1;
[0f700ffc]685
[81d914d8]686    /*
[0f700ffc]687     * Is there a free descriptor available?
[81d914d8]688     */
[39671330]689    if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
[0f700ffc]690            /* No. */
691            inside = 0;
692            return 1;
693    }
[81d914d8]694
[0f700ffc]695    /* Remember head of chain */
696    n = m;
[81d914d8]697
698    len = 0;
[39671330]699    temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
[81d914d8]700#ifdef GRETH_DEBUG
[050249d]701    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
[81d914d8]702#endif
703    for (;;)
[050249d]704    {
[81d914d8]705#ifdef GRETH_DEBUG
[050249d]706            int i;
707            printf("MBUF: 0x%08x : ", (int) m->m_data);
708            for (i=0;i<m->m_len;i++)
709                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
710            printf("\n");
[81d914d8]711#endif
[050249d]712            len += m->m_len;
713            if (len <= RBUF_SIZE)
714                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
715            temp += m->m_len;
716            if ((m = m->m_next) == NULL)
717                    break;
718    }
[3495c57]719
[81d914d8]720    m_freem (n);
[3495c57]721
[81d914d8]722    /* don't send long packets */
723
724    if (len <= GRETH_MAXBUF_LEN) {
[050249d]725            if (dp->tx_ptr < dp->txbufs-1) {
726                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
727            } else {
[3495c57]728                    dp->txdesc[dp->tx_ptr].ctrl =
[050249d]729                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
730            }
731            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
[0f700ffc]732            rtems_interrupt_disable(level);
733            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
734            rtems_interrupt_enable(level);
735           
[81d914d8]736    }
737    inside = 0;
[0f700ffc]738   
739    return 0;
[81d914d8]740}
741
[050249d]742
[e4b50853]743static int
[050249d]744sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
745{
746        struct greth_softc *dp = ifp->if_softc;
747        unsigned int len;
[0f700ffc]748       
749        unsigned int ctrl;
750        int frags;
751        struct mbuf *mtmp;
752        int int_en;
753        rtems_interrupt_level level;
[050249d]754
755        if (inside) printf ("error: sendpacket re-entered!!\n");
756        inside = 1;
[3495c57]757
[050249d]758        len = 0;
759#ifdef GRETH_DEBUG
760        printf("TXD: 0x%08x\n", (int) m->m_data);
761#endif
[0f700ffc]762        /* Get number of fragments too see if we have enough
763         * resources.
764         */
765        frags=1;
766        mtmp=m;
767        while(mtmp->m_next){
768            frags++;
769            mtmp = mtmp->m_next;
770        }
771       
772        if ( frags > dp->max_fragsize )
773            dp->max_fragsize = frags;
774       
775        if ( frags > dp->txbufs ){
776            inside = 0;
777            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
778            return -1;
779        }
780       
781        if ( frags > (dp->txbufs-dp->tx_cnt) ){
782            inside = 0;
783            /* Return number of fragments */
784            return frags;
785        }
786       
787       
788        /* Enable interrupt from descriptor every tx_int_gen
789         * descriptor. Typically every 16 descriptor. This
790         * is only to reduce the number of interrupts during
791         * heavy load.
792         */
793        dp->tx_int_gen_cur-=frags;
794        if ( dp->tx_int_gen_cur <= 0 ){
795            dp->tx_int_gen_cur = dp->tx_int_gen;
796            int_en = GRETH_TXD_IRQ;
797        }else{
798            int_en = 0;
799        }
800       
801        /* At this stage we know that enough descriptors are available */
[050249d]802        for (;;)
803        {
[0f700ffc]804               
[050249d]805#ifdef GRETH_DEBUG
[0f700ffc]806            int i;
807            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
808            for (i=0; i<m->m_len; i++)
809                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
810            printf("\n");
[050249d]811#endif
812            len += m->m_len;
813            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
[0f700ffc]814
815            /* Wrap around? */
[050249d]816            if (dp->tx_ptr < dp->txbufs-1) {
[a20c114]817                ctrl = GRETH_TXD_ENABLE;
[0f700ffc]818            }else{
[a20c114]819                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_WRAP;
[0f700ffc]820            }
821
822            /* Enable Descriptor */
823            if ((m->m_next) == NULL) {
824                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
825                break;
826            }else{
827                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
[050249d]828            }
[0f700ffc]829
830            /* Next */
[050249d]831            dp->txmbuf[dp->tx_ptr] = m;
832            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
833            dp->tx_cnt++;
834            m = m->m_next;
[0f700ffc]835        }
[050249d]836        dp->txmbuf[dp->tx_ptr] = m;
[0f700ffc]837        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
[050249d]838        dp->tx_cnt++;
[0f700ffc]839
840        /* Tell Hardware about newly enabled descriptor */
841        rtems_interrupt_disable(level);
[050249d]842        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
[0f700ffc]843        rtems_interrupt_enable(level);
844
[050249d]845        inside = 0;
[0f700ffc]846
847        return 0;
[050249d]848}
849
[0f700ffc]850int greth_process_tx_gbit(struct greth_softc *sc)
[81d914d8]851{
852    struct ifnet *ifp = &sc->arpcom.ac_if;
853    struct mbuf *m;
[0f700ffc]854    rtems_interrupt_level level;
855    int first=1;
[3495c57]856
[0f700ffc]857    /*
858     * Send packets till queue is empty
859     */
860    for (;;){
861        /* Reap Sent packets */
[39671330]862        while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
[0f700ffc]863            m_free(sc->txmbuf[sc->tx_dptr]);
864            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
865            sc->tx_cnt--;
866        }
867
868        if ( sc->next_tx_mbuf ){
869            /* Get packet we tried but faild to transmit last time */
870            m = sc->next_tx_mbuf;
871            sc->next_tx_mbuf = NULL; /* Mark packet taken */
872        }else{
[050249d]873            /*
[0f700ffc]874             * Get the next mbuf chain to transmit from Stack.
[050249d]875             */
[0f700ffc]876            IF_DEQUEUE (&ifp->if_snd, m);
877            if (!m){
878                /* Hardware has sent all schedule packets, this
879                 * makes the stack enter at greth_start next time
880                 * a packet is to be sent.
881                 */
882                ifp->if_flags &= ~IFF_OACTIVE;
883                break;
884            }
885        }
[3495c57]886
[0f700ffc]887        /* Are there free descriptors available? */
888        /* Try to send packet, if it a negative number is returned. */
889        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
890            /* Not enough resources */
[3495c57]891
[0f700ffc]892            /* Since we have taken the mbuf out of the "send chain"
893             * we must remember to use that next time we come back.
894             * or else we have dropped a packet.
[050249d]895             */
[0f700ffc]896            sc->next_tx_mbuf = m;
[3495c57]897
[0f700ffc]898            /* Not enough resources, enable interrupt for transmissions
899             * this way we will be informed when more TX-descriptors are
900             * available.
901             */
902            if ( first ){
903                first = 0;
904                rtems_interrupt_disable(level);
905                ifp->if_flags |= IFF_OACTIVE;
906                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
907                rtems_interrupt_enable(level);
908
909                /* We must check again to be sure that we didn't
910                 * miss an interrupt (if a packet was sent just before
911                 * enabling interrupts)
912                 */
913                continue;
[050249d]914            }
[0f700ffc]915
916            return -1;
917        }else{
918            /* Sent Ok, proceed to process more packets if available */
919        }
[050249d]920    }
[0f700ffc]921    return 0;
[050249d]922}
[81d914d8]923
[0f700ffc]924int greth_process_tx(struct greth_softc *sc)
[050249d]925{
926    struct ifnet *ifp = &sc->arpcom.ac_if;
927    struct mbuf *m;
[0f700ffc]928    rtems_interrupt_level level;
929    int first=1;
[3495c57]930
[0f700ffc]931    /*
932     * Send packets till queue is empty
933     */
934    for (;;){
935        if ( sc->next_tx_mbuf ){
936            /* Get packet we tried but failed to transmit last time */
937            m = sc->next_tx_mbuf;
938            sc->next_tx_mbuf = NULL; /* Mark packet taken */
939        }else{
[050249d]940            /*
[0f700ffc]941             * Get the next mbuf chain to transmit from Stack.
[050249d]942             */
[0f700ffc]943            IF_DEQUEUE (&ifp->if_snd, m);
944            if (!m){
945                /* Hardware has sent all schedule packets, this
946                 * makes the stack enter at greth_start next time
947                 * a packet is to be sent.
948                 */
949                ifp->if_flags &= ~IFF_OACTIVE;
950                break;
951            }
952        }
[3495c57]953
[0f700ffc]954        /* Try to send packet, failed if it a non-zero number is returned. */
955        if ( sendpacket(ifp, m) ){
956            /* Not enough resources */
[3495c57]957
[0f700ffc]958            /* Since we have taken the mbuf out of the "send chain"
959             * we must remember to use that next time we come back.
960             * or else we have dropped a packet.
[050249d]961             */
[0f700ffc]962            sc->next_tx_mbuf = m;
963
964            /* Not enough resources, enable interrupt for transmissions
965             * this way we will be informed when more TX-descriptors are
966             * available.
967             */
968            if ( first ){
969                first = 0;
970                rtems_interrupt_disable(level);
971                ifp->if_flags |= IFF_OACTIVE;
972                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
973                rtems_interrupt_enable(level);
974
975                /* We must check again to be sure that we didn't
976                 * miss an interrupt (if a packet was sent just before
977                 * enabling interrupts)
978                 */
979                continue;
[050249d]980            }
[0f700ffc]981
982            return -1;
983        }else{
984            /* Sent Ok, proceed to process more packets if available */
985        }
[050249d]986    }
[0f700ffc]987    return 0;
[81d914d8]988}
989
990static void
991greth_start (struct ifnet *ifp)
992{
993    struct greth_softc *sc = ifp->if_softc;
[3495c57]994
[0f700ffc]995    if ( ifp->if_flags & IFF_OACTIVE )
996            return;
997
998    if ( sc->gbit_mac ){
999        /* No use trying to handle this if we are waiting on GRETH
1000         * to send the previously scheduled packets.
1001         */
[3495c57]1002
[0f700ffc]1003        greth_process_tx_gbit(sc);
1004    }else{
1005        greth_process_tx(sc);
1006    }
[81d914d8]1007}
1008
1009/*
1010 * Initialize and start the device
1011 */
1012static void
1013greth_init (void *arg)
1014{
1015    struct greth_softc *sc = arg;
1016    struct ifnet *ifp = &sc->arpcom.ac_if;
1017
[0f700ffc]1018    if (sc->daemonTid == 0) {
[81d914d8]1019
[0f700ffc]1020        /*
1021         * Start driver tasks
1022         */
1023        sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
1024                                              greth_Daemon, sc);
[3495c57]1025
[0f700ffc]1026        /*
1027         * Set up GRETH hardware
1028         */
1029        greth_initialize_hardware (sc);
1030
1031    }
[81d914d8]1032
1033    /*
1034     * Tell the world that we're running.
1035     */
1036    ifp->if_flags |= IFF_RUNNING;
1037}
1038
1039/*
1040 * Stop the device
1041 */
1042static void
1043greth_stop (struct greth_softc *sc)
1044{
1045    struct ifnet *ifp = &sc->arpcom.ac_if;
1046
1047    ifp->if_flags &= ~IFF_RUNNING;
1048
1049    sc->regs->ctrl = 0;                 /* RX/TX OFF */
1050    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
1051    sc->regs->ctrl = 0;                 /* Reset OFF */
[0f700ffc]1052   
1053    sc->next_tx_mbuf = NULL;
[81d914d8]1054}
1055
1056
1057/*
1058 * Show interface statistics
1059 */
1060static void
1061greth_stats (struct greth_softc *sc)
1062{
1063  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1064  printf ("      Rx Packets:%-8lu", sc->rxPackets);
1065  printf ("          Length:%-8lu", sc->rxLengthError);
1066  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1067  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1068  printf ("         Overrun:%-8lu", sc->rxOverrun);
1069  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
[0f700ffc]1070  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
1071  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
[81d914d8]1072}
1073
1074/*
1075 * Driver ioctl handler
1076 */
1077static int
[a612b50]1078greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
[81d914d8]1079{
1080    struct greth_softc *sc = ifp->if_softc;
1081    int error = 0;
1082
1083    switch (command)
1084      {
1085      case SIOCGIFADDR:
1086      case SIOCSIFADDR:
1087          ether_ioctl (ifp, command, data);
1088          break;
1089
1090      case SIOCSIFFLAGS:
1091          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1092            {
1093            case IFF_RUNNING:
1094                greth_stop (sc);
1095                break;
1096
1097            case IFF_UP:
1098                greth_init (sc);
1099                break;
1100
1101            case IFF_UP | IFF_RUNNING:
1102                greth_stop (sc);
1103                greth_init (sc);
1104                break;
1105       default:
1106                break;
1107            }
1108          break;
1109
1110      case SIO_RTEMS_SHOW_STATS:
1111          greth_stats (sc);
1112          break;
1113
1114          /*
1115           * FIXME: All sorts of multicast commands need to be added here!
1116           */
1117      default:
1118          error = EINVAL;
1119          break;
1120      }
1121
1122    return error;
1123}
1124
1125/*
1126 * Attach an GRETH driver to the system
1127 */
1128int
1129rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
1130                           greth_configuration_t *chip)
1131{
1132    struct greth_softc *sc;
1133    struct ifnet *ifp;
1134    int mtu;
1135    int unitNumber;
1136    char *unitName;
1137
1138      /* parse driver name */
1139    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1140        return 0;
1141
1142    sc = &greth;
1143    ifp = &sc->arpcom.ac_if;
1144    memset (sc, 0, sizeof (*sc));
1145
1146    if (config->hardware_address)
1147      {
1148          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
1149                  ETHER_ADDR_LEN);
1150      }
1151    else
1152      {
1153          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
1154      }
1155
1156    if (config->mtu)
1157        mtu = config->mtu;
1158    else
1159        mtu = ETHERMTU;
1160
1161    sc->acceptBroadcast = !config->ignore_broadcast;
[1f25c77]1162    sc->regs = chip->base_address;
[81d914d8]1163    sc->vector = chip->vector;
1164    sc->txbufs = chip->txd_count;
1165    sc->rxbufs = chip->rxd_count;
[3495c57]1166
[81d914d8]1167    /*
1168     * Set up network interface values
1169     */
1170    ifp->if_softc = sc;
1171    ifp->if_unit = unitNumber;
1172    ifp->if_name = unitName;
1173    ifp->if_mtu = mtu;
1174    ifp->if_init = greth_init;
1175    ifp->if_ioctl = greth_ioctl;
1176    ifp->if_start = greth_start;
1177    ifp->if_output = ether_output;
1178    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1179    if (ifp->if_snd.ifq_maxlen == 0)
1180        ifp->if_snd.ifq_maxlen = ifqmaxlen;
1181
1182    /*
1183     * Attach the interface
1184     */
1185    if_attach (ifp);
1186    ether_ifattach (ifp);
1187
1188#ifdef GRETH_DEBUG
1189    printf ("GRETH : driver has been attached\n");
1190#endif
1191    return 1;
1192};
1193
[39671330]1194#endif
Note: See TracBrowser for help on using the repository browser.