source: rtems/c/src/lib/libbsp/arm/csb336/network/network.c @ c193baad

4.104.115
Last change on this file since c193baad was c193baad, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 04/09/10 at 20:24:57

unify irq data types and code, merge s3c2400/s3c2410 support

  • Property mode set to 100644
File size: 19.0 KB
RevLine 
[1a3d1f3e]1/*
2 *  MC9323MXL Ethernet driver
3 *
4 *  Copyright (c) 2004 by Cogent Computer Systems
5 *  Written by Jay Monkman <jtm@lopingdog.com>
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *
[0c0ae29]10 *  http://www.rtems.com/license/LICENSE.
[1a3d1f3e]11 *
12 *  $Id$
13 */
14#include <rtems.h>
15#include <rtems/rtems_bsdnet.h>
16#include <mc9328mxl.h>
17#include "lan91c11x.h"
18
19#include <stdio.h>
20#include <string.h>
21
22#include <errno.h>
23#include <rtems/error.h>
[d000bd0]24#include <rtems/bspIo.h>
[1a3d1f3e]25
26#include <sys/param.h>
27#include <sys/mbuf.h>
28#include <sys/socket.h>
29#include <sys/sockio.h>
30
31#include <net/if.h>
32
33#include <netinet/in.h>
34#include <netinet/if_ether.h>
35
36#include <irq.h>
37
38/*  RTEMS event used by interrupt handler to start receive daemon. */
39#define START_RECEIVE_EVENT  RTEMS_EVENT_1
40
41/* RTEMS event used to start transmit daemon. */
42#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
43
[9c05850c]44static void enet_isr(rtems_irq_hdl_param);
[1a3d1f3e]45static void enet_isr_on(const rtems_irq_connect_data *unused);
46static void enet_isr_off(const rtems_irq_connect_data *unused);
47static int enet_isr_is_on(const rtems_irq_connect_data *irq);
48
49/* Replace the first value with the clock's interrupt name. */
[9c05850c]50rtems_irq_connect_data mc9328mxl_enet_isr_data = {
51    .name    = BSP_INT_GPIO_PORTA,
[c193baad]52    .hdl     = enet_isr,
[9c05850c]53    .handle  = (void *)BSP_INT_GPIO_PORTA,
54    .on      = enet_isr_on,
55    .off     = enet_isr_off,
56    .isOn    = enet_isr_is_on,
57};
[1a3d1f3e]58typedef struct {
59  unsigned long rx_packets;        /* total packets received         */
60  unsigned long tx_packets;        /* total packets transmitted      */
61  unsigned long rx_bytes;          /* total bytes received           */
62  unsigned long tx_bytes;          /* total bytes transmitted        */
63  unsigned long interrupts;        /* total number of interrupts     */
64  unsigned long rx_interrupts;     /* total number of rx interrupts  */
65  unsigned long tx_interrupts;     /* total number of tx interrupts  */
66  unsigned long txerr_interrupts;  /* total number of tx error interrupts  */
67
68} eth_stats_t;
69
70/*
71 * Hardware-specific storage
72 */
73typedef struct
74{
75    /*
76     * Connection to networking code
77     * This entry *must* be the first in the sonic_softc structure.
78     */
79    struct arpcom arpcom;
[32b8506]80
[1a3d1f3e]81    int accept_bcast;
[32b8506]82
[1a3d1f3e]83    /* Tasks waiting for interrupts */
84    rtems_id rx_task;
85    rtems_id tx_task;
[32b8506]86
[1a3d1f3e]87    eth_stats_t stats;
88
89} mc9328mxl_enet_softc_t;
90
91static mc9328mxl_enet_softc_t softc;
92
93
94/* function prototypes */
[32b8506]95int rtems_mc9328mxl_enet_attach(struct rtems_bsdnet_ifconfig *config,
[1a3d1f3e]96                                void *chip);
97void mc9328mxl_enet_init(void *arg);
98void mc9328mxl_enet_init_hw(mc9328mxl_enet_softc_t *sc);
99void mc9328mxl_enet_start(struct ifnet *ifp);
100void mc9328mxl_enet_stop (mc9328mxl_enet_softc_t *sc);
101void mc9328mxl_enet_tx_task (void *arg);
102void mc9328mxl_enet_sendpacket (struct ifnet *ifp, struct mbuf *m);
103void mc9328mxl_enet_rx_task(void *arg);
104void mc9328mxl_enet_stats(mc9328mxl_enet_softc_t *sc);
[32b8506]105static int mc9328mxl_enet_ioctl(struct ifnet *ifp,
[7a5265ff]106                                ioctl_command_t command, caddr_t data);
[1a3d1f3e]107
108
109int rtems_mc9328mxl_enet_attach (
110    struct rtems_bsdnet_ifconfig *config,
111    void *chip  /* only one ethernet, so no chip number */
112    )
113{
114    struct ifnet *ifp;
115    int mtu;
116    int unitnumber;
117    char *unitname;
118    int tmp;
[32b8506]119
[1a3d1f3e]120    /*
121     * Parse driver name
122     */
123    unitnumber = rtems_bsdnet_parse_driver_name(config, &unitname);
124    if (unitnumber < 0) {
125        return 0;
126    }
[32b8506]127
[1a3d1f3e]128    /*
129     * Is driver free?
130     */
131    if (unitnumber != 0) {
132        printf ("Bad MC9328MXL unit number.\n");
133        return 0;
134    }
135
136    ifp = &softc.arpcom.ac_if;
137    if (ifp->if_softc != NULL) {
138        printf ("Driver already in use.\n");
139        return 0;
140    }
[32b8506]141
[1a3d1f3e]142    /* zero out the control structure  */
143    memset( &softc, 0, sizeof(softc) );
[32b8506]144
145
[1a3d1f3e]146    /* set the MAC address */
147    tmp = lan91c11x_read_reg(LAN91C11X_IA0);
148    softc.arpcom.ac_enaddr[0] = tmp & 0xff;
149    softc.arpcom.ac_enaddr[1] = (tmp >> 8) & 0xff;
150
151    tmp = lan91c11x_read_reg(LAN91C11X_IA2);
152    softc.arpcom.ac_enaddr[2] = tmp & 0xff;
153    softc.arpcom.ac_enaddr[3] = (tmp >> 8) & 0xff;
154
155    tmp = lan91c11x_read_reg(LAN91C11X_IA4);
156    softc.arpcom.ac_enaddr[4] = tmp & 0xff;
157    softc.arpcom.ac_enaddr[5] = (tmp >> 8) & 0xff;
158
159    if (config->mtu) {
160        mtu = config->mtu;
161    } else {
162        mtu = ETHERMTU;
163    }
164
165    softc.accept_bcast = !config->ignore_broadcast;
[32b8506]166
[1a3d1f3e]167    /*
168     * Set up network interface values
169     */
170    ifp->if_softc = &softc;
171    ifp->if_unit = unitnumber;
172    ifp->if_name = unitname;
173    ifp->if_mtu = mtu;
174    ifp->if_init = mc9328mxl_enet_init;
175    ifp->if_ioctl = mc9328mxl_enet_ioctl;
176    ifp->if_start = mc9328mxl_enet_start;
177    ifp->if_output = ether_output;
178    ifp->if_flags = IFF_BROADCAST;
179    if (ifp->if_snd.ifq_maxlen == 0) {
180        ifp->if_snd.ifq_maxlen = ifqmaxlen;
181    }
[32b8506]182
[1a3d1f3e]183    /* Attach the interface */
184    if_attach (ifp);
185    ether_ifattach (ifp);
186    return 1;
187}
188
189void mc9328mxl_enet_init(void *arg)
190{
[32b8506]191    mc9328mxl_enet_softc_t     *sc = arg;
[1a3d1f3e]192    struct ifnet *ifp = &sc->arpcom.ac_if;
[32b8506]193
194    /*
195     *This is for stuff that only gets done once (mc9328mxl_enet_init()
196     * gets called multiple times
[1a3d1f3e]197     */
198    if (sc->tx_task == 0)
199    {
200        /* Set up ENET hardware */
201        mc9328mxl_enet_init_hw(sc);
[32b8506]202
[1a3d1f3e]203        /* Start driver tasks */
[32b8506]204        sc->rx_task = rtems_bsdnet_newproc("ENrx",
205                                           4096,
206                                           mc9328mxl_enet_rx_task,
[1a3d1f3e]207                                           sc);
[32b8506]208        sc->tx_task = rtems_bsdnet_newproc("ENtx",
209                                           4096,
210                                           mc9328mxl_enet_tx_task,
[1a3d1f3e]211                                           sc);
212    } /* if tx_task */
[32b8506]213
[1a3d1f3e]214
215    /* Configure for promiscuous if needed */
216    if (ifp->if_flags & IFF_PROMISC) {
[32b8506]217        lan91c11x_write_reg(LAN91C11X_RCR,
[1a3d1f3e]218                            (lan91c11x_read_reg(LAN91C11X_RCR) |
219                             LAN91C11X_RCR_PRMS));
220    }
[32b8506]221
222
[1a3d1f3e]223    /*
224     * Tell the world that we're running.
225     */
226    ifp->if_flags |= IFF_RUNNING;
[32b8506]227
[1a3d1f3e]228    /* Enable TX/RX */
[32b8506]229    lan91c11x_write_reg(LAN91C11X_TCR,
[1a3d1f3e]230                        (lan91c11x_read_reg(LAN91C11X_TCR) |
231                         LAN91C11X_TCR_TXENA));
232
[32b8506]233    lan91c11x_write_reg(LAN91C11X_RCR,
[1a3d1f3e]234                        (lan91c11x_read_reg(LAN91C11X_RCR) |
235                         LAN91C11X_RCR_RXEN));
[32b8506]236
[1a3d1f3e]237
238} /* mc9328mxl_enet_init() */
239
240void  mc9328mxl_enet_init_hw(mc9328mxl_enet_softc_t *sc)
241{
242    uint16_t stat;
243    uint16_t my = 0;
244
245    lan91c11x_write_reg(LAN91C11X_RCR, LAN91C11X_RCR_RST);
246    lan91c11x_write_reg(LAN91C11X_RCR, 0);
247    rtems_task_wake_after(1);
248
249    /* Reset the PHY */
250    lan91c11x_write_phy_reg(PHY_CTRL, PHY_CTRL_RST);
251    while(lan91c11x_read_phy_reg(PHY_CTRL) & PHY_CTRL_RST) {
252        rtems_task_wake_after(1);
253    }
254
255
256    stat = lan91c11x_read_phy_reg(PHY_STAT);
[32b8506]257
[1a3d1f3e]258    if(stat & PHY_STAT_CAPT4) {
259        my |= PHY_ADV_T4;
260    }
261/* 100Mbs doesn't work, so we won't advertise it */
262
263    if(stat & PHY_STAT_CAPTXF) {
264        my |= PHY_ADV_TXFDX;
265    }
266    if(stat & PHY_STAT_CAPTXH) {
267        my |= PHY_ADV_TXHDX;
268    }
269
270    if(stat & PHY_STAT_CAPTF) {
271        my |= PHY_ADV_10FDX;
272    }
273
274    if(stat & PHY_STAT_CAPTH) {
275        my |= PHY_ADV_10HDX;
276    }
[32b8506]277
[1a3d1f3e]278    my |= PHY_ADV_CSMA;
[32b8506]279
[1a3d1f3e]280    lan91c11x_write_phy_reg(PHY_AD, my);
281
282
283    /* Enable Autonegotiation */
284#if 0
[32b8506]285    lan91c11x_write_phy_reg(PHY_CTRL,
[1a3d1f3e]286                            (PHY_CTRL_ANEGEN | PHY_CTRL_ANEGRST));
287#endif
288
289    /* Enable full duplex, let MAC take care
290     * of padding and CRC.
291     */
[32b8506]292    lan91c11x_write_reg(LAN91C11X_TCR,
[1a3d1f3e]293                        (LAN91C11X_TCR_PADEN |
294                         LAN91C11X_TCR_SWFDUP));
295
296    /* Disable promisc, don'tstrip CRC */
297    lan91c11x_write_reg(LAN91C11X_RCR, 0);
298
299    /* Enable auto-negotiation, LEDA is link, LEDB is traffic */
[32b8506]300    lan91c11x_write_reg(LAN91C11X_RPCR,
[1a3d1f3e]301                        (LAN91C11X_RPCR_ANEG |
302                         LAN91C11X_RPCR_LS2B));
303
304    /* Don't add wait states, enable PHY power */
305    lan91c11x_write_reg(LAN91C11X_CONFIG,
306                        (LAN91C11X_CONFIG_NOWAIT |
307                         LAN91C11X_CONFIG_PWR));
308
309    /* Disable error interrupts, enable auto release */
310    lan91c11x_write_reg(LAN91C11X_CTRL, LAN91C11X_CTRL_AUTO);
[32b8506]311
[1a3d1f3e]312    /* Reset MMU */
[32b8506]313    lan91c11x_write_reg(LAN91C11X_MMUCMD,
[1a3d1f3e]314                        LAN91C11X_MMUCMD_RESETMMU );
315
316
317    rtems_task_wake_after(100);
318    /* Enable Autonegotiation */
319    lan91c11x_write_phy_reg(PHY_CTRL, 0x3000);
320    rtems_task_wake_after(100);
321
322    /* Enable Interrupts for RX */
323    lan91c11x_write_reg(LAN91C11X_INT, LAN91C11X_INT_RXMASK);
324
325    /* Enable interrupts on GPIO Port A3 */
326    /*   Make pin 3 an input */
[32b8506]327    MC9328MXL_GPIOA_DDIR &= ~bit(3);
[1a3d1f3e]328
329    /*   Use GPIO function for pin 3 */
330    MC9328MXL_GPIOA_GIUS |= bit(3);
331
332    /*   Set for active high, level triggered interupt */
333    MC9328MXL_GPIOA_ICR1 = ((MC9328MXL_GPIOA_ICR1 & ~(3 << 6)) |
334                              (2 << 6));
335
336    /*   Enable GPIO port A3 interrupt */
337    MC9328MXL_GPIOA_IMR |= bit(3);
338
339    /* Install the interrupt handler */
340    BSP_install_rtems_irq_handler(&mc9328mxl_enet_isr_data);
[32b8506]341
[1a3d1f3e]342} /* mc9328mxl_enet_init_hw() */
343
344void mc9328mxl_enet_start(struct ifnet *ifp)
345{
346    mc9328mxl_enet_softc_t *sc = ifp->if_softc;
[32b8506]347
[1a3d1f3e]348    rtems_event_send(sc->tx_task, START_TRANSMIT_EVENT);
349    ifp->if_flags |= IFF_OACTIVE;
350}
351
352void mc9328mxl_enet_stop (mc9328mxl_enet_softc_t *sc)
353{
354    struct ifnet *ifp = &sc->arpcom.ac_if;
[32b8506]355
[1a3d1f3e]356    ifp->if_flags &= ~IFF_RUNNING;
[32b8506]357
[1a3d1f3e]358
359    /* Stop the transmitter and receiver. */
[32b8506]360    lan91c11x_write_reg(LAN91C11X_TCR,
361                        (lan91c11x_read_reg(LAN91C11X_TCR) &
[1a3d1f3e]362                         ~LAN91C11X_TCR_TXENA));
363
[32b8506]364    lan91c11x_write_reg(LAN91C11X_RCR,
365                        (lan91c11x_read_reg(LAN91C11X_RCR) &
[1a3d1f3e]366                        ~LAN91C11X_RCR_RXEN));
[32b8506]367
[1a3d1f3e]368}
369
370/*
371 * Driver transmit daemon
372 */
373void mc9328mxl_enet_tx_task(void *arg)
374{
375    mc9328mxl_enet_softc_t *sc = (mc9328mxl_enet_softc_t *)arg;
376    struct ifnet *ifp = &sc->arpcom.ac_if;
377    struct mbuf *m;
378    rtems_event_set events;
[32b8506]379
[1a3d1f3e]380    for (;;)
381    {
382        rtems_bsdnet_event_receive(
383            START_TRANSMIT_EVENT,
384            RTEMS_EVENT_ANY | RTEMS_WAIT,
385            RTEMS_NO_TIMEOUT,
386            &events);
[32b8506]387
[1a3d1f3e]388        /* Send packets till queue is empty */
389        for (;;)
390        {
391            /* Get the next mbuf chain to transmit. */
392            IF_DEQUEUE(&ifp->if_snd, m);
393            if (!m) {
394                break;
395            }
396            mc9328mxl_enet_sendpacket (ifp, m);
397            softc.stats.tx_packets++;
[32b8506]398
[1a3d1f3e]399        }
400        ifp->if_flags &= ~IFF_OACTIVE;
401    }
402}
403
404/* Send packet */
405void mc9328mxl_enet_sendpacket (struct ifnet *ifp, struct mbuf *m)
406{
407    struct mbuf *l = NULL;
408    int size = 0;
409    int tmp;
410    int i;
411    int start;
412    uint16_t d;
413
414    /* How big is the packet ? */
415    l = m;
416    do {
417        size += l->m_len;
418        l = l->m_next;
419    } while (l != NULL);
420
421    /* Allocate a TX buffer */
[32b8506]422    lan91c11x_write_reg(LAN91C11X_MMUCMD,
[1a3d1f3e]423                        (LAN91C11X_MMUCMD_ALLOCTX |
424                         (size >> 8)));
425
426    /* Wait for the allocation */
427    while ((lan91c11x_read_reg(LAN91C11X_INT) & LAN91C11X_INT_ALLOC) == 0) {
428        continue;
429    }
430
431    tmp = lan91c11x_read_reg(LAN91C11X_PNR);
432    lan91c11x_write_reg(LAN91C11X_PNR, ((tmp >> 8) & 0xff));
433
434    /* Set the data pointer for auto increment */
435    lan91c11x_write_reg(LAN91C11X_PTR, LAN91C11X_PTR_AUTOINC);
436
437    /* A delay is needed between pointer and data access ?!? */
438    for (i = 0; i < 10; i++) {
439        continue;
440    }
441
442    /* Write status word */
443    lan91c11x_write_reg(LAN91C11X_DATA, 0);
444
445    /* Write byte count */
446    if (size & 1) {
447        size++;
448    }
[32b8506]449    lan91c11x_write_reg(LAN91C11X_DATA, size + 6);
[1a3d1f3e]450
451    lan91c11x_lock();
452
453    /* Copy the mbuf */
[32b8506]454    l = m;
[1a3d1f3e]455    start = 0;
456    d = 0;
457    while (l != NULL)
458    {
459        uint8_t *data;
[32b8506]460
[1a3d1f3e]461        data = mtod(l, uint8_t *);
462
463        for (i = start; i < l->m_len; i++) {
464            if ((i & 1) == 0) {
465                d = data[i] << 8;
466            } else {
467                d = d | data[i];
468                lan91c11x_write_reg_fast(LAN91C11X_DATA, htons(d));
469            }
470        }
471
472        /* If everything is 2 byte aligned, i will be even */
473        start = (i & 1);
474
475        l = l->m_next;
476    }
[32b8506]477
[1a3d1f3e]478    /* write control byte */
479    if (i & 1) {
[32b8506]480        lan91c11x_write_reg_fast(LAN91C11X_DATA,
[1a3d1f3e]481                            htons(LAN91C11X_PKT_CTRL_ODD | d));
482    } else {
483        lan91c11x_write_reg_fast(LAN91C11X_DATA, 0);
484    }
485
486    lan91c11x_unlock();
487
488    /* Enable TX interrupts */
[32b8506]489    lan91c11x_write_reg(LAN91C11X_INT,
[1a3d1f3e]490                        (lan91c11x_read_reg(LAN91C11X_INT) |
491                         LAN91C11X_INT_TXMASK |
492                         LAN91C11X_INT_TXEMASK));
493
494    /* Enqueue it */
[32b8506]495    lan91c11x_write_reg(LAN91C11X_MMUCMD,
[1a3d1f3e]496                        LAN91C11X_MMUCMD_ENQUEUE);
[32b8506]497
[1a3d1f3e]498    /* free the mbuf chain we just copied */
499    m_freem(m);
[32b8506]500
[1a3d1f3e]501} /* mc9328mxl_enet_sendpacket () */
502
503
504/* reader task */
505void mc9328mxl_enet_rx_task(void *arg)
506{
507    mc9328mxl_enet_softc_t *sc = (mc9328mxl_enet_softc_t *)arg;
508    struct ifnet *ifp = &sc->arpcom.ac_if;
509    struct mbuf *m;
510    struct ether_header *eh;
511    rtems_event_set events;
512    int pktlen;
513    uint16_t rsw;
514    uint16_t bc;
515    uint16_t cbyte;
516    int i;
517    uint16_t int_reg;
518
519    /* Input packet handling loop */
520    while (1) {
521        rtems_bsdnet_event_receive(
522            START_RECEIVE_EVENT,
523            RTEMS_EVENT_ANY | RTEMS_WAIT,
524            RTEMS_NO_TIMEOUT,
525            &events);
526
527        /* Configure for reads from RX data area */
[32b8506]528        lan91c11x_write_reg(LAN91C11X_PTR,
[1a3d1f3e]529                            (LAN91C11X_PTR_AUTOINC |
530                             LAN91C11X_PTR_RCV |
531                             LAN91C11X_PTR_READ));
532
533        /* read the receive status word */
534        rsw = lan91c11x_read_reg(LAN91C11X_DATA);
535        /* TBD: Need to check rsw here */
536
537        /* read the byte count */
538        bc = lan91c11x_read_reg(LAN91C11X_DATA);
539        pktlen = (bc & 0x7ff) - 6;
540
541        /* get an mbuf for this packet */
542        MGETHDR(m, M_WAIT, MT_DATA);
[32b8506]543
[1a3d1f3e]544        /* now get a cluster pointed to by the mbuf */
545        /* since an mbuf by itself is too small */
546        MCLGET(m, M_WAIT);
547
548        lan91c11x_lock();
[32b8506]549
[1a3d1f3e]550        /* Copy the received packet into an mbuf */
551        for (i = 0; i < (pktlen / 2); i++) {
[32b8506]552            ((uint16_t*)m->m_ext.ext_buf)[i] =
[1a3d1f3e]553                lan91c11x_read_reg_fast(LAN91C11X_DATA);
554        }
555
556        cbyte = lan91c11x_read_reg_fast(LAN91C11X_DATA);
557        if (cbyte & LAN91C11X_PKT_CTRL_ODD) {
558            ((uint16_t*)m->m_ext.ext_buf)[i] = cbyte;
559            pktlen++;
560        }
561        lan91c11x_unlock();
562
563        /* Release the packets memory */
[32b8506]564        lan91c11x_write_reg(LAN91C11X_MMUCMD,
[1a3d1f3e]565                            LAN91C11X_MMUCMD_REMTOP);
566
567        /* set the receiving interface */
568        m->m_pkthdr.rcvif = ifp;
569        m->m_nextpkt = 0;
[32b8506]570
[1a3d1f3e]571        /* set the length of the mbuf */
572        m->m_len = pktlen - (sizeof(struct ether_header));
573        m->m_pkthdr.len = m->m_len;
[32b8506]574
[1a3d1f3e]575        /* strip off the ethernet header from the mbuf */
576        /* but save the pointer to it */
577        eh = mtod (m, struct ether_header *);
578        m->m_data += sizeof(struct ether_header);
[32b8506]579
580
[1a3d1f3e]581        softc.stats.rx_packets++;
582
583        /* give all this stuff to the stack */
584        ether_input(ifp, eh, m);
585
586        /* renable RX interrupts */
587        int_reg = lan91c11x_read_reg(LAN91C11X_INT);
588        int_reg |= LAN91C11X_INT_RXMASK;
589        lan91c11x_write_reg(LAN91C11X_INT, int_reg);
590
591    }
[32b8506]592} /* mc9328mxl_enet_rx_task */
[1a3d1f3e]593
594
595/* Show interface statistics */
596void mc9328mxl_enet_stats (mc9328mxl_enet_softc_t *sc)
597{
598    printf (" Total Interrupts:%-8lu",         sc->stats.interrupts);
599    printf ("   Rx Interrupts:%-8lu",          sc->stats.rx_interrupts);
600    printf ("   Tx Interrupts:%-8lu\n",        sc->stats.tx_interrupts);
601    printf (" Tx Error Interrupts:%-8lu\n",    sc->stats.txerr_interrupts);
602    printf (" Rx Packets:%-8lu",               sc->stats.rx_packets);
603    printf ("   Tx Packets:%-8lu\n",           sc->stats.tx_packets);
604}
605
606
607/* Enables mc9328mxl_enet interrupts. */
608static void enet_isr_on(const rtems_irq_connect_data *unused)
609{
610    /* Enable interrupts */
611    MC9328MXL_AITC_INTENNUM = MC9328MXL_INT_GPIO_PORTA;
[32b8506]612
[1a3d1f3e]613    return;
614}
615
616/* Disables enet interrupts */
617static void enet_isr_off(const rtems_irq_connect_data *unused)
618{
619    /* disable all various TX/RX interrupts */
620    MC9328MXL_AITC_INTDISNUM = MC9328MXL_INT_GPIO_PORTA;
621
622    return;
623}
624
625/* Tests to see if mc9328mxl_enet interrupts are enabled, and returns non-0 if so.
626 * If interrupt is not enabled, returns 0.
627 */
628static int enet_isr_is_on(const rtems_irq_connect_data *irq)
629{
630    return MC9328MXL_AITC_INTENABLEL & (1 << MC9328MXL_INT_GPIO_PORTA);
631}
632
633/*  Driver ioctl handler */
634static int
[7a5265ff]635mc9328mxl_enet_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
[1a3d1f3e]636{
637    mc9328mxl_enet_softc_t *sc = ifp->if_softc;
638    int error = 0;
[32b8506]639
[1a3d1f3e]640    switch (command) {
641    case SIOCGIFADDR:
642    case SIOCSIFADDR:
643        ether_ioctl (ifp, command, data);
644        break;
[32b8506]645
[1a3d1f3e]646    case SIOCSIFFLAGS:
647        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
648        {
649        case IFF_RUNNING:
650            mc9328mxl_enet_stop (sc);
651            break;
[32b8506]652
[1a3d1f3e]653        case IFF_UP:
654            mc9328mxl_enet_init (sc);
655            break;
[32b8506]656
[1a3d1f3e]657        case IFF_UP | IFF_RUNNING:
658            mc9328mxl_enet_stop (sc);
659            mc9328mxl_enet_init (sc);
660            break;
[32b8506]661
[1a3d1f3e]662        default:
663            break;
664        } /* switch (if_flags) */
665        break;
[32b8506]666
[1a3d1f3e]667    case SIO_RTEMS_SHOW_STATS:
668        mc9328mxl_enet_stats (sc);
669        break;
[32b8506]670
[1a3d1f3e]671        /*
672         * FIXME: All sorts of multicast commands need to be added here!
673         */
674    default:
675        error = EINVAL;
676        break;
677    } /* switch (command) */
678    return error;
679}
680
681/* interrupt handler */
[9c05850c]682static void enet_isr(rtems_irq_hdl_param unused)
[1a3d1f3e]683{
684    uint16_t int_reg;
685
686    softc.stats.interrupts++;
687    /* get the ISR status and determine RX or TX */
688    int_reg = lan91c11x_read_reg(LAN91C11X_INT);
[32b8506]689
[1a3d1f3e]690    /* Handle RX interrupts */
691    if ((int_reg & LAN91C11X_INT_RX) && (int_reg & LAN91C11X_INT_RXMASK)) {
692        softc.stats.rx_interrupts++;
693
694        /* Disable the interrupt */
695        int_reg &= ~LAN91C11X_INT_RXMASK;
[32b8506]696
[1a3d1f3e]697        rtems_event_send (softc.rx_task, START_RECEIVE_EVENT);
698    }
699
700    /* Handle TX Empty interrupts */
701    if ((int_reg & LAN91C11X_INT_TXE) && (int_reg & LAN91C11X_INT_TXEMASK)) {
702        softc.stats.tx_interrupts++;
703
704        /* Disable the interrupt */
705        int_reg &= ~LAN91C11X_INT_TXEMASK;
706
707        /* Acknowledge the interrupt */
708        int_reg |= LAN91C11X_INT_TXE;
709
710        rtems_event_send(softc.tx_task, START_TRANSMIT_EVENT);
711
712    }
713
714    /* Handle interrupts for transmit errors */
715    if ((int_reg & LAN91C11X_INT_TX) && (int_reg & LAN91C11X_INT_TXMASK)) {
716        softc.stats.txerr_interrupts++;
717        printk("Caught TX interrupt - error on transmission\n");
718    }
[32b8506]719
[1a3d1f3e]720    /* Update the interrupt register on the 91c11x */
721    lan91c11x_write_reg(LAN91C11X_INT, int_reg);
722
723    /* clear GPIO Int. status */
724    MC9328MXL_GPIOA_ISR |= bit(3);
725}
726
Note: See TracBrowser for help on using the repository browser.