source: rtems/c/src/lib/libbsp/arm/atsam/network/if_atsam.c @ f6fdf2e

5
Last change on this file since f6fdf2e was f6fdf2e, checked in by Alexander Krutwig <alexander.krutwig@…>, on 07/25/16 at 13:11:07

atsam: Add user defined RX/TX descriptor counts

  • Property mode set to 100644
File size: 32.0 KB
Line 
1/*
2 * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <libchip/chip.h>
33#include <libchip/include/gmacd.h>
34#include <libchip/include/pio.h>
35
36#define __INSIDE_RTEMS_BSD_TCPIP_STACK__        1
37#define __BSD_VISIBLE                           1
38
39#include <bsp.h>
40#include <bsp/irq.h>
41
42#include <stdio.h>
43
44#include <rtems/error.h>
45#include <rtems/rtems_bsdnet.h>
46#include <rtems/rtems_mii_ioctl.h>
47
48#include <sys/types.h>
49#include <sys/ioctl.h>
50#include <sys/param.h>
51#include <sys/mbuf.h>
52#include <sys/socket.h>
53#include <sys/sockio.h>
54
55#include <net/if.h>
56#include <net/if_var.h>
57#include <net/if_types.h>
58
59#include <netinet/in.h>
60#include <netinet/if_ether.h>
61
62#include <dev/mii/mii.h>
63
64/*
65 * Number of interfaces supported by the driver
66 */
67#define NIFACES                 1
68
69/** Enable/Disable CopyAllFrame */
70#define GMAC_CAF_DISABLE        0
71#define GMAC_CAF_ENABLE         1
72
73/** Enable/Disable NoBroadCast */
74#define GMAC_NBC_DISABLE        0
75#define GMAC_NBC_ENABLE         1
76
77/** The PIN list of PIO for GMAC */
78#define BOARD_GMAC_PINS                                                    \
79        { (PIO_PD0A_GTXCK | PIO_PD1A_GTXEN | PIO_PD2A_GTX0 | PIO_PD3A_GTX1 \
80          | PIO_PD4A_GRXDV | PIO_PD5A_GRX0 | PIO_PD6A_GRX1                 \
81          | PIO_PD7A_GRXER                                                 \
82          | PIO_PD8A_GMDC | PIO_PD9A_GMDIO), PIOD, ID_PIOD, PIO_PERIPH_A,  \
83          PIO_DEFAULT }
84/** The runtime pin configure list for GMAC */
85#define BOARD_GMAC_RUN_PINS                     BOARD_GMAC_PINS
86
87/** The PIN list of PIO for GMAC */
88#define BOARD_GMAC_RESET_PIN                                               \
89                                                { PIO_PC10, PIOC, ID_PIOC, \
90                                                          PIO_OUTPUT_1,    \
91                                                          PIO_PULLUP }
92
93/** Multicast Enable */
94#define GMAC_MC_ENABLE                          (1u << 6)
95#define HASH_INDEX_AMOUNT                       6
96#define HASH_ELEMENTS_PER_INDEX                 8
97#define MAC_ADDR_MASK                           0x0000FFFFFFFFFFFF
98#define MAC_IDX_MASK                            (1u << 0)
99
100/** Promiscuous Mode Enable */
101#define GMAC_PROM_ENABLE                        (1u << 4)
102
103/** RX Defines */
104#define GMAC_RX_BUFFER_SIZE                     1536
105#define GMAC_RX_BUF_DESC_ADDR_MASK              0xFFFFFFFC
106#define GMAC_RX_SET_OFFSET                      (1u << 15)
107#define GMAC_RX_SET_USED_WRAP                   ((1u << 1) | (1u << 0))
108#define GMAC_RX_SET_WRAP                        (1u << 1)
109#define GMAC_RX_SET_USED                        (1u << 0)
110/** TX Defines */
111#define GMAC_TX_SET_EOF                         (1u << 15)
112#define GMAC_TX_SET_WRAP                        (1u << 30)
113#define GMAC_TX_SET_USED                        (1u << 31)
114
115#define GMAC_DESCRIPTOR_ALIGNMENT               8
116
117/** Events */
118#define ATSAMV7_ETH_RX_EVENT_INTERRUPT          RTEMS_EVENT_1
119#define ATSAMV7_ETH_TX_EVENT_INTERRUPT          RTEMS_EVENT_2
120#define ATSAMV7_ETH_START_TRANSMIT_EVENT        RTEMS_EVENT_3
121
122#define ATSAMV7_ETH_RX_DATA_OFFSET              2
123
124#define WATCHDOG_TIMEOUT                        5
125
126/** The PINs for GMAC */
127static const Pin gmacPins[] = { BOARD_GMAC_RUN_PINS };
128
129static const Pin gmacResetPin = BOARD_GMAC_RESET_PIN;
130
131typedef struct if_atsam_gmac {
132        /** The GMAC driver instance */
133        sGmacd gGmacd;
134        uint32_t retries;
135        uint8_t phy_address;
136} if_atsam_gmac;
137
138typedef struct ring_buffer {
139        unsigned tx_bd_used;
140        unsigned tx_bd_free;
141        size_t length;
142} ring_buffer;
143
144/*
145 * Per-device data
146 */
147typedef struct if_atsam_softc {
148        /*
149         * Data
150         */
151        struct arpcom arpcom;
152        if_atsam_gmac Gmac_inst;
153        struct rtems_mdio_info mdio;
154        uint8_t GMacAddress[6];
155        rtems_id rx_daemon_tid;
156        rtems_id tx_daemon_tid;
157        rtems_vector_number interrupt_number;
158        struct mbuf **rx_mbuf;
159        struct mbuf **tx_mbuf;
160        volatile sGmacTxDescriptor *tx_bd_base;
161        uint32_t anlpar;
162        size_t rx_bd_fill_idx;
163        size_t amount_rx_buf;
164        size_t amount_tx_buf;
165        ring_buffer tx_ring;
166
167        /*
168         * Statistics
169         */
170        unsigned rx_overrun_errors;
171        unsigned rx_interrupts;
172        unsigned tx_complete_int;
173        unsigned tx_tur_errors;
174        unsigned tx_rlex_errors;
175        unsigned tx_tfc_errors;
176        unsigned tx_hresp_errors;
177        unsigned tx_interrupts;
178} if_atsam_softc;
179
180static struct if_atsam_softc if_atsam_softc_inst;
181
182static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp)
183{
184        struct mbuf *m;
185
186        MGETHDR(m, M_DONTWAIT, MT_DATA);
187        if (m != NULL) {
188                MCLGET(m, M_DONTWAIT);
189                if ((m->m_flags & M_EXT) != 0) {
190                        m->m_pkthdr.rcvif = ifp;
191                        m->m_data = mtod(m, char *);
192                        rtems_cache_invalidate_multiple_data_lines(mtod(m, void *),
193                            GMAC_RX_BUFFER_SIZE);
194                } else {
195                        m_free(m);
196                        m = NULL;
197                }
198        }
199        return (m);
200}
201
202
203static uint8_t if_atsam_wait_phy(Gmac *pHw, uint32_t retry)
204{
205        volatile uint32_t retry_count = 0;
206
207        while (!GMAC_IsIdle(pHw)) {
208                if (retry == 0) {
209                        continue;
210                }
211                retry_count++;
212
213                if (retry_count >= retry) {
214                        return (1);
215                }
216                rtems_task_wake_after(1);
217        }
218
219        return (0);
220}
221
222
223static uint8_t
224if_atsam_write_phy(Gmac *pHw, uint8_t PhyAddress, uint8_t Address,
225    uint32_t Value, uint32_t retry)
226{
227        GMAC_PHYMaintain(pHw, PhyAddress, Address, 0, (uint16_t)Value);
228        if (if_atsam_wait_phy(pHw, retry) == 1) {
229                return (1);
230        }
231        return (0);
232}
233
234
235static uint8_t
236if_atsam_read_phy(Gmac *pHw,
237    uint8_t PhyAddress, uint8_t Address, uint32_t *pvalue, uint32_t retry)
238{
239        GMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0);
240        if (if_atsam_wait_phy(pHw, retry) == 1) {
241                return (1);
242        }
243        *pvalue = GMAC_PHYData(pHw);
244        return (0);
245}
246
247
248static void atsamv7_find_valid_phy(if_atsam_gmac *gmac_inst)
249{
250        Gmac *pHw = gmac_inst->gGmacd.pHw;
251
252        uint32_t retry_max;
253        uint32_t value = 0;
254        uint8_t rc;
255        uint8_t phy_address;
256
257        phy_address = gmac_inst->phy_address;
258        retry_max = gmac_inst->retries;
259
260        if (phy_address != 0xFF) {
261                return;
262        }
263
264        /* Find another one */
265        rc = 0xFF;
266
267        for (phy_address = 0; phy_address < 32; ++phy_address) {
268                int rv;
269
270                rv = if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1,
271                    &value, retry_max);
272                if (rv == 0 && value != 0 && value >= 0xffff) {
273                        rc = phy_address;
274                        break;
275                }
276        }
277
278        if (rc != 0xFF) {
279                if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1, &value,
280                    retry_max);
281                if_atsam_read_phy(pHw, phy_address, MII_PHYIDR2, &value,
282                    retry_max);
283                gmac_inst->phy_address = phy_address;
284        }
285}
286
287
288static uint8_t if_atsam_reset_phy(if_atsam_gmac *gmac_inst)
289{
290        uint32_t retry_max;
291        uint32_t bmcr;
292        uint8_t phy_address;
293        uint32_t timeout = 10;
294        uint8_t ret = 0;
295
296        Gmac *pHw = gmac_inst->gGmacd.pHw;
297
298        phy_address = gmac_inst->phy_address;
299        retry_max = gmac_inst->retries;
300
301        bmcr = BMCR_RESET;
302        if_atsam_write_phy(pHw, phy_address, MII_BMCR, bmcr, retry_max);
303        do {
304                if_atsam_read_phy(pHw, phy_address, MII_BMCR, &bmcr,
305                    retry_max);
306                timeout--;
307        } while ((bmcr & BMCR_RESET) && timeout);
308
309        if (!timeout) {
310                ret = 1;
311        }
312        return (ret);
313}
314
315
316static uint8_t
317if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck,
318    const Pin *pResetPins, uint32_t nbResetPins, const Pin *pGmacPins,
319    uint32_t nbGmacPins)
320{
321        uint8_t rc = 1;
322        Gmac *pHw = gmac_inst->gGmacd.pHw;
323
324        /* Perform RESET */
325        if (pResetPins) {
326                /* Configure PINS */
327                PIO_Configure(pResetPins, nbResetPins);
328                PIO_Clear(pResetPins);
329                rtems_task_wake_after(1);
330                PIO_Set(pResetPins);
331        }
332        /* Configure GMAC runtime pins */
333        if (rc) {
334                PIO_Configure(pGmacPins, nbGmacPins);
335                rc = GMAC_SetMdcClock(pHw, mck);
336
337                if (!rc) {
338                        return (0);
339                }
340                if_atsam_reset_phy(gmac_inst);
341        }
342        return (rc);
343}
344
345static bool if_atsam_is_valid_phy(int phy)
346{
347        return phy >= 0 && phy <= 31;
348}
349
350static int if_atsam_mdio_read(int phy, void *arg, unsigned reg, uint32_t *pval)
351{
352        if_atsam_softc *sc = (if_atsam_softc *)arg;
353
354        if (!if_atsam_is_valid_phy(phy)) {
355                return (EINVAL);
356        }
357
358        return (if_atsam_read_phy(sc->Gmac_inst.gGmacd.pHw,
359            (uint8_t)phy, (uint8_t)reg, pval, sc->Gmac_inst.retries));
360}
361
362
363static int if_atsam_mdio_write(int phy, void *arg, unsigned reg, uint32_t pval)
364{
365        if_atsam_softc *sc = (if_atsam_softc *)arg;
366
367        if (!if_atsam_is_valid_phy(phy)) {
368                return (EINVAL);
369        }
370
371        return if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw,
372            (uint8_t)phy, (uint8_t)reg, pval, sc->Gmac_inst.retries);
373}
374
375
376/*
377 * Interrupt Handler for the network driver
378 */
379static void if_atsam_interrupt_handler(void *arg)
380{
381        if_atsam_softc *sc = (if_atsam_softc *)arg;
382        uint32_t irq_status_val;
383        rtems_event_set rx_event = 0;
384        rtems_event_set tx_event = 0;
385        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
386
387        /* Get interrupt status */
388        irq_status_val = GMAC_GetItStatus(pHw, 0);
389
390        /* Check receive interrupts */
391        if ((irq_status_val & GMAC_IER_ROVR) != 0) {
392                ++sc->rx_overrun_errors;
393                rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
394        }
395        if ((irq_status_val & GMAC_IER_RCOMP) != 0) {
396                rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
397        }
398        /* Send events to receive task and switch off rx interrupts */
399        if (rx_event != 0) {
400                ++sc->rx_interrupts;
401                /* Erase the interrupts for RX completion and errors */
402                GMAC_DisableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
403                (void)rtems_bsdnet_event_send(sc->rx_daemon_tid, rx_event);
404        }
405        if ((irq_status_val & GMAC_IER_TUR) != 0) {
406                ++sc->tx_tur_errors;
407                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
408        }
409        if ((irq_status_val & GMAC_IER_RLEX) != 0) {
410                ++sc->tx_rlex_errors;
411                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
412        }
413        if ((irq_status_val & GMAC_IER_TFC) != 0) {
414                ++sc->tx_tfc_errors;
415                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
416        }
417        if ((irq_status_val & GMAC_IER_HRESP) != 0) {
418                ++sc->tx_hresp_errors;
419                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
420        }
421        if ((irq_status_val & GMAC_IER_TCOMP) != 0) {
422                ++sc->tx_complete_int;
423                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
424        }
425        /* Send events to transmit task and switch off tx interrupts */
426        if (tx_event != 0) {
427                ++sc->tx_interrupts;
428                /* Erase the interrupts for TX completion and errors */
429                GMAC_DisableIt(pHw, GMAC_INT_TX_BITS, 0);
430                (void)rtems_bsdnet_event_send(sc->tx_daemon_tid, tx_event);
431        }
432}
433/*
434 * Receive daemon
435 */
436static void if_atsam_rx_daemon(void *arg)
437{
438        if_atsam_softc *sc = (if_atsam_softc *)arg;
439        rtems_event_set events = 0;
440        void *rx_bd_base;
441        struct mbuf *m;
442        struct mbuf *n;
443        volatile sGmacRxDescriptor *buffer_desc;
444        int frame_len;
445        struct ether_header *eh;
446        uint32_t tmp_rx_bd_address;
447
448        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
449
450        /* Allocate memory space for priority queue descriptor list */
451        rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor),
452                GMAC_DESCRIPTOR_ALIGNMENT, 0);
453        assert(rx_bd_base != NULL);
454
455        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
456        buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP;
457        buffer_desc->status.val = 0;
458
459        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1);
460        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2);
461
462        /* Allocate memory space for buffer descriptor list */
463        rx_bd_base = rtems_cache_coherent_allocate(
464                sc->amount_rx_buf * sizeof(sGmacRxDescriptor),
465                GMAC_DESCRIPTOR_ALIGNMENT, 0);
466        assert(rx_bd_base != NULL);
467        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
468
469        /* Create descriptor list and mark as empty */
470        for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf;
471            ++sc->rx_bd_fill_idx) {
472                m = if_atsam_new_mbuf(&sc->arpcom.ac_if);
473                assert(m != NULL);
474                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
475                buffer_desc->addr.val = ((uint32_t)m->m_data) &
476                    GMAC_RX_BUF_DESC_ADDR_MASK;
477                buffer_desc->status.val = 0;
478                if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) {
479                        buffer_desc->addr.bm.bWrap = 1;
480                } else {
481                        buffer_desc++;
482                }
483        }
484        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
485
486        /* Set 2 Byte Receive Buffer Offset */
487        pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET;
488
489        /* Write Buffer Queue Base Address Register */
490        GMAC_ReceiveEnable(pHw, 0);
491        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0);
492
493        /* Set address for address matching */
494        GMAC_SetAddress(pHw, 0, sc->GMacAddress);
495
496        /* Enable Receiving of data */
497        GMAC_ReceiveEnable(pHw, 1);
498
499        /* Setup the interrupts for RX completion and errors */
500        GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
501
502        sc->rx_bd_fill_idx = 0;
503
504        while (true) {
505                /* Wait for events */
506                rtems_bsdnet_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT,
507                    RTEMS_EVENT_ANY | RTEMS_WAIT,
508                    RTEMS_NO_TIMEOUT, &events);
509
510                /*
511                 * Check for all packets with a set ownership bit
512                 */
513                while (buffer_desc->addr.bm.bOwnership == 1) {
514                        if (buffer_desc->status.bm.bEof == 1) {
515                                m = sc->rx_mbuf[sc->rx_bd_fill_idx];
516
517                                /* New mbuf for desc */
518                                n = if_atsam_new_mbuf(&sc->arpcom.ac_if);
519                                if (n != NULL) {
520                                        frame_len = (int)
521                                            (buffer_desc->status.bm.len);
522
523                                        /* Discard Ethernet header */
524                                        int sz = frame_len - ETHER_HDR_LEN;
525
526                                        /* Update mbuf */
527                                        eh = (struct ether_header *)
528                                            (mtod(m, char *) + 2);
529                                        m->m_len = sz;
530                                        m->m_pkthdr.len = sz;
531                                        m->m_data = (void *)(eh + 1);
532                                        ether_input(&sc->arpcom.ac_if, eh, m);
533                                        m = n;
534                                } else {
535                                        (void)rtems_bsdnet_event_send(
536                                            sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT);
537                                }
538                                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
539                                tmp_rx_bd_address = (uint32_t)m->m_data &
540                                    GMAC_RX_BUF_DESC_ADDR_MASK;
541
542                                /* Switch pointer to next buffer descriptor */
543                                if (sc->rx_bd_fill_idx ==
544                                    (sc->amount_rx_buf - 1)) {
545                                        tmp_rx_bd_address |= GMAC_RX_SET_WRAP;
546                                        sc->rx_bd_fill_idx = 0;
547                                } else {
548                                        ++sc->rx_bd_fill_idx;
549                                }
550
551                                /*
552                                 * Give ownership to GMAC for further processing
553                                 */
554                                tmp_rx_bd_address &= ~GMAC_RX_SET_USED;
555                                _ARM_Data_synchronization_barrier();
556                                buffer_desc->addr.val = tmp_rx_bd_address;
557
558                                buffer_desc = (sGmacRxDescriptor *)rx_bd_base
559                                    + sc->rx_bd_fill_idx;
560                        }
561                }
562                /* Setup the interrupts for RX completion and errors */
563                GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
564        }
565}
566
567/*
568 * Update of current transmit buffer position.
569 */
570static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf)
571{
572        *pos = (*pos + 1) % amount_tx_buf;
573}
574
575/*
576 * Is RingBuffer empty
577 */
578static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer)
579{
580        return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free);
581}
582
583/*
584 * Is RingBuffer full
585 */
586static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer)
587{
588        size_t tx_bd_used_next = ring_buffer->tx_bd_used;
589
590        if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length);
591        return (tx_bd_used_next == ring_buffer->tx_bd_free);
592}
593
594/*
595 * Cleanup transmit file descriptors by freeing mbufs which are not needed any
596 * longer due to correct transmission.
597 */
598static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc)
599{
600        struct mbuf *m;
601        volatile sGmacTxDescriptor *cur;
602        bool eof_needed = false;
603
604        while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){
605                cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free;
606                if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) {
607                        eof_needed = true;
608                        cur->status.val |= GMAC_TX_SET_USED;
609                        m = sc->tx_mbuf[sc->tx_ring.tx_bd_free];
610                        m_free(m);
611                        sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0;
612                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free,
613                            sc->tx_ring.length);
614                        if (cur->status.bm.bLastBuffer) {
615                                eof_needed = false;
616                        }
617                } else {
618                        break;
619                }
620        }
621}
622
623/*
624 * Prepare Ethernet frame to start transmission.
625 */
626static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
627{
628        volatile sGmacTxDescriptor *cur;
629        volatile sGmacTxDescriptor *start_packet_tx_bd = 0;
630        int pos = 0;
631        uint32_t tmp_val = 0;
632        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
633        bool success;
634
635        if_atsam_tx_bd_cleanup(sc);
636        /* Wait for interrupt in case no buffer descriptors are available */
637        /* Wait for events */
638        while (true) {
639                if (if_atsam_ring_buffer_full(&sc->tx_ring)) {
640                        /* Setup the interrupts for TX completion and errors */
641                        GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0);
642                        success = false;
643                        break;
644                }
645
646                /*
647                 * Get current mbuf for data fill
648                 */
649                cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used];
650                /* Set the transfer data */
651                rtems_cache_flush_multiple_data_lines(mtod(m, const void *),
652                    (size_t)m->m_len);
653                if (m->m_len) {
654                        cur->addr = (uint32_t)(mtod(m, void *));
655                        tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED;
656                        if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) {
657                                tmp_val |= GMAC_TX_SET_WRAP;
658                        }
659                        if (pos == 0) {
660                                start_packet_tx_bd = cur;
661                        }
662                        sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m;
663                        m = m->m_next;
664                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used,
665                            sc->tx_ring.length);
666                } else {
667                        /* Discard empty mbufs */
668                        m = m_free(m);
669                }
670
671                /*
672                 * Send out the buffer once the complete mbuf_chain has been
673                 * processed
674                 */
675                if (m == NULL) {
676                        tmp_val |= GMAC_TX_SET_EOF;
677                        tmp_val &= ~GMAC_TX_SET_USED;
678                        _ARM_Data_synchronization_barrier();
679                        cur->status.val = tmp_val;
680                        start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED;
681                        _ARM_Data_synchronization_barrier();
682                        GMAC_TransmissionStart(pHw);
683                        success = true;
684                        break;
685                } else {
686                        if (pos > 0) {
687                                tmp_val &= ~GMAC_TX_SET_USED;
688                        }
689                        pos++;
690                        cur->status.val = tmp_val;
691                }
692        }
693        return success;
694}
695
696
697/*
698 * Transmit daemon
699 */
700static void if_atsam_tx_daemon(void *arg)
701{
702        if_atsam_softc *sc = (if_atsam_softc *)arg;
703        rtems_event_set events = 0;
704        sGmacTxDescriptor *buffer_desc;
705        int bd_number;
706        void *tx_bd_base;
707        struct mbuf *m;
708        bool success;
709
710        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
711        struct ifnet *ifp = &sc->arpcom.ac_if;
712
713        GMAC_TransmitEnable(pHw, 0);
714
715        /* Allocate memory space for priority queue descriptor list */
716        tx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacTxDescriptor),
717                GMAC_DESCRIPTOR_ALIGNMENT, 0);
718        assert(tx_bd_base != NULL);
719
720        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
721        buffer_desc->addr = 0;
722        buffer_desc->status.val = GMAC_TX_SET_USED | GMAC_TX_SET_WRAP;
723
724        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 1);
725        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 2);
726
727        /* Allocate memory space for buffer descriptor list */
728        tx_bd_base = rtems_cache_coherent_allocate(
729                sc->amount_tx_buf * sizeof(sGmacTxDescriptor),
730                GMAC_DESCRIPTOR_ALIGNMENT, 0);
731        assert(tx_bd_base != NULL);
732        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
733
734        /* Create descriptor list and mark as empty */
735        for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) {
736                buffer_desc->addr = 0;
737                buffer_desc->status.val = GMAC_TX_SET_USED;
738                if (bd_number == (sc->amount_tx_buf - 1)) {
739                        buffer_desc->status.bm.bWrap = 1;
740                } else {
741                        buffer_desc++;
742                }
743        }
744        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
745
746        /* Write Buffer Queue Base Address Register */
747        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 0);
748
749        /* Enable Transmission of data */
750        GMAC_TransmitEnable(pHw, 1);
751
752        /* Set variables in context */
753        sc->tx_bd_base = tx_bd_base;
754
755        while (true) {
756                /* Wait for events */
757                rtems_bsdnet_event_receive(ATSAMV7_ETH_START_TRANSMIT_EVENT | ATSAMV7_ETH_TX_EVENT_INTERRUPT,
758                    RTEMS_EVENT_ANY | RTEMS_WAIT,
759                    RTEMS_NO_TIMEOUT, &events);
760                //printf("TX Transmit Event received\n");
761
762                /*
763                 * Send packets till queue is empty
764                 */
765                while (true) {
766                        /*
767                         * Get the mbuf chain to transmit
768                         */
769                        if_atsam_tx_bd_cleanup(sc);
770                        IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
771                        if (!m) {
772                                ifp->if_flags &= ~IFF_OACTIVE;
773                                break;
774                        }
775                        success = if_atsam_send_packet(sc, m);
776                        if (!success){
777                                break;
778                        }
779                }
780        }
781}
782
783
784/*
785 * Send packet (caller provides header).
786 */
787static void if_atsam_enet_start(struct ifnet *ifp)
788{
789        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
790
791        ifp->if_flags |= IFF_OACTIVE;
792        rtems_bsdnet_event_send(sc->tx_daemon_tid,
793            ATSAMV7_ETH_START_TRANSMIT_EVENT);
794}
795
796
797/*
798 * Attach a watchdog for autonegotiation to the system
799 */
800static void if_atsam_interface_watchdog(struct ifnet *ifp)
801{
802        uint32_t anlpar;
803        uint8_t speed = GMAC_SPEED_100M;
804        uint8_t full_duplex = GMAC_DUPLEX_FULL;
805
806        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
807        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
808        uint8_t phy = sc->Gmac_inst.phy_address;
809        uint32_t retries = sc->Gmac_inst.retries;
810
811        if (if_atsam_read_phy(pHw, phy, MII_ANLPAR, &anlpar, retries)) {
812                anlpar = 0;
813        }
814        if (sc->anlpar != anlpar) {
815                /* Set up the GMAC link speed */
816                if (anlpar & ANLPAR_TX_FD) {
817                        /* Set MII for 100BaseTx and Full Duplex */
818                        speed = GMAC_SPEED_100M;
819                        full_duplex = GMAC_DUPLEX_FULL;
820                } else if (anlpar & ANLPAR_10_FD) {
821                        /* Set MII for 10BaseTx and Full Duplex */
822                        speed = GMAC_SPEED_10M;
823                        full_duplex = GMAC_DUPLEX_FULL;
824                } else if (anlpar & ANLPAR_TX) {
825                        /* Set MII for 100BaseTx and half Duplex */
826                        speed = GMAC_SPEED_100M;
827                        full_duplex = GMAC_DUPLEX_HALF;
828                } else if (anlpar & ANLPAR_10) {
829                        /* Set MII for 10BaseTx and half Duplex */
830                        speed = GMAC_SPEED_10M;
831                        full_duplex = GMAC_DUPLEX_HALF;
832                } else {
833                        /* Set MII for 100BaseTx and Full Duplex */
834                        speed = GMAC_SPEED_100M;
835                        full_duplex = GMAC_DUPLEX_FULL;
836                }
837                GMAC_SetLinkSpeed(pHw, speed, full_duplex);
838                sc->anlpar = anlpar;
839        }
840        ifp->if_timer = WATCHDOG_TIMEOUT;
841}
842
843
844/*
845 * Sets up the hardware and chooses the interface to be used
846 */
847static void if_atsam_init(void *arg)
848{
849        rtems_status_code status;
850
851        if_atsam_softc *sc = (if_atsam_softc *)arg;
852        struct ifnet *ifp = &sc->arpcom.ac_if;
853        uint32_t dmac_cfg = 0;
854        uint32_t gmii_val = 0;
855
856        if (sc->arpcom.ac_if.if_flags & IFF_RUNNING) {
857                return;
858        }
859        sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
860        sc->interrupt_number = GMAC_IRQn;
861
862        /* Disable Watchdog */
863        WDT_Disable(WDT);
864
865        /* Enable Peripheral Clock */
866        if ((PMC->PMC_PCSR1 & (1u << 7)) != (1u << 7)) {
867                PMC->PMC_PCER1 = 1 << 7;
868        }
869        /* Setup interrupts */
870        NVIC_ClearPendingIRQ(GMAC_IRQn);
871        NVIC_EnableIRQ(GMAC_IRQn);
872
873        GMACD_Init(&sc->Gmac_inst.gGmacd, GMAC, ID_GMAC, GMAC_CAF_ENABLE,
874            GMAC_NBC_DISABLE);
875
876        /* Enable MDIO interface */
877        GMAC_EnableMdio(sc->Gmac_inst.gGmacd.pHw);
878
879        /* PHY initialize */
880        if_atsam_init_phy(&sc->Gmac_inst, BOARD_MCK, &gmacResetPin, 1,
881            gmacPins, PIO_LISTSIZE(gmacPins));
882        /* Find valid Phy */
883        atsamv7_find_valid_phy(&sc->Gmac_inst);
884
885        /* Set Link Speed */
886        sc->anlpar = 0xFFFFFFFF;
887        if_atsam_interface_watchdog(ifp);
888
889        /* Enable autonegotation */
890        if_atsam_read_phy(sc->Gmac_inst.gGmacd.pHw, sc->Gmac_inst.phy_address,
891            MII_BMCR, &gmii_val, sc->Gmac_inst.retries);
892        if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw, sc->Gmac_inst.phy_address,
893            MII_BMCR, (gmii_val | BMCR_AUTOEN), sc->Gmac_inst.retries);
894
895        /* Configuration of DMAC */
896        dmac_cfg = (GMAC_DCFGR_DRBS(GMAC_RX_BUFFER_SIZE >> 6)) |
897            GMAC_DCFGR_RXBMS(3) | GMAC_DCFGR_TXPBMS | GMAC_DCFGR_FBLDO_INCR16;
898        GMAC_SetDMAConfig(sc->Gmac_inst.gGmacd.pHw, dmac_cfg, 0);
899
900        /* Shut down Transmit and Receive */
901        GMAC_ReceiveEnable(sc->Gmac_inst.gGmacd.pHw, 0);
902        GMAC_TransmitEnable(sc->Gmac_inst.gGmacd.pHw, 0);
903
904        GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1);
905
906        /*
907         * Allocate mbuf pointers
908         */
909        sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf,
910                M_MBUF, M_NOWAIT);
911        sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf,
912                M_MBUF, M_NOWAIT);
913
914        /* Install interrupt handler */
915        status = rtems_interrupt_handler_install(sc->interrupt_number,
916                "Ethernet",
917                RTEMS_INTERRUPT_UNIQUE,
918                if_atsam_interrupt_handler,
919                sc);
920        assert(status == RTEMS_SUCCESSFUL);
921
922        /*
923         * Start driver tasks
924         */
925        sc->rx_daemon_tid = rtems_bsdnet_newproc("SCrx", 4096,
926                if_atsam_rx_daemon, sc);
927        sc->tx_daemon_tid = rtems_bsdnet_newproc("SCtx", 4096,
928                if_atsam_tx_daemon, sc);
929
930        /* Start Watchdog Timer */
931        ifp->if_timer = 1;
932}
933
934
935/*
936 * Stop the device
937 */
938static void if_atsam_stop(struct if_atsam_softc *sc)
939{
940        struct ifnet *ifp = &sc->arpcom.ac_if;
941        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
942
943        ifp->if_flags &= ~IFF_RUNNING;
944
945        /* Disable MDIO interface and TX/RX */
946        pHw->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
947        pHw->GMAC_NCR &= ~GMAC_NCR_MPE;
948}
949
950
951/*
952 * Show interface statistics
953 */
954static void if_atsam_stats(struct if_atsam_softc *sc)
955{
956        int eno = EIO;
957        int media = 0;
958        Gmac *pHw;
959
960        media = (int)IFM_MAKEWORD(0, 0, 0, sc->Gmac_inst.phy_address);
961        eno = rtems_mii_ioctl(&sc->mdio, sc, SIOCGIFMEDIA, &media);
962
963        rtems_bsdnet_semaphore_release();
964
965        if (eno == 0) {
966                rtems_ifmedia2str(media, NULL, 0);
967                printf("\n");
968        }
969        pHw = sc->Gmac_inst.gGmacd.pHw;
970
971        printf("\n** Context Statistics **\n");
972        printf("Rx interrupts: %u\n", sc->rx_interrupts);
973        printf("Tx interrupts: %u\n", sc->tx_interrupts);
974        printf("Error Tur Tx interrupts: %u\n\n", sc->tx_tur_errors);
975        printf("Error Rlex Tx interrupts: %u\n\n", sc->tx_rlex_errors);
976        printf("Error Tfc Tx interrupts: %u\n\n", sc->tx_tfc_errors);
977        printf("Error Hresp Tx interrupts: %u\n\n", sc->tx_hresp_errors);
978        printf("Tx complete interrupts: %u\n\n", sc->tx_complete_int);
979        printf("\n** Statistics **\n");
980        printf("Octets Transmitted Low: %lu\n", pHw->GMAC_OTLO);
981        printf("Octets Transmitted High: %lu\n", pHw->GMAC_OTHI);
982        printf("Frames Transmitted: %lu\n", pHw->GMAC_FT);
983        printf("Broadcast Frames Transmitted: %lu\n", pHw->GMAC_BCFT);
984        printf("Multicast Frames Transmitted: %lu\n", pHw->GMAC_MFT);
985        printf("Pause Frames Transmitted: %lu\n", pHw->GMAC_PFT);
986        printf("64 Byte Frames Transmitted: %lu\n", pHw->GMAC_BFT64);
987        printf("65 to 127 Byte Frames Transmitted: %lu\n", pHw->GMAC_TBFT127);
988        printf("128 to 255 Byte Frames Transmitted: %lu\n", pHw->GMAC_TBFR255);
989        printf("256 to 511 Byte Frames Transmitted: %lu\n", pHw->GMAC_TBFT511);
990        printf("512 to 1023 Byte Frames Transmitted: %lu\n",
991            pHw->GMAC_TBFT1023);
992        printf("1024 to 1518 Byte Frames Transmitted: %lu\n",
993            pHw->GMAC_TBFT1518);
994        printf("Greater Than 1518 Byte Frames Transmitted: %lu\n",
995            pHw->GMAC_GTBFT1518);
996        printf("Transmit Underruns: %lu\n", pHw->GMAC_TUR);
997        printf("Single Collision Frames: %lu\n", pHw->GMAC_SCF);
998        printf("Multiple Collision Frames: %lu\n", pHw->GMAC_MCF);
999        printf("Excessive Collisions: %lu\n", pHw->GMAC_EC);
1000        printf("Late Collisions: %lu\n", pHw->GMAC_LC);
1001        printf("Deferred Transmission Frames: %lu\n", pHw->GMAC_DTF);
1002        printf("Carrier Sense Errors: %lu\n", pHw->GMAC_CSE);
1003        printf("Octets Received Low: %lu\n", pHw->GMAC_ORLO);
1004        printf("Octets Received High: %lu\n", pHw->GMAC_ORHI);
1005        printf("Frames Received: %lu\n", pHw->GMAC_FR);
1006        printf("Broadcast Frames Received: %lu\n", pHw->GMAC_BCFR);
1007        printf("Multicast Frames Received: %lu\n", pHw->GMAC_MFR);
1008        printf("Pause Frames Received: %lu\n", pHw->GMAC_PFR);
1009        printf("64 Byte Frames Received: %lu\n", pHw->GMAC_BFR64);
1010        printf("65 to 127 Byte Frames Received: %lu\n", pHw->GMAC_TBFR127);
1011        printf("128 to 255 Byte Frames Received: %lu\n", pHw->GMAC_TBFR255);
1012        printf("256 to 511 Byte Frames Received: %lu\n", pHw->GMAC_TBFR511);
1013        printf("512 to 1023 Byte Frames Received: %lu\n", pHw->GMAC_TBFR1023);
1014        printf("1024 to 1518 Byte Frames Received: %lu\n", pHw->GMAC_TBFR1518);
1015        printf("1519 to Maximum Byte Frames Received: %lu\n",
1016            pHw->GMAC_TBFR1518);
1017        printf("Undersize Frames Received: %lu\n", pHw->GMAC_UFR);
1018        printf("Oversize Frames Received: %lu\n", pHw->GMAC_OFR);
1019        printf("Jabbers Received: %lu\n", pHw->GMAC_JR);
1020        printf("Frame Check Sequence Errors: %lu\n", pHw->GMAC_FCSE);
1021        printf("Length Field Frame Errors: %lu\n", pHw->GMAC_LFFE);
1022        printf("Receive Symbol Errors: %lu\n", pHw->GMAC_RSE);
1023        printf("Alignment Errors: %lu\n", pHw->GMAC_AE);
1024        printf("Receive Resource Errors: %lu\n", pHw->GMAC_RRE);
1025        printf("Receive Overrun: %lu\n", pHw->GMAC_ROE);
1026        printf("IP Header Checksum Errors: %lu\n", pHw->GMAC_IHCE);
1027        printf("TCP Checksum Errors: %lu\n", pHw->GMAC_TCE);
1028        printf("UDP Checksum Errors: %lu\n", pHw->GMAC_UCE);
1029
1030        rtems_bsdnet_semaphore_obtain();
1031}
1032
1033
1034/*
1035 * Calculates the index that is to be sent into the hash registers
1036 */
1037static void if_atsam_get_hash_index(uint64_t addr, uint32_t *val)
1038{
1039        uint64_t tmp_val;
1040        uint8_t i, j;
1041        uint64_t idx;
1042        int offset = 0;
1043
1044        addr &= MAC_ADDR_MASK;
1045
1046        for (i = 0; i < HASH_INDEX_AMOUNT; ++i) {
1047                tmp_val = 0;
1048                offset = 0;
1049                for (j = 0; j < HASH_ELEMENTS_PER_INDEX; j++) {
1050                        idx = (addr >> (offset + i)) & MAC_IDX_MASK;
1051                        tmp_val ^= idx;
1052                        offset += HASH_INDEX_AMOUNT;
1053                }
1054                if (tmp_val > 0) {
1055                        *val |= (1u << i);
1056                }
1057        }
1058}
1059
1060
1061/*
1062 * Dis/Enable promiscuous Mode
1063 */
1064static void if_atsam_promiscuous_mode(if_atsam_softc *sc, bool enable)
1065{
1066        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1067
1068        if (enable) {
1069                pHw->GMAC_NCFGR |= GMAC_PROM_ENABLE;
1070        } else {
1071                pHw->GMAC_NCFGR &= ~GMAC_PROM_ENABLE;
1072        }
1073}
1074
1075
1076/*
1077 * Multicast handler
1078 */
1079static int
1080if_atsam_multicast_control(bool add, struct ifreq *ifr, if_atsam_softc *sc)
1081{
1082        int eno = 0;
1083        struct arpcom *ac = &sc->arpcom;
1084        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1085
1086        /* Switch off Multicast Hashing */
1087        pHw->GMAC_NCFGR &= ~GMAC_MC_ENABLE;
1088
1089        if (add) {
1090                eno = ether_addmulti(ifr, ac);
1091        } else {
1092                eno = ether_delmulti(ifr, ac);
1093        }
1094
1095        if (eno == ENETRESET) {
1096                struct ether_multistep step;
1097                struct ether_multi *enm;
1098
1099                eno = 0;
1100
1101                pHw->GMAC_HRB = 0;
1102                pHw->GMAC_HRT = 0;
1103
1104                ETHER_FIRST_MULTI(step, ac, enm);
1105                while (enm != NULL) {
1106                        uint64_t addrlo = 0;
1107                        uint64_t addrhi = 0;
1108                        uint32_t val = 0;
1109
1110                        memcpy(&addrlo, enm->enm_addrlo, ETHER_ADDR_LEN);
1111                        memcpy(&addrhi, enm->enm_addrhi, ETHER_ADDR_LEN);
1112                        while (addrlo <= addrhi) {
1113                                if_atsam_get_hash_index(addrlo, &val);
1114                                if (val < 32) {
1115                                        pHw->GMAC_HRB |= (1u << val);
1116                                } else {
1117                                        pHw->GMAC_HRT |= (1u << (val - 32));
1118                                }
1119                                ++addrlo;
1120                        }
1121                        ETHER_NEXT_MULTI(step, enm);
1122                }
1123        }
1124        /* Switch on Multicast Hashing */
1125        pHw->GMAC_NCFGR |= GMAC_MC_ENABLE;
1126        return (eno);
1127}
1128
1129
1130/*
1131 * Driver ioctl handler
1132 */
1133static int
1134if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1135{
1136        struct if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
1137        struct ifreq *ifr = (struct ifreq *)data;
1138        int rv = 0;
1139        bool prom_enable;
1140
1141        switch (command) {
1142        case SIOCGIFMEDIA:
1143        case SIOCSIFMEDIA:
1144                rtems_mii_ioctl(&sc->mdio, sc, command, &ifr->ifr_media);
1145                break;
1146        case SIOCGIFADDR:
1147        case SIOCSIFADDR:
1148                ether_ioctl(ifp, command, data);
1149                break;
1150        case SIOCSIFFLAGS:
1151                if (ifp->if_flags & IFF_UP) {
1152                        if (ifp->if_flags & IFF_RUNNING) {
1153                                /* Don't do anything */
1154                        } else {
1155                                if_atsam_init(sc);
1156                        }
1157                        prom_enable = ((ifp->if_flags & IFF_PROMISC) != 0);
1158                        if_atsam_promiscuous_mode(sc, prom_enable);
1159                } else {
1160                        if (ifp->if_flags & IFF_RUNNING) {
1161                                if_atsam_stop(sc);
1162                        }
1163                }
1164                break;
1165        case SIOCADDMULTI:
1166        case SIOCDELMULTI:
1167                if_atsam_multicast_control(command == SIOCADDMULTI, ifr, sc);
1168        case SIO_RTEMS_SHOW_STATS:
1169                if_atsam_stats(sc);
1170                break;
1171        default:
1172                rv = EINVAL;
1173                break;
1174        }
1175        return (rv);
1176}
1177
1178
1179/*
1180 * Attach an SAMV71 driver to the system
1181 */
1182static int if_atsam_driver_attach(struct rtems_bsdnet_ifconfig *config)
1183{
1184        if_atsam_softc *sc = &if_atsam_softc_inst;
1185        struct ifnet *ifp = &sc->arpcom.ac_if;
1186        const if_atsam_config *conf = config->drv_ctrl;
1187        int unitNumber;
1188        char *unitName;
1189
1190        if (conf != NULL) {
1191                sc->Gmac_inst.retries = conf->mdio_retries;
1192                sc->Gmac_inst.phy_address = conf->phy_addr;
1193        } else {
1194                sc->Gmac_inst.retries = 10;
1195                sc->Gmac_inst.phy_address = 0xFF;
1196        }
1197
1198        /* The MAC address used */
1199        memcpy(sc->GMacAddress, config->hardware_address, ETHER_ADDR_LEN);
1200        memcpy(sc->arpcom.ac_enaddr, sc->GMacAddress, ETHER_ADDR_LEN);
1201
1202        /*
1203         * Parse driver name
1204         */
1205        unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName);
1206        assert(unitNumber == 0);
1207
1208        assert(ifp->if_softc == NULL);
1209
1210        /* MDIO */
1211        sc->mdio.mdio_r = if_atsam_mdio_read;
1212        sc->mdio.mdio_w = if_atsam_mdio_write;
1213        sc->mdio.has_gmii = 1;
1214
1215        sc->amount_rx_buf = config->rbuf_count;
1216        sc->amount_tx_buf = config->xbuf_count;
1217
1218        sc->tx_ring.tx_bd_used = 0;
1219        sc->tx_ring.tx_bd_free = 0;
1220        sc->tx_ring.length = sc->amount_tx_buf;
1221
1222        /*
1223         * Set up network interface values
1224         */
1225        ifp->if_softc = sc;
1226        ifp->if_unit = (short int)unitNumber;
1227        ifp->if_name = unitName;
1228        ifp->if_mtu = ETHERMTU;
1229        ifp->if_init = if_atsam_init;
1230        ifp->if_ioctl = if_atsam_ioctl;
1231        ifp->if_start = if_atsam_enet_start;
1232        ifp->if_output = ether_output;
1233        ifp->if_watchdog = if_atsam_interface_watchdog;
1234        ifp->if_flags = IFF_MULTICAST | IFF_BROADCAST | IFF_SIMPLEX;
1235        ifp->if_snd.ifq_maxlen = ifqmaxlen;
1236        ifp->if_timer = 0;
1237
1238        /*
1239         * Attach the interface
1240         */
1241        if_attach(ifp);
1242        ether_ifattach(ifp);
1243        return (1);
1244}
1245
1246
1247int if_atsam_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
1248{
1249        (void)attaching;
1250        return (if_atsam_driver_attach(config));
1251}
Note: See TracBrowser for help on using the repository browser.