source: rtems-libbsd/rtemsbsd/sys/dev/atsam/if_atsam.c @ 0190cfd

5-freebsd-12
Last change on this file since 0190cfd was 0190cfd, checked in by Christian Mauderer <Christian.Mauderer@…>, on Sep 22, 2017 at 7:41:19 AM

if_atsam: Move statistics to sysctl.

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