source: rtems/bsps/arm/atsam/net/if_atsam.c @ d7d0bba

Last change on this file since d7d0bba was d7d0bba, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 13, 2019 at 6:44:04 AM

bsp/atsam: Do not disable the WDT

The watchdog timer (WDT) can be configure only once. Do not touch it in
the BSP since the application may want to use it.

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