source: rtems-libbsd/rtemsbsd/sys/dev/atsam/if_atsam.c @ 67c35b9

55-freebsd-126-freebsd-12
Last change on this file since 67c35b9 was c6f4aa6, checked in by Christian Mauderer <Christian.Mauderer@…>, on 09/22/17 at 07:41:20

if_atsam: Allow fixed MII settings.

  • Property mode set to 100644
File size: 41.4 KB
Line 
1/*
2 * Copyright (c) 2016 - 2017 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 <machine/rtems-bsd-kernel-space.h>
33
34#include <bsp.h>
35
36#ifdef LIBBSP_ARM_ATSAM_BSP_H
37
38#include <bsp/irq.h>
39
40#include <stdio.h>
41
42#include <sys/types.h>
43#include <sys/param.h>
44#include <sys/mbuf.h>
45#include <sys/socket.h>
46#include <sys/sockio.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#include <sys/bus.h>
50#include <sys/sysctl.h>
51
52#include <net/if.h>
53#include <net/if_var.h>
54#include <net/if_types.h>
55#include <net/if_media.h>
56
57#include <netinet/in.h>
58#include <netinet/if_ether.h>
59
60#include <dev/mii/mii.h>
61#include <dev/mii/miivar.h>
62
63#include <libchip/chip.h>
64#include <libchip/include/gmacd.h>
65#include <libchip/include/pio.h>
66
67#include <rtems/bsd/local/miibus_if.h>
68#include <rtems/bsd/if_atsam.h>
69
70/*
71 * Number of interfaces supported by the driver
72 */
73#define NIFACES                 1
74
75/** Enable/Disable CopyAllFrame */
76#define GMAC_CAF_DISABLE        0
77#define GMAC_CAF_ENABLE         1
78
79/** Enable/Disable NoBroadCast */
80#define GMAC_NBC_DISABLE        0
81#define GMAC_NBC_ENABLE         1
82
83/** The PIN list of PIO for GMAC */
84#define BOARD_GMAC_PINS                                                    \
85        { (PIO_PD0A_GTXCK | PIO_PD1A_GTXEN | PIO_PD2A_GTX0 | PIO_PD3A_GTX1 \
86          | PIO_PD4A_GRXDV | PIO_PD5A_GRX0 | PIO_PD6A_GRX1                 \
87          | PIO_PD7A_GRXER                                                 \
88          | PIO_PD8A_GMDC | PIO_PD9A_GMDIO), PIOD, ID_PIOD, PIO_PERIPH_A,  \
89          PIO_DEFAULT }
90/** The runtime pin configure list for GMAC */
91#define BOARD_GMAC_RUN_PINS                     BOARD_GMAC_PINS
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/* FIXME: Make these configurable */
127#define MDIO_RETRIES 10
128#define MDIO_PHY MII_PHY_ANY
129#define RXBUF_COUNT 8
130#define TXBUF_COUNT 64
131#define IGNORE_RX_ERR false
132
133/** The PINs for GMAC */
134static const Pin gmacPins[] = { BOARD_GMAC_RUN_PINS };
135
136typedef struct if_atsam_gmac {
137        /** The GMAC driver instance */
138        sGmacd gGmacd;
139        uint32_t retries;
140} if_atsam_gmac;
141
142typedef struct ring_buffer {
143        unsigned tx_bd_used;
144        unsigned tx_bd_free;
145        size_t length;
146} ring_buffer;
147
148/*
149 * Per-device data
150 */
151typedef struct if_atsam_softc {
152        /*
153         * Data
154         */
155        device_t dev;
156        struct ifnet *ifp;
157        struct mtx mtx;
158        if_atsam_gmac Gmac_inst;
159        uint8_t GMacAddress[6];
160        rtems_id rx_daemon_tid;
161        rtems_id tx_daemon_tid;
162        rtems_vector_number interrupt_number;
163        struct mbuf **rx_mbuf;
164        struct mbuf **tx_mbuf;
165        volatile sGmacTxDescriptor *tx_bd_base;
166        size_t rx_bd_fill_idx;
167        size_t amount_rx_buf;
168        size_t amount_tx_buf;
169        ring_buffer tx_ring;
170        struct callout tick_ch;
171
172        /*
173         * Settings for a fixed speed.
174         */
175        bool fixed_speed;
176        uint32_t media;
177        uint32_t duplex;
178        struct ifmedia ifmedia;
179
180        /*
181         * MII bus (only used if no fixed speed)
182         */
183        device_t miibus;
184        uint8_t link_speed;
185        uint8_t link_duplex;
186
187        /*
188         * Statistics
189         */
190        struct if_atsam_stats {
191                /* Software */
192                uint32_t rx_overrun_errors;
193                uint32_t rx_interrupts;
194                uint32_t tx_complete_int;
195                uint32_t tx_tur_errors;
196                uint32_t tx_rlex_errors;
197                uint32_t tx_tfc_errors;
198                uint32_t tx_hresp_errors;
199                uint32_t tx_interrupts;
200
201                /* Hardware */
202                uint64_t octets_transm;
203                uint32_t frames_transm;
204                uint32_t broadcast_frames_transm;
205                uint32_t multicast_frames_transm;
206                uint32_t pause_frames_transm;
207                uint32_t frames_64_byte_transm;
208                uint32_t frames_65_to_127_byte_transm;
209                uint32_t frames_128_to_255_byte_transm;
210                uint32_t frames_256_to_511_byte_transm;
211                uint32_t frames_512_to_1023_byte_transm;
212                uint32_t frames_1024_to_1518_byte_transm;
213                uint32_t frames_greater_1518_byte_transm;
214                uint32_t transmit_underruns;
215                uint32_t single_collision_frames;
216                uint32_t multiple_collision_frames;
217                uint32_t excessive_collisions;
218                uint32_t late_collisions;
219                uint32_t deferred_transmission_frames;
220                uint32_t carrier_sense_errors;
221                uint64_t octets_rec;
222                uint32_t frames_rec;
223                uint32_t broadcast_frames_rec;
224                uint32_t multicast_frames_rec;
225                uint32_t pause_frames_rec;
226                uint32_t frames_64_byte_rec;
227                uint32_t frames_65_to_127_byte_rec;
228                uint32_t frames_128_to_255_byte_rec;
229                uint32_t frames_256_to_511_byte_rec;
230                uint32_t frames_512_to_1023_byte_rec;
231                uint32_t frames_1024_to_1518_byte_rec;
232                uint32_t frames_1519_to_maximum_byte_rec;
233                uint32_t undersize_frames_rec;
234                uint32_t oversize_frames_rec;
235                uint32_t jabbers_rec;
236                uint32_t frame_check_sequence_errors;
237                uint32_t length_field_frame_errors;
238                uint32_t receive_symbol_errors;
239                uint32_t alignment_errors;
240                uint32_t receive_resource_errors;
241                uint32_t receive_overrun;
242                uint32_t ip_header_checksum_errors;
243                uint32_t tcp_checksum_errors;
244                uint32_t udp_checksum_errors;
245        } stats;
246} if_atsam_softc;
247
248static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc);
249
250#define IF_ATSAM_LOCK(sc) mtx_lock(&(sc)->mtx)
251
252#define IF_ATSAM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
253
254static void if_atsam_event_send(rtems_id task, rtems_event_set event)
255{
256        rtems_event_send(task, event);
257}
258
259
260static void if_atsam_event_receive(if_atsam_softc *sc, rtems_event_set in)
261{
262        rtems_event_set out;
263
264        IF_ATSAM_UNLOCK(sc);
265        rtems_event_receive(
266            in,
267            RTEMS_EVENT_ANY | RTEMS_WAIT,
268            RTEMS_NO_TIMEOUT,
269            &out
270        );
271        IF_ATSAM_LOCK(sc);
272}
273
274
275static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp)
276{
277        struct mbuf *m;
278
279        MGETHDR(m, M_NOWAIT, MT_DATA);
280        if (m != NULL) {
281                MCLGET(m, M_NOWAIT);
282                if ((m->m_flags & M_EXT) != 0) {
283                        m->m_pkthdr.rcvif = ifp;
284                        m->m_data = mtod(m, char *);
285                        rtems_cache_invalidate_multiple_data_lines(mtod(m, void *),
286                            GMAC_RX_BUFFER_SIZE);
287                } else {
288                        m_free(m);
289                        m = NULL;
290                }
291        }
292        return (m);
293}
294
295static uint8_t if_atsam_wait_phy(Gmac *pHw, uint32_t retry)
296{
297        volatile uint32_t retry_count = 0;
298
299        while (!GMAC_IsIdle(pHw)) {
300                if (retry == 0) {
301                        continue;
302                }
303                retry_count++;
304
305                if (retry_count >= retry) {
306                        return (1);
307                }
308                rtems_task_wake_after(1);
309        }
310
311        return (0);
312}
313
314
315static uint8_t
316if_atsam_write_phy(Gmac *pHw, uint8_t PhyAddress, uint8_t Address,
317    uint32_t Value, uint32_t retry)
318{
319        GMAC_PHYMaintain(pHw, PhyAddress, Address, 0, (uint16_t)Value);
320        if (if_atsam_wait_phy(pHw, retry) == 1) {
321                return (1);
322        }
323        return (0);
324}
325
326
327static uint8_t
328if_atsam_read_phy(Gmac *pHw,
329    uint8_t PhyAddress, uint8_t Address, uint32_t *pvalue, uint32_t retry)
330{
331        GMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0);
332        if (if_atsam_wait_phy(pHw, retry) == 1) {
333                return (1);
334        }
335        *pvalue = GMAC_PHYData(pHw);
336        return (0);
337}
338
339
340static int
341if_atsam_miibus_readreg(device_t dev, int phy, int reg)
342{
343        uint32_t val;
344        uint8_t err;
345        if_atsam_softc *sc = device_get_softc(dev);
346
347        IF_ATSAM_LOCK(sc);
348        err = if_atsam_read_phy(sc->Gmac_inst.gGmacd.pHw,
349            (uint8_t)phy, (uint8_t)reg, &val, sc->Gmac_inst.retries);
350        IF_ATSAM_UNLOCK(sc);
351
352        return (err == 0 ? val : 0);
353}
354
355
356static int
357if_atsam_miibus_writereg(device_t dev, int phy, int reg, int data)
358{
359        uint8_t err;
360        if_atsam_softc *sc = device_get_softc(dev);
361
362        IF_ATSAM_LOCK(sc);
363        err = if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw,
364            (uint8_t)phy, (uint8_t)reg, data, sc->Gmac_inst.retries);
365        IF_ATSAM_UNLOCK(sc);
366
367        return 0;
368}
369
370
371static uint8_t
372if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck,
373    const Pin *pResetPins, uint32_t nbResetPins, const Pin *pGmacPins,
374    uint32_t nbGmacPins)
375{
376        uint8_t rc = 1;
377        Gmac *pHw = gmac_inst->gGmacd.pHw;
378
379        /* Perform RESET */
380        if (pResetPins) {
381                /* Configure PINS */
382                PIO_Configure(pResetPins, nbResetPins);
383                PIO_Clear(pResetPins);
384                rtems_task_wake_after(1);
385                PIO_Set(pResetPins);
386        }
387        /* Configure GMAC runtime pins */
388        if (rc) {
389                PIO_Configure(pGmacPins, nbGmacPins);
390                rc = GMAC_SetMdcClock(pHw, mck);
391
392                if (!rc) {
393                        return (0);
394                }
395        }
396        return (rc);
397}
398
399
400/*
401 * Interrupt Handler for the network driver
402 */
403static void if_atsam_interrupt_handler(void *arg)
404{
405        if_atsam_softc *sc = (if_atsam_softc *)arg;
406        uint32_t irq_status_val;
407        rtems_event_set rx_event = 0;
408        rtems_event_set tx_event = 0;
409        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
410
411        /* Get interrupt status */
412        irq_status_val = GMAC_GetItStatus(pHw, 0);
413
414        /* Check receive interrupts */
415        if ((irq_status_val & GMAC_IER_ROVR) != 0) {
416                ++sc->stats.rx_overrun_errors;
417                rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
418        }
419        if ((irq_status_val & GMAC_IER_RCOMP) != 0) {
420                rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
421        }
422        /* Send events to receive task and switch off rx interrupts */
423        if (rx_event != 0) {
424                ++sc->stats.rx_interrupts;
425                /* Erase the interrupts for RX completion and errors */
426                GMAC_DisableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
427                (void)if_atsam_event_send(sc->rx_daemon_tid, rx_event);
428        }
429        if ((irq_status_val & GMAC_IER_TUR) != 0) {
430                ++sc->stats.tx_tur_errors;
431                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
432        }
433        if ((irq_status_val & GMAC_IER_RLEX) != 0) {
434                ++sc->stats.tx_rlex_errors;
435                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
436        }
437        if ((irq_status_val & GMAC_IER_TFC) != 0) {
438                ++sc->stats.tx_tfc_errors;
439                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
440        }
441        if ((irq_status_val & GMAC_IER_HRESP) != 0) {
442                ++sc->stats.tx_hresp_errors;
443                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
444        }
445        if ((irq_status_val & GMAC_IER_TCOMP) != 0) {
446                ++sc->stats.tx_complete_int;
447                tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
448        }
449        /* Send events to transmit task and switch off tx interrupts */
450        if (tx_event != 0) {
451                ++sc->stats.tx_interrupts;
452                /* Erase the interrupts for TX completion and errors */
453                GMAC_DisableIt(pHw, GMAC_INT_TX_BITS, 0);
454                (void)if_atsam_event_send(sc->tx_daemon_tid, tx_event);
455        }
456}
457/*
458 * Receive daemon
459 */
460static void if_atsam_rx_daemon(void *arg)
461{
462        if_atsam_softc *sc = (if_atsam_softc *)arg;
463        struct ifnet *ifp = sc->ifp;
464        rtems_event_set events = 0;
465        void *rx_bd_base;
466        struct mbuf *m;
467        struct mbuf *n;
468        volatile sGmacRxDescriptor *buffer_desc;
469        int frame_len;
470        uint32_t tmp_rx_bd_address;
471        size_t i;
472        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
473
474        IF_ATSAM_LOCK(sc);
475
476        if (IGNORE_RX_ERR) {
477                pHw->GMAC_NCFGR |= GMAC_NCFGR_IRXER;
478        } else {
479                pHw->GMAC_NCFGR &= ~GMAC_NCFGR_IRXER;
480        }
481
482        /* Allocate memory space for priority queue descriptor list */
483        rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor),
484                GMAC_DESCRIPTOR_ALIGNMENT, 0);
485        assert(rx_bd_base != NULL);
486
487        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
488        buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP;
489        buffer_desc->status.val = 0;
490
491        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1);
492        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2);
493
494        /* Allocate memory space for buffer descriptor list */
495        rx_bd_base = rtems_cache_coherent_allocate(
496                sc->amount_rx_buf * sizeof(sGmacRxDescriptor),
497                GMAC_DESCRIPTOR_ALIGNMENT, 0);
498        assert(rx_bd_base != NULL);
499        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
500
501        /* Create descriptor list and mark as empty */
502        for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf;
503            ++sc->rx_bd_fill_idx) {
504                m = if_atsam_new_mbuf(ifp);
505                assert(m != NULL);
506                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
507                buffer_desc->addr.val = ((uint32_t)m->m_data) &
508                    GMAC_RX_BUF_DESC_ADDR_MASK;
509                buffer_desc->status.val = 0;
510                if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) {
511                        buffer_desc->addr.bm.bWrap = 1;
512                } else {
513                        buffer_desc++;
514                }
515        }
516        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
517
518        /* Set 2 Byte Receive Buffer Offset */
519        pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET;
520
521        /* Write Buffer Queue Base Address Register */
522        GMAC_ReceiveEnable(pHw, 0);
523        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0);
524
525        /* Set address for address matching */
526        GMAC_SetAddress(pHw, 0, sc->GMacAddress);
527
528        /* Enable Receiving of data */
529        GMAC_ReceiveEnable(pHw, 1);
530
531        /* Setup the interrupts for RX completion and errors */
532        GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
533
534        sc->rx_bd_fill_idx = 0;
535
536        while (true) {
537                /* Wait for events */
538                if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT);
539
540                /*
541                 * Check for all packets with a set ownership bit
542                 */
543                while (buffer_desc->addr.bm.bOwnership == 1) {
544                        if (buffer_desc->status.bm.bEof == 1) {
545                                m = sc->rx_mbuf[sc->rx_bd_fill_idx];
546
547                                /* New mbuf for desc */
548                                n = if_atsam_new_mbuf(ifp);
549                                if (n != NULL) {
550                                        frame_len = (int)
551                                            (buffer_desc->status.bm.len);
552
553                                        /* Update mbuf */
554                                        m->m_data = mtod(m, char*)+ETHER_ALIGN;
555                                        m->m_len = frame_len;
556                                        m->m_pkthdr.len = frame_len;
557                                        IF_ATSAM_UNLOCK(sc);
558                                        sc->ifp->if_input(ifp, m);
559                                        IF_ATSAM_LOCK(sc);
560                                        m = n;
561                                } else {
562                                        (void)if_atsam_event_send(
563                                            sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT);
564                                }
565                                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
566                                tmp_rx_bd_address = (uint32_t)m->m_data &
567                                    GMAC_RX_BUF_DESC_ADDR_MASK;
568
569                                /* Switch pointer to next buffer descriptor */
570                                if (sc->rx_bd_fill_idx ==
571                                    (sc->amount_rx_buf - 1)) {
572                                        tmp_rx_bd_address |= GMAC_RX_SET_WRAP;
573                                        sc->rx_bd_fill_idx = 0;
574                                } else {
575                                        ++sc->rx_bd_fill_idx;
576                                }
577
578                                /*
579                                 * Give ownership to GMAC for further processing
580                                 */
581                                tmp_rx_bd_address &= ~GMAC_RX_SET_USED;
582                                _ARM_Data_synchronization_barrier();
583                                buffer_desc->addr.val = tmp_rx_bd_address;
584
585                                buffer_desc = (sGmacRxDescriptor *)rx_bd_base
586                                    + sc->rx_bd_fill_idx;
587                        }
588                }
589                /* Setup the interrupts for RX completion and errors */
590                GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
591        }
592}
593
594/*
595 * Update of current transmit buffer position.
596 */
597static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf)
598{
599        *pos = (*pos + 1) % amount_tx_buf;
600}
601
602/*
603 * Is RingBuffer empty
604 */
605static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer)
606{
607        return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free);
608}
609
610/*
611 * Is RingBuffer full
612 */
613static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer)
614{
615        size_t tx_bd_used_next = ring_buffer->tx_bd_used;
616
617        if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length);
618        return (tx_bd_used_next == ring_buffer->tx_bd_free);
619}
620
621/*
622 * Cleanup transmit file descriptors by freeing mbufs which are not needed any
623 * longer due to correct transmission.
624 */
625static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc)
626{
627        struct mbuf *m;
628        volatile sGmacTxDescriptor *cur;
629        bool eof_needed = false;
630
631        while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){
632                cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free;
633                if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) {
634                        eof_needed = true;
635                        cur->status.val |= GMAC_TX_SET_USED;
636                        m = sc->tx_mbuf[sc->tx_ring.tx_bd_free];
637                        m_free(m);
638                        sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0;
639                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free,
640                            sc->tx_ring.length);
641                        if (cur->status.bm.bLastBuffer) {
642                                eof_needed = false;
643                        }
644                } else {
645                        break;
646                }
647        }
648}
649
650/*
651 * Prepare Ethernet frame to start transmission.
652 */
653static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
654{
655        volatile sGmacTxDescriptor *cur;
656        volatile sGmacTxDescriptor *start_packet_tx_bd = 0;
657        int pos = 0;
658        uint32_t tmp_val = 0;
659        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
660        bool success;
661
662        if_atsam_tx_bd_cleanup(sc);
663        /* Wait for interrupt in case no buffer descriptors are available */
664        /* Wait for events */
665        while (true) {
666                if (if_atsam_ring_buffer_full(&sc->tx_ring)) {
667                        /* Setup the interrupts for TX completion and errors */
668                        GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0);
669                        success = false;
670                        break;
671                }
672
673                /*
674                 * Get current mbuf for data fill
675                 */
676                cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used];
677                /* Set the transfer data */
678                if (m->m_len) {
679                        uintptr_t cache_adjustment = mtod(m, uintptr_t) % 32;
680
681                        rtems_cache_flush_multiple_data_lines(
682                          mtod(m, const char *) - cache_adjustment,
683                          (size_t)(m->m_len + cache_adjustment));
684
685                        cur->addr = mtod(m, uint32_t);
686                        tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED;
687                        if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) {
688                                tmp_val |= GMAC_TX_SET_WRAP;
689                        }
690                        if (pos == 0) {
691                                start_packet_tx_bd = cur;
692                        }
693                        sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m;
694                        m = m->m_next;
695                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used,
696                            sc->tx_ring.length);
697                } else {
698                        /* Discard empty mbufs */
699                        m = m_free(m);
700                }
701
702                /*
703                 * Send out the buffer once the complete mbuf_chain has been
704                 * processed
705                 */
706                if (m == NULL) {
707                        tmp_val |= GMAC_TX_SET_EOF;
708                        tmp_val &= ~GMAC_TX_SET_USED;
709                        _ARM_Data_synchronization_barrier();
710                        cur->status.val = tmp_val;
711                        start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED;
712                        _ARM_Data_synchronization_barrier();
713                        GMAC_TransmissionStart(pHw);
714                        success = true;
715                        break;
716                } else {
717                        if (pos > 0) {
718                                tmp_val &= ~GMAC_TX_SET_USED;
719                        }
720                        pos++;
721                        cur->status.val = tmp_val;
722                }
723        }
724        return success;
725}
726
727
728/*
729 * Transmit daemon
730 */
731static void if_atsam_tx_daemon(void *arg)
732{
733        if_atsam_softc *sc = (if_atsam_softc *)arg;
734        rtems_event_set events = 0;
735        sGmacTxDescriptor *buffer_desc;
736        int bd_number;
737        void *tx_bd_base;
738        struct mbuf *m;
739        bool success;
740
741        IF_ATSAM_LOCK(sc);
742
743        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
744        struct ifnet *ifp = sc->ifp;
745
746        GMAC_TransmitEnable(pHw, 0);
747
748        /* Allocate memory space for priority queue descriptor list */
749        tx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacTxDescriptor),
750                GMAC_DESCRIPTOR_ALIGNMENT, 0);
751        assert(tx_bd_base != NULL);
752
753        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
754        buffer_desc->addr = 0;
755        buffer_desc->status.val = GMAC_TX_SET_USED | GMAC_TX_SET_WRAP;
756
757        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 1);
758        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 2);
759
760        /* Allocate memory space for buffer descriptor list */
761        tx_bd_base = rtems_cache_coherent_allocate(
762                sc->amount_tx_buf * sizeof(sGmacTxDescriptor),
763                GMAC_DESCRIPTOR_ALIGNMENT, 0);
764        assert(tx_bd_base != NULL);
765        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
766
767        /* Create descriptor list and mark as empty */
768        for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) {
769                buffer_desc->addr = 0;
770                buffer_desc->status.val = GMAC_TX_SET_USED;
771                if (bd_number == (sc->amount_tx_buf - 1)) {
772                        buffer_desc->status.bm.bWrap = 1;
773                } else {
774                        buffer_desc++;
775                }
776        }
777        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
778
779        /* Write Buffer Queue Base Address Register */
780        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 0);
781
782        /* Enable Transmission of data */
783        GMAC_TransmitEnable(pHw, 1);
784
785        /* Set variables in context */
786        sc->tx_bd_base = tx_bd_base;
787
788        while (true) {
789                /* Wait for events */
790                if_atsam_event_receive(sc,
791                    ATSAMV7_ETH_START_TRANSMIT_EVENT |
792                    ATSAMV7_ETH_TX_EVENT_INTERRUPT);
793                //printf("TX Transmit Event received\n");
794
795                /*
796                 * Send packets till queue is empty
797                 */
798                while (true) {
799                        /*
800                         * Get the mbuf chain to transmit
801                         */
802                        if_atsam_tx_bd_cleanup(sc);
803                        IF_DEQUEUE(&ifp->if_snd, m);
804                        if (!m) {
805                                ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
806                                break;
807                        }
808                        success = if_atsam_send_packet(sc, m);
809                        if (!success){
810                                break;
811                        }
812                }
813        }
814}
815
816
817/*
818 * Send packet (caller provides header).
819 */
820static void if_atsam_enet_start(struct ifnet *ifp)
821{
822        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
823
824        ifp->if_drv_flags |= IFF_DRV_OACTIVE;
825        if_atsam_event_send(sc->tx_daemon_tid,
826            ATSAMV7_ETH_START_TRANSMIT_EVENT);
827}
828
829
830static uint8_t if_atsam_get_gmac_linkspeed_from_media(uint32_t media_subtype)
831{
832        switch (media_subtype) {
833        case IFM_10_T:
834                return GMAC_SPEED_10M;
835                break;
836        case IFM_100_TX:
837                return GMAC_SPEED_100M;
838                break;
839        case IFM_1000_T:
840                return GMAC_SPEED_1000M;
841                break;
842        default:
843                return 0xFF;
844                break;
845        }
846}
847
848
849static uint8_t if_atsam_get_gmac_duplex_from_media(uint32_t media_options)
850{
851        if (media_options & IFM_FDX) {
852                return GMAC_DUPLEX_FULL;
853        } else {
854                return GMAC_DUPLEX_HALF;
855        }
856}
857
858
859static void if_atsam_miibus_statchg(device_t dev)
860{
861        uint8_t link_speed = GMAC_SPEED_100M;
862        uint8_t link_duplex = GMAC_DUPLEX_FULL;
863        if_atsam_softc *sc = device_get_softc(dev);
864        struct mii_data *mii = device_get_softc(sc->miibus);
865
866        if(sc->fixed_speed)
867                return;
868
869        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
870
871        link_duplex = if_atsam_get_gmac_duplex_from_media(
872            IFM_OPTIONS(mii->mii_media_active));
873
874        link_speed = if_atsam_get_gmac_linkspeed_from_media(
875            IFM_SUBTYPE(mii->mii_media_active));
876
877        if (sc->link_speed != link_speed || sc->link_duplex != link_duplex) {
878                GMAC_SetLinkSpeed(pHw, link_speed, link_duplex);
879                sc->link_speed = link_speed;
880                sc->link_duplex = link_duplex;
881        }
882}
883
884
885static int
886if_atsam_mii_ifmedia_upd(struct ifnet *ifp)
887{
888        if_atsam_softc *sc;
889        struct mii_data *mii;
890
891        sc = ifp->if_softc;
892        if (sc->fixed_speed || sc->miibus == NULL)
893                return (ENXIO);
894
895        mii = device_get_softc(sc->miibus);
896        return (mii_mediachg(mii));
897}
898
899
900static void
901if_atsam_mii_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
902{
903        if_atsam_softc *sc;
904        struct mii_data *mii;
905
906        sc = ifp->if_softc;
907        if (sc->fixed_speed || sc->miibus == NULL)
908                return;
909
910        mii = device_get_softc(sc->miibus);
911        mii_pollstat(mii);
912        ifmr->ifm_active = mii->mii_media_active;
913        ifmr->ifm_status = mii->mii_media_status;
914}
915
916
917static int
918if_atsam_media_change(struct ifnet *ifp __unused)
919{
920        /* Do nothing. */
921        return (0);
922}
923
924
925static void
926if_atsam_media_status(struct ifnet *ifp, struct ifmediareq *imr)
927{
928        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
929
930        imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
931        imr->ifm_active = IFM_ETHER | sc->media | sc->duplex;
932}
933
934
935static void
936if_atsam_tick(void *context)
937{
938        if_atsam_softc *sc = context;
939
940        if_atsam_poll_hw_stats(sc);
941
942        IF_ATSAM_UNLOCK(sc);
943
944        if (!sc->fixed_speed) {
945                mii_tick(device_get_softc(sc->miibus));
946        }
947        callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc);
948}
949
950
951/*
952 * Sets up the hardware and chooses the interface to be used
953 */
954static void if_atsam_init(void *arg)
955{
956        rtems_status_code status;
957
958        if_atsam_softc *sc = (if_atsam_softc *)arg;
959        struct ifnet *ifp = sc->ifp;
960        uint32_t dmac_cfg = 0;
961        uint32_t gmii_val = 0;
962
963        if (ifp->if_flags & IFF_DRV_RUNNING) {
964                return;
965        }
966        ifp->if_flags |= IFF_DRV_RUNNING;
967        sc->interrupt_number = GMAC_IRQn;
968
969        /* Disable Watchdog */
970        WDT_Disable(WDT);
971
972        /* Enable Peripheral Clock */
973        if ((PMC->PMC_PCSR1 & (1u << 7)) != (1u << 7)) {
974                PMC->PMC_PCER1 = 1 << 7;
975        }
976        /* Setup interrupts */
977        NVIC_ClearPendingIRQ(GMAC_IRQn);
978        NVIC_EnableIRQ(GMAC_IRQn);
979
980        /* Configuration of DMAC */
981        dmac_cfg = (GMAC_DCFGR_DRBS(GMAC_RX_BUFFER_SIZE >> 6)) |
982            GMAC_DCFGR_RXBMS(3) | GMAC_DCFGR_TXPBMS | GMAC_DCFGR_FBLDO_INCR16;
983        GMAC_SetDMAConfig(sc->Gmac_inst.gGmacd.pHw, dmac_cfg, 0);
984
985        /* Shut down Transmit and Receive */
986        GMAC_ReceiveEnable(sc->Gmac_inst.gGmacd.pHw, 0);
987        GMAC_TransmitEnable(sc->Gmac_inst.gGmacd.pHw, 0);
988
989        GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1);
990
991        /*
992         * Allocate mbuf pointers
993         */
994        sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf,
995                M_TEMP, M_NOWAIT);
996        sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf,
997                M_TEMP, M_NOWAIT);
998
999        /* Install interrupt handler */
1000        status = rtems_interrupt_handler_install(sc->interrupt_number,
1001                "Ethernet",
1002                RTEMS_INTERRUPT_UNIQUE,
1003                if_atsam_interrupt_handler,
1004                sc);
1005        assert(status == RTEMS_SUCCESSFUL);
1006
1007        /*
1008         * Start driver tasks
1009         */
1010        sc->rx_daemon_tid = rtems_bsdnet_newproc("SCrx", 4096,
1011                if_atsam_rx_daemon, sc);
1012        sc->tx_daemon_tid = rtems_bsdnet_newproc("SCtx", 4096,
1013                if_atsam_tx_daemon, sc);
1014
1015        callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc);
1016
1017        ifp->if_drv_flags |= IFF_DRV_RUNNING;
1018}
1019
1020
1021/*
1022 * Stop the device
1023 */
1024static void if_atsam_stop(struct if_atsam_softc *sc)
1025{
1026        struct ifnet *ifp = sc->ifp;
1027        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1028
1029        ifp->if_flags &= ~IFF_DRV_RUNNING;
1030
1031        /* Disable MDIO interface and TX/RX */
1032        pHw->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
1033        pHw->GMAC_NCR &= ~GMAC_NCR_MPE;
1034}
1035
1036
1037static void
1038if_atsam_poll_hw_stats(struct if_atsam_softc *sc)
1039{
1040        uint64_t octets;
1041        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1042
1043        octets = pHw->GMAC_OTLO;
1044        octets |= pHw->GMAC_OTHI << 32;
1045        sc->stats.octets_transm += octets;
1046        sc->stats.frames_transm += pHw->GMAC_FT;
1047        sc->stats.broadcast_frames_transm += pHw->GMAC_BCFT;
1048        sc->stats.multicast_frames_transm += pHw->GMAC_MFT;
1049        sc->stats.pause_frames_transm += pHw->GMAC_PFT;
1050        sc->stats.frames_64_byte_transm += pHw->GMAC_BFT64;
1051        sc->stats.frames_65_to_127_byte_transm += pHw->GMAC_TBFT127;
1052        sc->stats.frames_128_to_255_byte_transm += pHw->GMAC_TBFT255;
1053        sc->stats.frames_256_to_511_byte_transm += pHw->GMAC_TBFT511;
1054        sc->stats.frames_512_to_1023_byte_transm += pHw->GMAC_TBFT1023;
1055        sc->stats.frames_1024_to_1518_byte_transm += pHw->GMAC_TBFT1518;
1056        sc->stats.frames_greater_1518_byte_transm += pHw->GMAC_GTBFT1518;
1057        sc->stats.transmit_underruns += pHw->GMAC_TUR;
1058        sc->stats.single_collision_frames += pHw->GMAC_SCF;
1059        sc->stats.multiple_collision_frames += pHw->GMAC_MCF;
1060        sc->stats.excessive_collisions += pHw->GMAC_EC;
1061        sc->stats.late_collisions += pHw->GMAC_LC;
1062        sc->stats.deferred_transmission_frames += pHw->GMAC_DTF;
1063        sc->stats.carrier_sense_errors += pHw->GMAC_CSE;
1064
1065        octets = pHw->GMAC_ORLO;
1066        octets |= pHw->GMAC_ORHI << 32;
1067        sc->stats.octets_rec += octets;
1068        sc->stats.frames_rec += pHw->GMAC_FR;
1069        sc->stats.broadcast_frames_rec += pHw->GMAC_BCFR;
1070        sc->stats.multicast_frames_rec += pHw->GMAC_MFR;
1071        sc->stats.pause_frames_rec += pHw->GMAC_PFR;
1072        sc->stats.frames_64_byte_rec += pHw->GMAC_BFR64;
1073        sc->stats.frames_65_to_127_byte_rec += pHw->GMAC_TBFR127;
1074        sc->stats.frames_128_to_255_byte_rec += pHw->GMAC_TBFR255;
1075        sc->stats.frames_256_to_511_byte_rec += pHw->GMAC_TBFR511;
1076        sc->stats.frames_512_to_1023_byte_rec += pHw->GMAC_TBFR1023;
1077        sc->stats.frames_1024_to_1518_byte_rec += pHw->GMAC_TBFR1518;
1078        sc->stats.frames_1519_to_maximum_byte_rec += pHw->GMAC_TMXBFR;
1079        sc->stats.undersize_frames_rec += pHw->GMAC_UFR;
1080        sc->stats.oversize_frames_rec += pHw->GMAC_OFR;
1081        sc->stats.jabbers_rec += pHw->GMAC_JR;
1082        sc->stats.frame_check_sequence_errors += pHw->GMAC_FCSE;
1083        sc->stats.length_field_frame_errors += pHw->GMAC_LFFE;
1084        sc->stats.receive_symbol_errors += pHw->GMAC_RSE;
1085        sc->stats.alignment_errors += pHw->GMAC_AE;
1086        sc->stats.receive_resource_errors += pHw->GMAC_RRE;
1087        sc->stats.receive_overrun += pHw->GMAC_ROE;
1088
1089        sc->stats.ip_header_checksum_errors += pHw->GMAC_IHCE;
1090        sc->stats.tcp_checksum_errors += pHw->GMAC_TCE;
1091        sc->stats.udp_checksum_errors += pHw->GMAC_UCE;
1092}
1093
1094
1095static void
1096if_atsam_add_sysctls(device_t dev)
1097{
1098        struct if_atsam_softc *sc = device_get_softc(dev);
1099        struct sysctl_ctx_list *ctx;
1100        struct sysctl_oid_list *statsnode;
1101        struct sysctl_oid_list *hwstatsnode;
1102        struct sysctl_oid_list *child;
1103        struct sysctl_oid *tree;
1104
1105        ctx = device_get_sysctl_ctx(dev);
1106        child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
1107
1108        tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
1109                               NULL, "if_atsam statistics");
1110        statsnode = SYSCTL_CHILDREN(tree);
1111
1112        tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "sw", CTLFLAG_RD,
1113                               NULL, "if_atsam software statistics");
1114        child = SYSCTL_CHILDREN(tree);
1115
1116        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overrun_errors",
1117            CTLFLAG_RD, &sc->stats.rx_overrun_errors, 0,
1118            "RX overrun errors");
1119        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_interrupts",
1120            CTLFLAG_RD, &sc->stats.rx_interrupts, 0,
1121            "Rx interrupts");
1122        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_complete_int",
1123            CTLFLAG_RD, &sc->stats.tx_complete_int, 0,
1124            "Tx complete interrupts");
1125        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tur_errors",
1126            CTLFLAG_RD, &sc->stats.tx_tur_errors, 0,
1127            "Error Tur Tx interrupts");
1128        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_rlex_errors",
1129            CTLFLAG_RD, &sc->stats.tx_rlex_errors, 0,
1130            "Error Rlex Tx interrupts");
1131        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tfc_errors",
1132            CTLFLAG_RD, &sc->stats.tx_tfc_errors, 0,
1133            "Error Tfc Tx interrupts");
1134        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_hresp_errors",
1135            CTLFLAG_RD, &sc->stats.tx_hresp_errors, 0,
1136            "Error Hresp Tx interrupts");
1137        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_interrupts",
1138            CTLFLAG_RD, &sc->stats.tx_interrupts, 0,
1139            "Tx interrupts");
1140
1141        tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "hw", CTLFLAG_RD,
1142                               NULL, "if_atsam hardware statistics");
1143        hwstatsnode = SYSCTL_CHILDREN(tree);
1144
1145        tree = SYSCTL_ADD_NODE(ctx, hwstatsnode, OID_AUTO, "tx", CTLFLAG_RD,
1146                               NULL, "if_atsam hardware transmit statistics");
1147        child = SYSCTL_CHILDREN(tree);
1148
1149        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_transm",
1150            CTLFLAG_RD, &sc->stats.octets_transm,
1151            "Octets Transmitted");
1152        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_transm",
1153            CTLFLAG_RD, &sc->stats.frames_transm, 0,
1154            "Frames Transmitted");
1155        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_transm",
1156            CTLFLAG_RD, &sc->stats.broadcast_frames_transm, 0,
1157            "Broadcast Frames Transmitted");
1158        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_transm",
1159            CTLFLAG_RD, &sc->stats.multicast_frames_transm, 0,
1160            "Multicast Frames Transmitted");
1161        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_transm",
1162            CTLFLAG_RD, &sc->stats.pause_frames_transm, 0,
1163            "Pause Frames Transmitted");
1164        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_transm",
1165            CTLFLAG_RD, &sc->stats.frames_64_byte_transm, 0,
1166            "64 Byte Frames Transmitted");
1167        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_transm",
1168            CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_transm, 0,
1169            "65 to 127 Byte Frames Transmitted");
1170        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_transm",
1171            CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_transm, 0,
1172            "128 to 255 Byte Frames Transmitted");
1173        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_transm",
1174            CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_transm, 0,
1175            "256 to 511 Byte Frames Transmitted");
1176        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_transm",
1177            CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_transm, 0,
1178            "512 to 1023 Byte Frames Transmitted");
1179        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_transm",
1180            CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_transm, 0,
1181            "1024 to 1518 Byte Frames Transmitted");
1182        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_greater_1518_byte_transm",
1183            CTLFLAG_RD, &sc->stats.frames_greater_1518_byte_transm, 0,
1184            "Greater Than 1518 Byte Frames Transmitted");
1185        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "transmit_underruns",
1186            CTLFLAG_RD, &sc->stats.transmit_underruns, 0,
1187            "Transmit Underruns");
1188        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "single_collision_frames",
1189            CTLFLAG_RD, &sc->stats.single_collision_frames, 0,
1190            "Single Collision Frames");
1191        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multiple_collision_frames",
1192            CTLFLAG_RD, &sc->stats.multiple_collision_frames, 0,
1193            "Multiple Collision Frames");
1194        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "excessive_collisions",
1195            CTLFLAG_RD, &sc->stats.excessive_collisions, 0,
1196            "Excessive Collisions");
1197        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "late_collisions",
1198            CTLFLAG_RD, &sc->stats.late_collisions, 0,
1199            "Late Collisions");
1200        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "deferred_transmission_frames",
1201            CTLFLAG_RD, &sc->stats.deferred_transmission_frames, 0,
1202            "Deferred Transmission Frames");
1203        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "carrier_sense_errors",
1204            CTLFLAG_RD, &sc->stats.carrier_sense_errors, 0,
1205            "Carrier Sense Errors");
1206
1207        tree = SYSCTL_ADD_NODE(ctx, hwstatsnode, OID_AUTO, "rx", CTLFLAG_RD,
1208                               NULL, "if_atsam hardware receive statistics");
1209        child = SYSCTL_CHILDREN(tree);
1210
1211        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_rec",
1212            CTLFLAG_RD, &sc->stats.octets_rec,
1213            "Octets Received");
1214        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_rec",
1215            CTLFLAG_RD, &sc->stats.frames_rec, 0,
1216            "Frames Received");
1217        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_rec",
1218            CTLFLAG_RD, &sc->stats.broadcast_frames_rec, 0,
1219            "Broadcast Frames Received");
1220        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_rec",
1221            CTLFLAG_RD, &sc->stats.multicast_frames_rec, 0,
1222            "Multicast Frames Received");
1223        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_rec",
1224            CTLFLAG_RD, &sc->stats.pause_frames_rec, 0,
1225            "Pause Frames Received");
1226        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_rec",
1227            CTLFLAG_RD, &sc->stats.frames_64_byte_rec, 0,
1228            "64 Byte Frames Received");
1229        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_rec",
1230            CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_rec, 0,
1231            "65 to 127 Byte Frames Received");
1232        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_rec",
1233            CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_rec, 0,
1234            "128 to 255 Byte Frames Received");
1235        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_rec",
1236            CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_rec, 0,
1237            "256 to 511 Byte Frames Received");
1238        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_rec",
1239            CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_rec, 0,
1240            "512 to 1023 Byte Frames Received");
1241        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_rec",
1242            CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_rec, 0,
1243            "1024 to 1518 Byte Frames Received");
1244        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_byte_rec",
1245            CTLFLAG_RD, &sc->stats.frames_1519_to_maximum_byte_rec, 0,
1246            "1519 to Maximum Byte Frames Received");
1247        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames_rec",
1248            CTLFLAG_RD, &sc->stats.undersize_frames_rec, 0,
1249            "Undersize Frames Received");
1250        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames_rec",
1251            CTLFLAG_RD, &sc->stats.oversize_frames_rec, 0,
1252            "Oversize Frames Received");
1253        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers_rec",
1254            CTLFLAG_RD, &sc->stats.jabbers_rec, 0,
1255            "Jabbers Received");
1256        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frame_check_sequence_errors",
1257            CTLFLAG_RD, &sc->stats.frame_check_sequence_errors, 0,
1258            "Frame Check Sequence Errors");
1259        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "length_field_frame_errors",
1260            CTLFLAG_RD, &sc->stats.length_field_frame_errors, 0,
1261            "Length Field Frame Errors");
1262        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_symbol_errors",
1263            CTLFLAG_RD, &sc->stats.receive_symbol_errors, 0,
1264            "Receive Symbol Errors");
1265        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "alignment_errors",
1266            CTLFLAG_RD, &sc->stats.alignment_errors, 0,
1267            "Alignment Errors");
1268        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_resource_errors",
1269            CTLFLAG_RD, &sc->stats.receive_resource_errors, 0,
1270            "Receive Resource Errors");
1271        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_overrun",
1272            CTLFLAG_RD, &sc->stats.receive_overrun, 0,
1273            "Receive Overrun");
1274        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ip_header_checksum_errors",
1275            CTLFLAG_RD, &sc->stats.ip_header_checksum_errors, 0,
1276            "IP Header Checksum Errors");
1277        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tcp_checksum_errors",
1278            CTLFLAG_RD, &sc->stats.tcp_checksum_errors, 0,
1279            "TCP Checksum Errors");
1280        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "udp_checksum_errors",
1281            CTLFLAG_RD, &sc->stats.udp_checksum_errors, 0,
1282            "UDP Checksum Errors");
1283}
1284
1285
1286/*
1287 * Calculates the index that is to be sent into the hash registers
1288 */
1289static void if_atsam_get_hash_index(uint64_t addr, uint32_t *val)
1290{
1291        uint64_t tmp_val;
1292        uint8_t i, j;
1293        uint64_t idx;
1294        int offset = 0;
1295
1296        addr &= MAC_ADDR_MASK;
1297
1298        for (i = 0; i < HASH_INDEX_AMOUNT; ++i) {
1299                tmp_val = 0;
1300                offset = 0;
1301                for (j = 0; j < HASH_ELEMENTS_PER_INDEX; j++) {
1302                        idx = (addr >> (offset + i)) & MAC_IDX_MASK;
1303                        tmp_val ^= idx;
1304                        offset += HASH_INDEX_AMOUNT;
1305                }
1306                if (tmp_val > 0) {
1307                        *val |= (1u << i);
1308                }
1309        }
1310}
1311
1312
1313/*
1314 * Dis/Enable promiscuous Mode
1315 */
1316static void if_atsam_promiscuous_mode(if_atsam_softc *sc, bool enable)
1317{
1318        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1319
1320        if (enable) {
1321                pHw->GMAC_NCFGR |= GMAC_PROM_ENABLE;
1322        } else {
1323                pHw->GMAC_NCFGR &= ~GMAC_PROM_ENABLE;
1324        }
1325}
1326
1327
1328static int
1329if_atsam_mediaioctl(if_atsam_softc *sc, struct ifreq *ifr, u_long command)
1330{
1331        if (sc->fixed_speed) {
1332                return ifmedia_ioctl(sc->ifp, ifr, &sc->ifmedia, command);
1333        } else {
1334                struct mii_data *mii;
1335
1336                if (sc->miibus == NULL)
1337                        return (EINVAL);
1338
1339                mii = device_get_softc(sc->miibus);
1340                return (ifmedia_ioctl(sc->ifp, ifr, &mii->mii_media, command));
1341        }
1342}
1343
1344
1345/*
1346 * Driver ioctl handler
1347 */
1348static int
1349if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1350{
1351        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
1352        struct ifreq *ifr = (struct ifreq *)data;
1353        int rv = 0;
1354        bool prom_enable;
1355        struct mii_data *mii;
1356
1357        switch (command) {
1358        case SIOCGIFMEDIA:
1359        case SIOCSIFMEDIA:
1360                rv = if_atsam_mediaioctl(sc, ifr, command);
1361                break;
1362        case SIOCSIFFLAGS:
1363                if (ifp->if_flags & IFF_UP) {
1364                        if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1365                                if_atsam_init(sc);
1366                        }
1367                        prom_enable = ((ifp->if_flags & IFF_PROMISC) != 0);
1368                        if_atsam_promiscuous_mode(sc, prom_enable);
1369                } else {
1370                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1371                                if_atsam_stop(sc);
1372                        }
1373                }
1374                break;
1375        default:
1376                rv = ether_ioctl(ifp, command, data);
1377                break;
1378        }
1379        return (rv);
1380}
1381
1382/*
1383 * Attach an SAMV71 driver to the system
1384 */
1385static int if_atsam_driver_attach(device_t dev)
1386{
1387        if_atsam_softc *sc;
1388        struct ifnet *ifp;
1389        int unit;
1390        char *unitName;
1391        uint8_t eaddr[ETHER_ADDR_LEN];
1392
1393        sc = device_get_softc(dev);
1394        unit = device_get_unit(dev);
1395        assert(unit == 0);
1396
1397        sc->dev = dev;
1398        sc->ifp = ifp = if_alloc(IFT_ETHER);
1399
1400        mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK,
1401            MTX_DEF);
1402
1403        rtems_bsd_if_atsam_get_if_media_props(device_get_name(sc->dev), unit,
1404            &sc->fixed_speed, &sc->media, &sc->duplex);
1405        rtems_bsd_get_mac_address(device_get_name(sc->dev), unit, eaddr);
1406
1407        sc->Gmac_inst.retries = MDIO_RETRIES;
1408
1409        memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN);
1410
1411        sc->amount_rx_buf = RXBUF_COUNT;
1412        sc->amount_tx_buf = TXBUF_COUNT;
1413
1414        sc->tx_ring.tx_bd_used = 0;
1415        sc->tx_ring.tx_bd_free = 0;
1416        sc->tx_ring.length = sc->amount_tx_buf;
1417
1418        /* Set Initial Link Speed */
1419        sc->link_speed = GMAC_SPEED_100M;
1420        sc->link_duplex = GMAC_DUPLEX_FULL;
1421
1422        GMACD_Init(&sc->Gmac_inst.gGmacd, GMAC, ID_GMAC, GMAC_CAF_ENABLE,
1423            GMAC_NBC_DISABLE);
1424
1425        /* Enable MDIO interface */
1426        GMAC_EnableMdio(sc->Gmac_inst.gGmacd.pHw);
1427
1428        /* PHY initialize */
1429        if_atsam_init_phy(&sc->Gmac_inst, BOARD_MCK, NULL, 0,
1430            gmacPins, PIO_LISTSIZE(gmacPins));
1431
1432        /*
1433         * MII Bus
1434         */
1435        callout_init_mtx(&sc->tick_ch, &sc->mtx, CALLOUT_RETURNUNLOCKED);
1436        if (!sc->fixed_speed) {
1437                mii_attach(dev, &sc->miibus, ifp, if_atsam_mii_ifmedia_upd,
1438                    if_atsam_mii_ifmedia_sts, BMSR_DEFCAPMASK,
1439                    MDIO_PHY, MII_OFFSET_ANY, 0);
1440        } else {
1441                ifmedia_init(&sc->ifmedia, 0, if_atsam_media_change,
1442                    if_atsam_media_status);
1443                ifmedia_add(&sc->ifmedia, IFM_ETHER | sc->media
1444                    | sc->duplex, 0, NULL);
1445                ifmedia_set(&sc->ifmedia, IFM_ETHER | sc->media
1446                    | sc->duplex);
1447
1448                GMAC_SetLinkSpeed(sc->Gmac_inst.gGmacd.pHw,
1449                    if_atsam_get_gmac_linkspeed_from_media(sc->media),
1450                    if_atsam_get_gmac_duplex_from_media(sc->duplex));
1451
1452                if_link_state_change(sc->ifp, LINK_STATE_UP);
1453        }
1454
1455        /*
1456         * Set up network interface values
1457         */
1458        ifp->if_softc = sc;
1459        if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1460        ifp->if_init = if_atsam_init;
1461        ifp->if_ioctl = if_atsam_ioctl;
1462        ifp->if_start = if_atsam_enet_start;
1463        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1464        IFQ_SET_MAXLEN(&ifp->if_snd, TXBUF_COUNT - 1);
1465        ifp->if_snd.ifq_drv_maxlen = TXBUF_COUNT - 1;
1466        IFQ_SET_READY(&ifp->if_snd);
1467
1468        /*
1469         * Attach the interface
1470         */
1471        ether_ifattach(ifp, eaddr);
1472
1473        if_atsam_add_sysctls(dev);
1474
1475        return (0);
1476}
1477
1478static int
1479if_atsam_probe(device_t dev)
1480{
1481        int unit = device_get_unit(dev);
1482        int error;
1483
1484        if (unit >= 0 && unit < NIFACES) {
1485                error = BUS_PROBE_DEFAULT;
1486        } else {
1487                error = ENXIO;
1488        }
1489
1490        return (error);
1491}
1492
1493static device_method_t if_atsam_methods[] = {
1494        DEVMETHOD(device_probe,         if_atsam_probe),
1495        DEVMETHOD(device_attach,        if_atsam_driver_attach),
1496        DEVMETHOD(miibus_readreg,       if_atsam_miibus_readreg),
1497        DEVMETHOD(miibus_writereg,      if_atsam_miibus_writereg),
1498        DEVMETHOD(miibus_statchg,       if_atsam_miibus_statchg),
1499        DEVMETHOD_END
1500};
1501
1502static driver_t if_atsam_nexus_driver = {
1503        "if_atsam",
1504        if_atsam_methods,
1505        sizeof(struct if_atsam_softc)
1506};
1507
1508static devclass_t if_atsam_devclass;
1509DRIVER_MODULE(if_atsam, nexus, if_atsam_nexus_driver, if_atsam_devclass, 0, 0);
1510MODULE_DEPEND(if_atsam, nexus, 1, 1, 1);
1511MODULE_DEPEND(if_atsam, ether, 1, 1, 1);
1512MODULE_DEPEND(if_atsam, miibus, 1, 1, 1);
1513DRIVER_MODULE(miibus, if_atsam, miibus_driver, miibus_devclass, NULL, NULL);
1514
1515#endif /* LIBBSP_ARM_ATSAM_BSP_H */
Note: See TracBrowser for help on using the repository browser.