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

5
Last change on this file since 15f0f9b was 15f0f9b, checked in by Alexander Krutwig <alexander.krutwig@…>, on 04/11/16 at 11:27:53

atsam: Fix network interface PHY handling

Close #2685.

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