| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_cemac.c,v 1.21 2019/05/28 07:41:48 msaitoh Exp $ */ | | 1 | /* $NetBSD: if_cemac.c,v 1.22 2020/01/29 05:54:29 thorpej Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2015 Genetec Corporation. All rights reserved. | | 4 | * Copyright (c) 2015 Genetec Corporation. All rights reserved. |
5 | * Written by Hashimoto Kenichi for Genetec Corporation. | | 5 | * Written by Hashimoto Kenichi for Genetec Corporation. |
6 | * | | 6 | * |
7 | * Based on arch/arm/at91/at91emac.c | | 7 | * Based on arch/arm/at91/at91emac.c |
8 | * | | 8 | * |
9 | * Copyright (c) 2007 Embedtronics Oy | | 9 | * Copyright (c) 2007 Embedtronics Oy |
10 | * All rights reserved. | | 10 | * All rights reserved. |
11 | * | | 11 | * |
12 | * Copyright (c) 2004 Jesse Off | | 12 | * Copyright (c) 2004 Jesse Off |
13 | * All rights reserved. | | 13 | * All rights reserved. |
14 | * | | 14 | * |
| @@ -30,27 +30,27 @@ | | | @@ -30,27 +30,27 @@ |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
34 | * POSSIBILITY OF SUCH DAMAGE. | | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | /* | | 37 | /* |
38 | * Cadence EMAC/GEM ethernet controller IP driver | | 38 | * Cadence EMAC/GEM ethernet controller IP driver |
39 | * used by arm/at91, arm/zynq SoC | | 39 | * used by arm/at91, arm/zynq SoC |
40 | */ | | 40 | */ |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.21 2019/05/28 07:41:48 msaitoh Exp $"); | | 43 | __KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.22 2020/01/29 05:54:29 thorpej Exp $"); |
44 | | | 44 | |
45 | #include <sys/types.h> | | 45 | #include <sys/types.h> |
46 | #include <sys/param.h> | | 46 | #include <sys/param.h> |
47 | #include <sys/systm.h> | | 47 | #include <sys/systm.h> |
48 | #include <sys/ioctl.h> | | 48 | #include <sys/ioctl.h> |
49 | #include <sys/kernel.h> | | 49 | #include <sys/kernel.h> |
50 | #include <sys/proc.h> | | 50 | #include <sys/proc.h> |
51 | #include <sys/malloc.h> | | 51 | #include <sys/malloc.h> |
52 | #include <sys/time.h> | | 52 | #include <sys/time.h> |
53 | #include <sys/device.h> | | 53 | #include <sys/device.h> |
54 | #include <uvm/uvm_extern.h> | | 54 | #include <uvm/uvm_extern.h> |
55 | | | 55 | |
56 | #include <sys/bus.h> | | 56 | #include <sys/bus.h> |
| @@ -286,40 +286,41 @@ cemac_intr(void *arg) | | | @@ -286,40 +286,41 @@ cemac_intr(void *arg) |
286 | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM))) { | | 286 | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM))) { |
287 | // interrupt not enabled, can't be us | | 287 | // interrupt not enabled, can't be us |
288 | return 0; | | 288 | return 0; |
289 | } | | 289 | } |
290 | | | 290 | |
291 | isr = CEMAC_READ(ETH_ISR); | | 291 | isr = CEMAC_READ(ETH_ISR); |
292 | CEMAC_WRITE(ETH_ISR, isr); | | 292 | CEMAC_WRITE(ETH_ISR, isr); |
293 | isr &= imr; | | 293 | isr &= imr; |
294 | #ifdef CEMAC_DEBUG | | 294 | #ifdef CEMAC_DEBUG |
295 | rsr = CEMAC_READ(ETH_RSR); // get receive status register | | 295 | rsr = CEMAC_READ(ETH_RSR); // get receive status register |
296 | #endif | | 296 | #endif |
297 | DPRINTFN(2, ("%s: isr=0x%08X rsr=0x%08X imr=0x%08X\n", __FUNCTION__, isr, rsr, imr)); | | 297 | DPRINTFN(2, ("%s: isr=0x%08X rsr=0x%08X imr=0x%08X\n", __FUNCTION__, isr, rsr, imr)); |
298 | | | 298 | |
| | | 299 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); |
299 | if (isr & ETH_ISR_RBNA) { // out of receive buffers | | 300 | if (isr & ETH_ISR_RBNA) { // out of receive buffers |
300 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear interrupt | | 301 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear interrupt |
301 | ctl = CEMAC_READ(ETH_CTL); // get current control register value | | 302 | ctl = CEMAC_READ(ETH_CTL); // get current control register value |
302 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); // disable receiver | | 303 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); // disable receiver |
303 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear BNA bit | | 304 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear BNA bit |
304 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); // re-enable receiver | | 305 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); // re-enable receiver |
305 | ifp->if_ierrors++; | | 306 | if_statinc_ref(nsr, if_ierrors); |
306 | ifp->if_ipackets++; | | 307 | if_statinc_ref(nsr, if_ipackets); |
307 | DPRINTFN(1,("%s: out of receive buffers\n", __FUNCTION__)); | | 308 | DPRINTFN(1,("%s: out of receive buffers\n", __FUNCTION__)); |
308 | } | | 309 | } |
309 | if (isr & ETH_ISR_ROVR) { | | 310 | if (isr & ETH_ISR_ROVR) { |
310 | CEMAC_WRITE(ETH_RSR, ETH_RSR_OVR); // clear interrupt | | 311 | CEMAC_WRITE(ETH_RSR, ETH_RSR_OVR); // clear interrupt |
311 | ifp->if_ierrors++; | | 312 | if_statinc_ref(nsr, if_ierrors); |
312 | ifp->if_ipackets++; | | 313 | if_statinc_ref(nsr, if_ipackets); |
313 | DPRINTFN(1,("%s: receive overrun\n", __FUNCTION__)); | | 314 | DPRINTFN(1,("%s: receive overrun\n", __FUNCTION__)); |
314 | } | | 315 | } |
315 | | | 316 | |
316 | if (isr & ETH_ISR_RCOM) { // packet has been received! | | 317 | if (isr & ETH_ISR_RCOM) { // packet has been received! |
317 | uint32_t nfo; | | 318 | uint32_t nfo; |
318 | DPRINTFN(2,("#2 RDSC[%i].INFO=0x%08X\n", sc->rxqi % RX_QLEN, sc->RDSC[sc->rxqi % RX_QLEN].Info)); | | 319 | DPRINTFN(2,("#2 RDSC[%i].INFO=0x%08X\n", sc->rxqi % RX_QLEN, sc->RDSC[sc->rxqi % RX_QLEN].Info)); |
319 | while (sc->RDSC[(bi = sc->rxqi % RX_QLEN)].Addr & ETH_RDSC_F_USED) { | | 320 | while (sc->RDSC[(bi = sc->rxqi % RX_QLEN)].Addr & ETH_RDSC_F_USED) { |
320 | int fl, csum; | | 321 | int fl, csum; |
321 | struct mbuf *m; | | 322 | struct mbuf *m; |
322 | | | 323 | |
323 | nfo = sc->RDSC[bi].Info; | | 324 | nfo = sc->RDSC[bi].Info; |
324 | fl = (nfo & ETH_RDSC_I_LEN) - 4; | | 325 | fl = (nfo & ETH_RDSC_I_LEN) - 4; |
325 | DPRINTFN(2,("## nfo=0x%08X\n", nfo)); | | 326 | DPRINTFN(2,("## nfo=0x%08X\n", nfo)); |
| @@ -363,32 +364,34 @@ cemac_intr(void *arg) | | | @@ -363,32 +364,34 @@ cemac_intr(void *arg) |
363 | NULL, BUS_DMA_NOWAIT); | | 364 | NULL, BUS_DMA_NOWAIT); |
364 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, | | 365 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, |
365 | MCLBYTES, BUS_DMASYNC_PREREAD); | | 366 | MCLBYTES, BUS_DMASYNC_PREREAD); |
366 | sc->RDSC[bi].Info = 0; | | 367 | sc->RDSC[bi].Info = 0; |
367 | sc->RDSC[bi].Addr = | | 368 | sc->RDSC[bi].Addr = |
368 | sc->rxq[bi].m_dmamap->dm_segs[0].ds_addr | | 369 | sc->rxq[bi].m_dmamap->dm_segs[0].ds_addr |
369 | | (bi == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); | | 370 | | (bi == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); |
370 | } else { | | 371 | } else { |
371 | /* Drop packets until we can get replacement | | 372 | /* Drop packets until we can get replacement |
372 | * empty mbufs for the RXDQ. | | 373 | * empty mbufs for the RXDQ. |
373 | */ | | 374 | */ |
374 | if (m != NULL) | | 375 | if (m != NULL) |
375 | m_freem(m); | | 376 | m_freem(m); |
376 | ifp->if_ierrors++; | | 377 | if_statinc_ref(nsr, if_ierrors); |
377 | } | | 378 | } |
378 | sc->rxqi++; | | 379 | sc->rxqi++; |
379 | } | | 380 | } |
380 | } | | 381 | } |
381 | | | 382 | |
| | | 383 | IF_STAT_PUTREF(ifp); |
| | | 384 | |
382 | if (cemac_gctx(sc) > 0) | | 385 | if (cemac_gctx(sc) > 0) |
383 | if_schedule_deferred_start(ifp); | | 386 | if_schedule_deferred_start(ifp); |
384 | #if 0 // reloop | | 387 | #if 0 // reloop |
385 | irq = CEMAC_READ(IntStsC); | | 388 | irq = CEMAC_READ(IntStsC); |
386 | if ((irq & (IntSts_RxSQ | IntSts_ECI)) != 0) | | 389 | if ((irq & (IntSts_RxSQ | IntSts_ECI)) != 0) |
387 | goto begin; | | 390 | goto begin; |
388 | #endif | | 391 | #endif |
389 | | | 392 | |
390 | return (1); | | 393 | return (1); |
391 | } | | 394 | } |
392 | | | 395 | |
393 | | | 396 | |
394 | static void | | 397 | static void |
| @@ -709,29 +712,31 @@ cemac_statchg(struct ifnet *ifp) | | | @@ -709,29 +712,31 @@ cemac_statchg(struct ifnet *ifp) |
709 | break; | | 712 | break; |
710 | } | | 713 | } |
711 | CEMAC_WRITE(ETH_CFG, reg); | | 714 | CEMAC_WRITE(ETH_CFG, reg); |
712 | } | | 715 | } |
713 | | | 716 | |
714 | static void | | 717 | static void |
715 | cemac_tick(void *arg) | | 718 | cemac_tick(void *arg) |
716 | { | | 719 | { |
717 | struct cemac_softc* sc = (struct cemac_softc *)arg; | | 720 | struct cemac_softc* sc = (struct cemac_softc *)arg; |
718 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; | | 721 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; |
719 | int s; | | 722 | int s; |
720 | | | 723 | |
721 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 724 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
722 | ifp->if_collisions += CEMAC_READ(GEM_SCOL) + CEMAC_READ(GEM_MCOL); | | 725 | if_statadd(ifp, if_collisions, |
| | | 726 | CEMAC_READ(GEM_SCOL) + CEMAC_READ(GEM_MCOL)); |
723 | else | | 727 | else |
724 | ifp->if_collisions += CEMAC_READ(ETH_SCOL) + CEMAC_READ(ETH_MCOL); | | 728 | if_statadd(ifp, if_collisions, |
| | | 729 | CEMAC_READ(ETH_SCOL) + CEMAC_READ(ETH_MCOL)); |
725 | | | 730 | |
726 | /* These misses are ok, they will happen if the RAM/CPU can't keep up */ | | 731 | /* These misses are ok, they will happen if the RAM/CPU can't keep up */ |
727 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 732 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
728 | uint32_t misses = CEMAC_READ(ETH_DRFC); | | 733 | uint32_t misses = CEMAC_READ(ETH_DRFC); |
729 | if (misses > 0) | | 734 | if (misses > 0) |
730 | aprint_normal_ifnet(ifp, "%d rx misses\n", misses); | | 735 | aprint_normal_ifnet(ifp, "%d rx misses\n", misses); |
731 | } | | 736 | } |
732 | | | 737 | |
733 | s = splnet(); | | 738 | s = splnet(); |
734 | if (cemac_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) | | 739 | if (cemac_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) |
735 | cemac_ifstart(ifp); | | 740 | cemac_ifstart(ifp); |
736 | splx(s); | | 741 | splx(s); |
737 | | | 742 | |