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

55-freebsd-126-freebsd-12
Last change on this file since b3d1e6a was b2a210c, checked in by Christian Mauderer <christian.mauderer@…>, on 03/15/18 at 08:09:31

if_atsam: Add checksum offload.

  • Property mode set to 100644
File size: 42.5 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
458static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc)
459{
460        int frame_len;
461
462        frame_len = (int) (buffer_desc->status.bm.len);
463
464        m->m_data = mtod(m, char*)+ETHER_ALIGN;
465        m->m_len = frame_len;
466        m->m_pkthdr.len = frame_len;
467
468        /* check checksum offload result */
469        m->m_pkthdr.csum_flags = 0;
470        switch (buffer_desc->status.bm.typeIDMatchOrCksumResult) {
471        case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED:
472                m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
473                m->m_pkthdr.csum_data = 0xffff;
474                break;
475        case GMAC_RXDESC_ST_CKSUM_RESULT_IP_AND_TCP_CHECKED:
476        case GMAC_RXDESC_ST_CKSUM_RESULT_IP_AND_UDP_CHECKED:
477                m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
478                    CSUM_L4_VALID | CSUM_L4_CALC;
479                m->m_pkthdr.csum_data = 0xffff;
480                break;
481        }
482}
483
484/*
485 * Receive daemon
486 */
487static void if_atsam_rx_daemon(void *arg)
488{
489        if_atsam_softc *sc = (if_atsam_softc *)arg;
490        struct ifnet *ifp = sc->ifp;
491        rtems_event_set events = 0;
492        void *rx_bd_base;
493        struct mbuf *m;
494        struct mbuf *n;
495        volatile sGmacRxDescriptor *buffer_desc;
496        uint32_t tmp_rx_bd_address;
497        size_t i;
498        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
499
500        IF_ATSAM_LOCK(sc);
501
502        if (IGNORE_RX_ERR) {
503                pHw->GMAC_NCFGR |= GMAC_NCFGR_IRXER;
504        } else {
505                pHw->GMAC_NCFGR &= ~GMAC_NCFGR_IRXER;
506        }
507
508        /* Allocate memory space for priority queue descriptor list */
509        rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor),
510                GMAC_DESCRIPTOR_ALIGNMENT, 0);
511        assert(rx_bd_base != NULL);
512
513        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
514        buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP;
515        buffer_desc->status.val = 0;
516
517        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1);
518        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2);
519
520        /* Allocate memory space for buffer descriptor list */
521        rx_bd_base = rtems_cache_coherent_allocate(
522                sc->amount_rx_buf * sizeof(sGmacRxDescriptor),
523                GMAC_DESCRIPTOR_ALIGNMENT, 0);
524        assert(rx_bd_base != NULL);
525        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
526
527        /* Create descriptor list and mark as empty */
528        for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf;
529            ++sc->rx_bd_fill_idx) {
530                m = if_atsam_new_mbuf(ifp);
531                assert(m != NULL);
532                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
533                buffer_desc->addr.val = ((uint32_t)m->m_data) &
534                    GMAC_RX_BUF_DESC_ADDR_MASK;
535                buffer_desc->status.val = 0;
536                if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) {
537                        buffer_desc->addr.bm.bWrap = 1;
538                } else {
539                        buffer_desc++;
540                }
541        }
542        buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
543
544        /* Set 2 Byte Receive Buffer Offset */
545        pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET;
546
547        /* Write Buffer Queue Base Address Register */
548        GMAC_ReceiveEnable(pHw, 0);
549        GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0);
550
551        /* Set address for address matching */
552        GMAC_SetAddress(pHw, 0, sc->GMacAddress);
553
554        /* Enable Receiving of data */
555        GMAC_ReceiveEnable(pHw, 1);
556
557        /* Setup the interrupts for RX completion and errors */
558        GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
559
560        sc->rx_bd_fill_idx = 0;
561
562        while (true) {
563                /* Wait for events */
564                if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT);
565
566                /*
567                 * Check for all packets with a set ownership bit
568                 */
569                while (buffer_desc->addr.bm.bOwnership == 1) {
570                        if (buffer_desc->status.bm.bEof == 1) {
571                                m = sc->rx_mbuf[sc->rx_bd_fill_idx];
572
573                                /* New mbuf for desc */
574                                n = if_atsam_new_mbuf(ifp);
575                                if (n != NULL) {
576                                        rx_update_mbuf(m, buffer_desc);
577
578                                        IF_ATSAM_UNLOCK(sc);
579                                        sc->ifp->if_input(ifp, m);
580                                        IF_ATSAM_LOCK(sc);
581                                        m = n;
582                                } else {
583                                        (void)if_atsam_event_send(
584                                            sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT);
585                                }
586                                sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
587                                tmp_rx_bd_address = (uint32_t)m->m_data &
588                                    GMAC_RX_BUF_DESC_ADDR_MASK;
589
590                                /* Switch pointer to next buffer descriptor */
591                                if (sc->rx_bd_fill_idx ==
592                                    (sc->amount_rx_buf - 1)) {
593                                        tmp_rx_bd_address |= GMAC_RX_SET_WRAP;
594                                        sc->rx_bd_fill_idx = 0;
595                                } else {
596                                        ++sc->rx_bd_fill_idx;
597                                }
598
599                                /*
600                                 * Give ownership to GMAC for further processing
601                                 */
602                                tmp_rx_bd_address &= ~GMAC_RX_SET_USED;
603                                _ARM_Data_synchronization_barrier();
604                                buffer_desc->addr.val = tmp_rx_bd_address;
605
606                                buffer_desc = (sGmacRxDescriptor *)rx_bd_base
607                                    + sc->rx_bd_fill_idx;
608                        }
609                }
610                /* Setup the interrupts for RX completion and errors */
611                GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
612        }
613}
614
615/*
616 * Update of current transmit buffer position.
617 */
618static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf)
619{
620        *pos = (*pos + 1) % amount_tx_buf;
621}
622
623/*
624 * Is RingBuffer empty
625 */
626static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer)
627{
628        return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free);
629}
630
631/*
632 * Is RingBuffer full
633 */
634static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer)
635{
636        size_t tx_bd_used_next = ring_buffer->tx_bd_used;
637
638        if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length);
639        return (tx_bd_used_next == ring_buffer->tx_bd_free);
640}
641
642/*
643 * Cleanup transmit file descriptors by freeing mbufs which are not needed any
644 * longer due to correct transmission.
645 */
646static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc)
647{
648        struct mbuf *m;
649        volatile sGmacTxDescriptor *cur;
650        bool eof_needed = false;
651
652        while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){
653                cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free;
654                if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) {
655                        eof_needed = true;
656                        cur->status.val |= GMAC_TX_SET_USED;
657                        m = sc->tx_mbuf[sc->tx_ring.tx_bd_free];
658                        m_free(m);
659                        sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0;
660                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free,
661                            sc->tx_ring.length);
662                        if (cur->status.bm.bLastBuffer) {
663                                eof_needed = false;
664                        }
665                } else {
666                        break;
667                }
668        }
669}
670
671/*
672 * Prepare Ethernet frame to start transmission.
673 */
674static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
675{
676        volatile sGmacTxDescriptor *cur;
677        volatile sGmacTxDescriptor *start_packet_tx_bd = 0;
678        int pos = 0;
679        uint32_t tmp_val = 0;
680        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
681        bool success;
682        int csum_flags = m->m_pkthdr.csum_flags;
683
684        if_atsam_tx_bd_cleanup(sc);
685        /* Wait for interrupt in case no buffer descriptors are available */
686        /* Wait for events */
687        while (true) {
688                if (if_atsam_ring_buffer_full(&sc->tx_ring)) {
689                        /* Setup the interrupts for TX completion and errors */
690                        GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0);
691                        success = false;
692                        break;
693                }
694
695                /*
696                 * Get current mbuf for data fill
697                 */
698                cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used];
699                /* Set the transfer data */
700                if (m->m_len) {
701                        uintptr_t cache_adjustment = mtod(m, uintptr_t) % 32;
702
703                        rtems_cache_flush_multiple_data_lines(
704                          mtod(m, const char *) - cache_adjustment,
705                          (size_t)(m->m_len + cache_adjustment));
706
707                        cur->addr = mtod(m, uint32_t);
708                        tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED;
709                        if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) {
710                                tmp_val |= GMAC_TX_SET_WRAP;
711                        }
712                        if (pos == 0) {
713                                start_packet_tx_bd = cur;
714                        }
715                        sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m;
716                        m = m->m_next;
717                        if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used,
718                            sc->tx_ring.length);
719                } else {
720                        /* Discard empty mbufs */
721                        m = m_free(m);
722                }
723
724                /*
725                 * Send out the buffer once the complete mbuf_chain has been
726                 * processed
727                 */
728                if (m == NULL) {
729                        tmp_val |= GMAC_TX_SET_EOF;
730                        tmp_val &= ~GMAC_TX_SET_USED;
731                        if ((csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP |
732                            CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0) {
733                                start_packet_tx_bd->status.bm.bNoCRC = 0;
734                        } else {
735                                start_packet_tx_bd->status.bm.bNoCRC = 1;
736                        }
737                        _ARM_Data_synchronization_barrier();
738                        cur->status.val = tmp_val;
739                        start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED;
740                        _ARM_Data_synchronization_barrier();
741                        GMAC_TransmissionStart(pHw);
742                        success = true;
743                        break;
744                } else {
745                        if (pos > 0) {
746                                tmp_val &= ~GMAC_TX_SET_USED;
747                        }
748                        pos++;
749                        cur->status.val = tmp_val;
750                }
751        }
752        return success;
753}
754
755
756/*
757 * Transmit daemon
758 */
759static void if_atsam_tx_daemon(void *arg)
760{
761        if_atsam_softc *sc = (if_atsam_softc *)arg;
762        rtems_event_set events = 0;
763        sGmacTxDescriptor *buffer_desc;
764        int bd_number;
765        void *tx_bd_base;
766        struct mbuf *m;
767        bool success;
768
769        IF_ATSAM_LOCK(sc);
770
771        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
772        struct ifnet *ifp = sc->ifp;
773
774        GMAC_TransmitEnable(pHw, 0);
775
776        /* Allocate memory space for priority queue descriptor list */
777        tx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacTxDescriptor),
778                GMAC_DESCRIPTOR_ALIGNMENT, 0);
779        assert(tx_bd_base != NULL);
780
781        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
782        buffer_desc->addr = 0;
783        buffer_desc->status.val = GMAC_TX_SET_USED | GMAC_TX_SET_WRAP;
784
785        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 1);
786        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 2);
787
788        /* Allocate memory space for buffer descriptor list */
789        tx_bd_base = rtems_cache_coherent_allocate(
790                sc->amount_tx_buf * sizeof(sGmacTxDescriptor),
791                GMAC_DESCRIPTOR_ALIGNMENT, 0);
792        assert(tx_bd_base != NULL);
793        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
794
795        /* Create descriptor list and mark as empty */
796        for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) {
797                buffer_desc->addr = 0;
798                buffer_desc->status.val = GMAC_TX_SET_USED;
799                if (bd_number == (sc->amount_tx_buf - 1)) {
800                        buffer_desc->status.bm.bWrap = 1;
801                } else {
802                        buffer_desc++;
803                }
804        }
805        buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
806
807        /* Write Buffer Queue Base Address Register */
808        GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 0);
809
810        /* Enable Transmission of data */
811        GMAC_TransmitEnable(pHw, 1);
812
813        /* Set variables in context */
814        sc->tx_bd_base = tx_bd_base;
815
816        while (true) {
817                /* Wait for events */
818                if_atsam_event_receive(sc,
819                    ATSAMV7_ETH_START_TRANSMIT_EVENT |
820                    ATSAMV7_ETH_TX_EVENT_INTERRUPT);
821                //printf("TX Transmit Event received\n");
822
823                /*
824                 * Send packets till queue is empty
825                 */
826                while (true) {
827                        /*
828                         * Get the mbuf chain to transmit
829                         */
830                        if_atsam_tx_bd_cleanup(sc);
831                        IF_DEQUEUE(&ifp->if_snd, m);
832                        if (!m) {
833                                ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
834                                break;
835                        }
836                        success = if_atsam_send_packet(sc, m);
837                        if (!success){
838                                break;
839                        }
840                }
841        }
842}
843
844
845/*
846 * Send packet (caller provides header).
847 */
848static void if_atsam_enet_start(struct ifnet *ifp)
849{
850        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
851
852        ifp->if_drv_flags |= IFF_DRV_OACTIVE;
853        if_atsam_event_send(sc->tx_daemon_tid,
854            ATSAMV7_ETH_START_TRANSMIT_EVENT);
855}
856
857
858static uint8_t if_atsam_get_gmac_linkspeed_from_media(uint32_t media_subtype)
859{
860        switch (media_subtype) {
861        case IFM_10_T:
862                return GMAC_SPEED_10M;
863                break;
864        case IFM_100_TX:
865                return GMAC_SPEED_100M;
866                break;
867        case IFM_1000_T:
868                return GMAC_SPEED_1000M;
869                break;
870        default:
871                return 0xFF;
872                break;
873        }
874}
875
876
877static uint8_t if_atsam_get_gmac_duplex_from_media(uint32_t media_options)
878{
879        if (media_options & IFM_FDX) {
880                return GMAC_DUPLEX_FULL;
881        } else {
882                return GMAC_DUPLEX_HALF;
883        }
884}
885
886
887static void if_atsam_miibus_statchg(device_t dev)
888{
889        uint8_t link_speed = GMAC_SPEED_100M;
890        uint8_t link_duplex = GMAC_DUPLEX_FULL;
891        if_atsam_softc *sc = device_get_softc(dev);
892        struct mii_data *mii = device_get_softc(sc->miibus);
893
894        if(sc->fixed_speed)
895                return;
896
897        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
898
899        link_duplex = if_atsam_get_gmac_duplex_from_media(
900            IFM_OPTIONS(mii->mii_media_active));
901
902        link_speed = if_atsam_get_gmac_linkspeed_from_media(
903            IFM_SUBTYPE(mii->mii_media_active));
904
905        if (sc->link_speed != link_speed || sc->link_duplex != link_duplex) {
906                GMAC_SetLinkSpeed(pHw, link_speed, link_duplex);
907                sc->link_speed = link_speed;
908                sc->link_duplex = link_duplex;
909        }
910}
911
912
913static int
914if_atsam_mii_ifmedia_upd(struct ifnet *ifp)
915{
916        if_atsam_softc *sc;
917        struct mii_data *mii;
918
919        sc = ifp->if_softc;
920        if (sc->fixed_speed || sc->miibus == NULL)
921                return (ENXIO);
922
923        mii = device_get_softc(sc->miibus);
924        return (mii_mediachg(mii));
925}
926
927
928static void
929if_atsam_mii_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
930{
931        if_atsam_softc *sc;
932        struct mii_data *mii;
933
934        sc = ifp->if_softc;
935        if (sc->fixed_speed || sc->miibus == NULL)
936                return;
937
938        mii = device_get_softc(sc->miibus);
939        mii_pollstat(mii);
940        ifmr->ifm_active = mii->mii_media_active;
941        ifmr->ifm_status = mii->mii_media_status;
942}
943
944
945static int
946if_atsam_media_change(struct ifnet *ifp __unused)
947{
948        /* Do nothing. */
949        return (0);
950}
951
952
953static void
954if_atsam_media_status(struct ifnet *ifp, struct ifmediareq *imr)
955{
956        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
957
958        imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
959        imr->ifm_active = IFM_ETHER | sc->media | sc->duplex;
960}
961
962
963static void
964if_atsam_tick(void *context)
965{
966        if_atsam_softc *sc = context;
967
968        if_atsam_poll_hw_stats(sc);
969
970        IF_ATSAM_UNLOCK(sc);
971
972        if (!sc->fixed_speed) {
973                mii_tick(device_get_softc(sc->miibus));
974        }
975        callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc);
976}
977
978
979/*
980 * Sets up the hardware and chooses the interface to be used
981 */
982static void if_atsam_init(void *arg)
983{
984        rtems_status_code status;
985
986        if_atsam_softc *sc = (if_atsam_softc *)arg;
987        struct ifnet *ifp = sc->ifp;
988        uint32_t dmac_cfg = 0;
989        uint32_t gmii_val = 0;
990
991        if (ifp->if_flags & IFF_DRV_RUNNING) {
992                return;
993        }
994        ifp->if_flags |= IFF_DRV_RUNNING;
995        sc->interrupt_number = GMAC_IRQn;
996
997        /* Disable Watchdog */
998        WDT_Disable(WDT);
999
1000        /* Enable Peripheral Clock */
1001        if ((PMC->PMC_PCSR1 & (1u << 7)) != (1u << 7)) {
1002                PMC->PMC_PCER1 = 1 << 7;
1003        }
1004        /* Setup interrupts */
1005        NVIC_ClearPendingIRQ(GMAC_IRQn);
1006        NVIC_EnableIRQ(GMAC_IRQn);
1007
1008        /* Configuration of DMAC */
1009        dmac_cfg = (GMAC_DCFGR_DRBS(GMAC_RX_BUFFER_SIZE >> 6)) |
1010            GMAC_DCFGR_RXBMS(3) | GMAC_DCFGR_TXPBMS | GMAC_DCFGR_FBLDO_INCR16 |
1011            GMAC_DCFGR_TXCOEN;
1012        GMAC_SetDMAConfig(sc->Gmac_inst.gGmacd.pHw, dmac_cfg, 0);
1013
1014        /* Enable hardware checksum offload for receive */
1015        sc->Gmac_inst.gGmacd.pHw->GMAC_NCFGR |= GMAC_NCFGR_RXCOEN;
1016
1017        /* Shut down Transmit and Receive */
1018        GMAC_ReceiveEnable(sc->Gmac_inst.gGmacd.pHw, 0);
1019        GMAC_TransmitEnable(sc->Gmac_inst.gGmacd.pHw, 0);
1020
1021        GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1);
1022
1023        /*
1024         * Allocate mbuf pointers
1025         */
1026        sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf,
1027                M_TEMP, M_NOWAIT);
1028        sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf,
1029                M_TEMP, M_NOWAIT);
1030
1031        /* Install interrupt handler */
1032        status = rtems_interrupt_handler_install(sc->interrupt_number,
1033                "Ethernet",
1034                RTEMS_INTERRUPT_UNIQUE,
1035                if_atsam_interrupt_handler,
1036                sc);
1037        assert(status == RTEMS_SUCCESSFUL);
1038
1039        /*
1040         * Start driver tasks
1041         */
1042        sc->rx_daemon_tid = rtems_bsdnet_newproc("SCrx", 4096,
1043                if_atsam_rx_daemon, sc);
1044        sc->tx_daemon_tid = rtems_bsdnet_newproc("SCtx", 4096,
1045                if_atsam_tx_daemon, sc);
1046
1047        callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc);
1048
1049        ifp->if_drv_flags |= IFF_DRV_RUNNING;
1050}
1051
1052
1053/*
1054 * Stop the device
1055 */
1056static void if_atsam_stop(struct if_atsam_softc *sc)
1057{
1058        struct ifnet *ifp = sc->ifp;
1059        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1060
1061        ifp->if_flags &= ~IFF_DRV_RUNNING;
1062
1063        /* Disable MDIO interface and TX/RX */
1064        pHw->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
1065        pHw->GMAC_NCR &= ~GMAC_NCR_MPE;
1066}
1067
1068
1069static void
1070if_atsam_poll_hw_stats(struct if_atsam_softc *sc)
1071{
1072        uint64_t octets;
1073        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1074
1075        octets = pHw->GMAC_OTLO;
1076        octets |= pHw->GMAC_OTHI << 32;
1077        sc->stats.octets_transm += octets;
1078        sc->stats.frames_transm += pHw->GMAC_FT;
1079        sc->stats.broadcast_frames_transm += pHw->GMAC_BCFT;
1080        sc->stats.multicast_frames_transm += pHw->GMAC_MFT;
1081        sc->stats.pause_frames_transm += pHw->GMAC_PFT;
1082        sc->stats.frames_64_byte_transm += pHw->GMAC_BFT64;
1083        sc->stats.frames_65_to_127_byte_transm += pHw->GMAC_TBFT127;
1084        sc->stats.frames_128_to_255_byte_transm += pHw->GMAC_TBFT255;
1085        sc->stats.frames_256_to_511_byte_transm += pHw->GMAC_TBFT511;
1086        sc->stats.frames_512_to_1023_byte_transm += pHw->GMAC_TBFT1023;
1087        sc->stats.frames_1024_to_1518_byte_transm += pHw->GMAC_TBFT1518;
1088        sc->stats.frames_greater_1518_byte_transm += pHw->GMAC_GTBFT1518;
1089        sc->stats.transmit_underruns += pHw->GMAC_TUR;
1090        sc->stats.single_collision_frames += pHw->GMAC_SCF;
1091        sc->stats.multiple_collision_frames += pHw->GMAC_MCF;
1092        sc->stats.excessive_collisions += pHw->GMAC_EC;
1093        sc->stats.late_collisions += pHw->GMAC_LC;
1094        sc->stats.deferred_transmission_frames += pHw->GMAC_DTF;
1095        sc->stats.carrier_sense_errors += pHw->GMAC_CSE;
1096
1097        octets = pHw->GMAC_ORLO;
1098        octets |= pHw->GMAC_ORHI << 32;
1099        sc->stats.octets_rec += octets;
1100        sc->stats.frames_rec += pHw->GMAC_FR;
1101        sc->stats.broadcast_frames_rec += pHw->GMAC_BCFR;
1102        sc->stats.multicast_frames_rec += pHw->GMAC_MFR;
1103        sc->stats.pause_frames_rec += pHw->GMAC_PFR;
1104        sc->stats.frames_64_byte_rec += pHw->GMAC_BFR64;
1105        sc->stats.frames_65_to_127_byte_rec += pHw->GMAC_TBFR127;
1106        sc->stats.frames_128_to_255_byte_rec += pHw->GMAC_TBFR255;
1107        sc->stats.frames_256_to_511_byte_rec += pHw->GMAC_TBFR511;
1108        sc->stats.frames_512_to_1023_byte_rec += pHw->GMAC_TBFR1023;
1109        sc->stats.frames_1024_to_1518_byte_rec += pHw->GMAC_TBFR1518;
1110        sc->stats.frames_1519_to_maximum_byte_rec += pHw->GMAC_TMXBFR;
1111        sc->stats.undersize_frames_rec += pHw->GMAC_UFR;
1112        sc->stats.oversize_frames_rec += pHw->GMAC_OFR;
1113        sc->stats.jabbers_rec += pHw->GMAC_JR;
1114        sc->stats.frame_check_sequence_errors += pHw->GMAC_FCSE;
1115        sc->stats.length_field_frame_errors += pHw->GMAC_LFFE;
1116        sc->stats.receive_symbol_errors += pHw->GMAC_RSE;
1117        sc->stats.alignment_errors += pHw->GMAC_AE;
1118        sc->stats.receive_resource_errors += pHw->GMAC_RRE;
1119        sc->stats.receive_overrun += pHw->GMAC_ROE;
1120
1121        sc->stats.ip_header_checksum_errors += pHw->GMAC_IHCE;
1122        sc->stats.tcp_checksum_errors += pHw->GMAC_TCE;
1123        sc->stats.udp_checksum_errors += pHw->GMAC_UCE;
1124}
1125
1126
1127static void
1128if_atsam_add_sysctls(device_t dev)
1129{
1130        struct if_atsam_softc *sc = device_get_softc(dev);
1131        struct sysctl_ctx_list *ctx;
1132        struct sysctl_oid_list *statsnode;
1133        struct sysctl_oid_list *hwstatsnode;
1134        struct sysctl_oid_list *child;
1135        struct sysctl_oid *tree;
1136
1137        ctx = device_get_sysctl_ctx(dev);
1138        child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
1139
1140        tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
1141                               NULL, "if_atsam statistics");
1142        statsnode = SYSCTL_CHILDREN(tree);
1143
1144        tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "sw", CTLFLAG_RD,
1145                               NULL, "if_atsam software statistics");
1146        child = SYSCTL_CHILDREN(tree);
1147
1148        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overrun_errors",
1149            CTLFLAG_RD, &sc->stats.rx_overrun_errors, 0,
1150            "RX overrun errors");
1151        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_interrupts",
1152            CTLFLAG_RD, &sc->stats.rx_interrupts, 0,
1153            "Rx interrupts");
1154        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_complete_int",
1155            CTLFLAG_RD, &sc->stats.tx_complete_int, 0,
1156            "Tx complete interrupts");
1157        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tur_errors",
1158            CTLFLAG_RD, &sc->stats.tx_tur_errors, 0,
1159            "Error Tur Tx interrupts");
1160        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_rlex_errors",
1161            CTLFLAG_RD, &sc->stats.tx_rlex_errors, 0,
1162            "Error Rlex Tx interrupts");
1163        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tfc_errors",
1164            CTLFLAG_RD, &sc->stats.tx_tfc_errors, 0,
1165            "Error Tfc Tx interrupts");
1166        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_hresp_errors",
1167            CTLFLAG_RD, &sc->stats.tx_hresp_errors, 0,
1168            "Error Hresp Tx interrupts");
1169        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_interrupts",
1170            CTLFLAG_RD, &sc->stats.tx_interrupts, 0,
1171            "Tx interrupts");
1172
1173        tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "hw", CTLFLAG_RD,
1174                               NULL, "if_atsam hardware statistics");
1175        hwstatsnode = SYSCTL_CHILDREN(tree);
1176
1177        tree = SYSCTL_ADD_NODE(ctx, hwstatsnode, OID_AUTO, "tx", CTLFLAG_RD,
1178                               NULL, "if_atsam hardware transmit statistics");
1179        child = SYSCTL_CHILDREN(tree);
1180
1181        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_transm",
1182            CTLFLAG_RD, &sc->stats.octets_transm,
1183            "Octets Transmitted");
1184        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_transm",
1185            CTLFLAG_RD, &sc->stats.frames_transm, 0,
1186            "Frames Transmitted");
1187        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_transm",
1188            CTLFLAG_RD, &sc->stats.broadcast_frames_transm, 0,
1189            "Broadcast Frames Transmitted");
1190        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_transm",
1191            CTLFLAG_RD, &sc->stats.multicast_frames_transm, 0,
1192            "Multicast Frames Transmitted");
1193        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_transm",
1194            CTLFLAG_RD, &sc->stats.pause_frames_transm, 0,
1195            "Pause Frames Transmitted");
1196        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_transm",
1197            CTLFLAG_RD, &sc->stats.frames_64_byte_transm, 0,
1198            "64 Byte Frames Transmitted");
1199        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_transm",
1200            CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_transm, 0,
1201            "65 to 127 Byte Frames Transmitted");
1202        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_transm",
1203            CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_transm, 0,
1204            "128 to 255 Byte Frames Transmitted");
1205        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_transm",
1206            CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_transm, 0,
1207            "256 to 511 Byte Frames Transmitted");
1208        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_transm",
1209            CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_transm, 0,
1210            "512 to 1023 Byte Frames Transmitted");
1211        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_transm",
1212            CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_transm, 0,
1213            "1024 to 1518 Byte Frames Transmitted");
1214        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_greater_1518_byte_transm",
1215            CTLFLAG_RD, &sc->stats.frames_greater_1518_byte_transm, 0,
1216            "Greater Than 1518 Byte Frames Transmitted");
1217        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "transmit_underruns",
1218            CTLFLAG_RD, &sc->stats.transmit_underruns, 0,
1219            "Transmit Underruns");
1220        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "single_collision_frames",
1221            CTLFLAG_RD, &sc->stats.single_collision_frames, 0,
1222            "Single Collision Frames");
1223        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multiple_collision_frames",
1224            CTLFLAG_RD, &sc->stats.multiple_collision_frames, 0,
1225            "Multiple Collision Frames");
1226        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "excessive_collisions",
1227            CTLFLAG_RD, &sc->stats.excessive_collisions, 0,
1228            "Excessive Collisions");
1229        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "late_collisions",
1230            CTLFLAG_RD, &sc->stats.late_collisions, 0,
1231            "Late Collisions");
1232        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "deferred_transmission_frames",
1233            CTLFLAG_RD, &sc->stats.deferred_transmission_frames, 0,
1234            "Deferred Transmission Frames");
1235        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "carrier_sense_errors",
1236            CTLFLAG_RD, &sc->stats.carrier_sense_errors, 0,
1237            "Carrier Sense Errors");
1238
1239        tree = SYSCTL_ADD_NODE(ctx, hwstatsnode, OID_AUTO, "rx", CTLFLAG_RD,
1240                               NULL, "if_atsam hardware receive statistics");
1241        child = SYSCTL_CHILDREN(tree);
1242
1243        SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_rec",
1244            CTLFLAG_RD, &sc->stats.octets_rec,
1245            "Octets Received");
1246        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_rec",
1247            CTLFLAG_RD, &sc->stats.frames_rec, 0,
1248            "Frames Received");
1249        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_rec",
1250            CTLFLAG_RD, &sc->stats.broadcast_frames_rec, 0,
1251            "Broadcast Frames Received");
1252        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_rec",
1253            CTLFLAG_RD, &sc->stats.multicast_frames_rec, 0,
1254            "Multicast Frames Received");
1255        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_rec",
1256            CTLFLAG_RD, &sc->stats.pause_frames_rec, 0,
1257            "Pause Frames Received");
1258        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_rec",
1259            CTLFLAG_RD, &sc->stats.frames_64_byte_rec, 0,
1260            "64 Byte Frames Received");
1261        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_rec",
1262            CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_rec, 0,
1263            "65 to 127 Byte Frames Received");
1264        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_rec",
1265            CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_rec, 0,
1266            "128 to 255 Byte Frames Received");
1267        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_rec",
1268            CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_rec, 0,
1269            "256 to 511 Byte Frames Received");
1270        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_rec",
1271            CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_rec, 0,
1272            "512 to 1023 Byte Frames Received");
1273        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_rec",
1274            CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_rec, 0,
1275            "1024 to 1518 Byte Frames Received");
1276        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_byte_rec",
1277            CTLFLAG_RD, &sc->stats.frames_1519_to_maximum_byte_rec, 0,
1278            "1519 to Maximum Byte Frames Received");
1279        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames_rec",
1280            CTLFLAG_RD, &sc->stats.undersize_frames_rec, 0,
1281            "Undersize Frames Received");
1282        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames_rec",
1283            CTLFLAG_RD, &sc->stats.oversize_frames_rec, 0,
1284            "Oversize Frames Received");
1285        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers_rec",
1286            CTLFLAG_RD, &sc->stats.jabbers_rec, 0,
1287            "Jabbers Received");
1288        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frame_check_sequence_errors",
1289            CTLFLAG_RD, &sc->stats.frame_check_sequence_errors, 0,
1290            "Frame Check Sequence Errors");
1291        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "length_field_frame_errors",
1292            CTLFLAG_RD, &sc->stats.length_field_frame_errors, 0,
1293            "Length Field Frame Errors");
1294        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_symbol_errors",
1295            CTLFLAG_RD, &sc->stats.receive_symbol_errors, 0,
1296            "Receive Symbol Errors");
1297        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "alignment_errors",
1298            CTLFLAG_RD, &sc->stats.alignment_errors, 0,
1299            "Alignment Errors");
1300        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_resource_errors",
1301            CTLFLAG_RD, &sc->stats.receive_resource_errors, 0,
1302            "Receive Resource Errors");
1303        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "receive_overrun",
1304            CTLFLAG_RD, &sc->stats.receive_overrun, 0,
1305            "Receive Overrun");
1306        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ip_header_checksum_errors",
1307            CTLFLAG_RD, &sc->stats.ip_header_checksum_errors, 0,
1308            "IP Header Checksum Errors");
1309        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tcp_checksum_errors",
1310            CTLFLAG_RD, &sc->stats.tcp_checksum_errors, 0,
1311            "TCP Checksum Errors");
1312        SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "udp_checksum_errors",
1313            CTLFLAG_RD, &sc->stats.udp_checksum_errors, 0,
1314            "UDP Checksum Errors");
1315}
1316
1317
1318/*
1319 * Calculates the index that is to be sent into the hash registers
1320 */
1321static void if_atsam_get_hash_index(uint64_t addr, uint32_t *val)
1322{
1323        uint64_t tmp_val;
1324        uint8_t i, j;
1325        uint64_t idx;
1326        int offset = 0;
1327
1328        addr &= MAC_ADDR_MASK;
1329
1330        for (i = 0; i < HASH_INDEX_AMOUNT; ++i) {
1331                tmp_val = 0;
1332                offset = 0;
1333                for (j = 0; j < HASH_ELEMENTS_PER_INDEX; j++) {
1334                        idx = (addr >> (offset + i)) & MAC_IDX_MASK;
1335                        tmp_val ^= idx;
1336                        offset += HASH_INDEX_AMOUNT;
1337                }
1338                if (tmp_val > 0) {
1339                        *val |= (1u << i);
1340                }
1341        }
1342}
1343
1344
1345/*
1346 * Dis/Enable promiscuous Mode
1347 */
1348static void if_atsam_promiscuous_mode(if_atsam_softc *sc, bool enable)
1349{
1350        Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
1351
1352        if (enable) {
1353                pHw->GMAC_NCFGR |= GMAC_PROM_ENABLE;
1354        } else {
1355                pHw->GMAC_NCFGR &= ~GMAC_PROM_ENABLE;
1356        }
1357}
1358
1359
1360static int
1361if_atsam_mediaioctl(if_atsam_softc *sc, struct ifreq *ifr, u_long command)
1362{
1363        if (sc->fixed_speed) {
1364                return ifmedia_ioctl(sc->ifp, ifr, &sc->ifmedia, command);
1365        } else {
1366                struct mii_data *mii;
1367
1368                if (sc->miibus == NULL)
1369                        return (EINVAL);
1370
1371                mii = device_get_softc(sc->miibus);
1372                return (ifmedia_ioctl(sc->ifp, ifr, &mii->mii_media, command));
1373        }
1374}
1375
1376
1377/*
1378 * Driver ioctl handler
1379 */
1380static int
1381if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1382{
1383        if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
1384        struct ifreq *ifr = (struct ifreq *)data;
1385        int rv = 0;
1386        bool prom_enable;
1387        struct mii_data *mii;
1388
1389        switch (command) {
1390        case SIOCGIFMEDIA:
1391        case SIOCSIFMEDIA:
1392                rv = if_atsam_mediaioctl(sc, ifr, command);
1393                break;
1394        case SIOCSIFFLAGS:
1395                if (ifp->if_flags & IFF_UP) {
1396                        if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1397                                if_atsam_init(sc);
1398                        }
1399                        prom_enable = ((ifp->if_flags & IFF_PROMISC) != 0);
1400                        if_atsam_promiscuous_mode(sc, prom_enable);
1401                } else {
1402                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1403                                if_atsam_stop(sc);
1404                        }
1405                }
1406                break;
1407        default:
1408                rv = ether_ioctl(ifp, command, data);
1409                break;
1410        }
1411        return (rv);
1412}
1413
1414/*
1415 * Attach an SAMV71 driver to the system
1416 */
1417static int if_atsam_driver_attach(device_t dev)
1418{
1419        if_atsam_softc *sc;
1420        struct ifnet *ifp;
1421        int unit;
1422        char *unitName;
1423        uint8_t eaddr[ETHER_ADDR_LEN];
1424
1425        sc = device_get_softc(dev);
1426        unit = device_get_unit(dev);
1427        assert(unit == 0);
1428
1429        sc->dev = dev;
1430        sc->ifp = ifp = if_alloc(IFT_ETHER);
1431
1432        mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK,
1433            MTX_DEF);
1434
1435        rtems_bsd_if_atsam_get_if_media_props(device_get_name(sc->dev), unit,
1436            &sc->fixed_speed, &sc->media, &sc->duplex);
1437        rtems_bsd_get_mac_address(device_get_name(sc->dev), unit, eaddr);
1438
1439        sc->Gmac_inst.retries = MDIO_RETRIES;
1440
1441        memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN);
1442
1443        sc->amount_rx_buf = RXBUF_COUNT;
1444        sc->amount_tx_buf = TXBUF_COUNT;
1445
1446        sc->tx_ring.tx_bd_used = 0;
1447        sc->tx_ring.tx_bd_free = 0;
1448        sc->tx_ring.length = sc->amount_tx_buf;
1449
1450        /* Set Initial Link Speed */
1451        sc->link_speed = GMAC_SPEED_100M;
1452        sc->link_duplex = GMAC_DUPLEX_FULL;
1453
1454        GMACD_Init(&sc->Gmac_inst.gGmacd, GMAC, ID_GMAC, GMAC_CAF_ENABLE,
1455            GMAC_NBC_DISABLE);
1456
1457        /* Enable MDIO interface */
1458        GMAC_EnableMdio(sc->Gmac_inst.gGmacd.pHw);
1459
1460        /* PHY initialize */
1461        if_atsam_init_phy(&sc->Gmac_inst, BOARD_MCK, NULL, 0,
1462            gmacPins, PIO_LISTSIZE(gmacPins));
1463
1464        /*
1465         * MII Bus
1466         */
1467        callout_init_mtx(&sc->tick_ch, &sc->mtx, CALLOUT_RETURNUNLOCKED);
1468        if (!sc->fixed_speed) {
1469                mii_attach(dev, &sc->miibus, ifp, if_atsam_mii_ifmedia_upd,
1470                    if_atsam_mii_ifmedia_sts, BMSR_DEFCAPMASK,
1471                    MDIO_PHY, MII_OFFSET_ANY, 0);
1472        } else {
1473                ifmedia_init(&sc->ifmedia, 0, if_atsam_media_change,
1474                    if_atsam_media_status);
1475                ifmedia_add(&sc->ifmedia, IFM_ETHER | sc->media
1476                    | sc->duplex, 0, NULL);
1477                ifmedia_set(&sc->ifmedia, IFM_ETHER | sc->media
1478                    | sc->duplex);
1479
1480                GMAC_SetLinkSpeed(sc->Gmac_inst.gGmacd.pHw,
1481                    if_atsam_get_gmac_linkspeed_from_media(sc->media),
1482                    if_atsam_get_gmac_duplex_from_media(sc->duplex));
1483
1484                if_link_state_change(sc->ifp, LINK_STATE_UP);
1485        }
1486
1487        /*
1488         * Set up network interface values
1489         */
1490        ifp->if_softc = sc;
1491        if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1492        ifp->if_init = if_atsam_init;
1493        ifp->if_ioctl = if_atsam_ioctl;
1494        ifp->if_start = if_atsam_enet_start;
1495        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1496        ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
1497            IFCAP_VLAN_HWCSUM;
1498        ifp->if_hwassist = CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP |
1499            CSUM_IP6_UDP | CSUM_IP6_TCP;
1500        IFQ_SET_MAXLEN(&ifp->if_snd, TXBUF_COUNT - 1);
1501        ifp->if_snd.ifq_drv_maxlen = TXBUF_COUNT - 1;
1502        IFQ_SET_READY(&ifp->if_snd);
1503
1504        /*
1505         * Attach the interface
1506         */
1507        ether_ifattach(ifp, eaddr);
1508
1509        if_atsam_add_sysctls(dev);
1510
1511        return (0);
1512}
1513
1514static int
1515if_atsam_probe(device_t dev)
1516{
1517        int unit = device_get_unit(dev);
1518        int error;
1519
1520        if (unit >= 0 && unit < NIFACES) {
1521                error = BUS_PROBE_DEFAULT;
1522        } else {
1523                error = ENXIO;
1524        }
1525
1526        return (error);
1527}
1528
1529static device_method_t if_atsam_methods[] = {
1530        DEVMETHOD(device_probe,         if_atsam_probe),
1531        DEVMETHOD(device_attach,        if_atsam_driver_attach),
1532        DEVMETHOD(miibus_readreg,       if_atsam_miibus_readreg),
1533        DEVMETHOD(miibus_writereg,      if_atsam_miibus_writereg),
1534        DEVMETHOD(miibus_statchg,       if_atsam_miibus_statchg),
1535        DEVMETHOD_END
1536};
1537
1538static driver_t if_atsam_nexus_driver = {
1539        "if_atsam",
1540        if_atsam_methods,
1541        sizeof(struct if_atsam_softc)
1542};
1543
1544static devclass_t if_atsam_devclass;
1545DRIVER_MODULE(if_atsam, nexus, if_atsam_nexus_driver, if_atsam_devclass, 0, 0);
1546MODULE_DEPEND(if_atsam, nexus, 1, 1, 1);
1547MODULE_DEPEND(if_atsam, ether, 1, 1, 1);
1548MODULE_DEPEND(if_atsam, miibus, 1, 1, 1);
1549DRIVER_MODULE(miibus, if_atsam, miibus_driver, miibus_devclass, NULL, NULL);
1550
1551#endif /* LIBBSP_ARM_ATSAM_BSP_H */
Note: See TracBrowser for help on using the repository browser.