Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/bouyer-socketcan]: src/sys/arch/arm/allwinner Handle interface errors.



details:   https://anonhg.NetBSD.org/src/rev/718d768f74c4
branches:  bouyer-socketcan
changeset: 820895:718d768f74c4
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Thu Apr 20 13:00:52 2017 +0000

description:
Handle interface errors.
Use a watchdog for transmit.

diffstat:

 sys/arch/arm/allwinner/awin_can.c |  100 ++++++++++++++++++++++++++++++++++++-
 1 files changed, 96 insertions(+), 4 deletions(-)

diffs (193 lines):

diff -r 7e9cf1128a2f -r 718d768f74c4 sys/arch/arm/allwinner/awin_can.c
--- a/sys/arch/arm/allwinner/awin_can.c Thu Apr 20 12:59:54 2017 +0000
+++ b/sys/arch/arm/allwinner/awin_can.c Thu Apr 20 13:00:52 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: awin_can.c,v 1.1.2.2 2017/04/19 17:54:18 bouyer Exp $  */
+/*     $NetBSD: awin_can.c,v 1.1.2.3 2017/04/20 13:00:52 bouyer Exp $  */
 
 /*-
  * Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: awin_can.c,v 1.1.2.2 2017/04/19 17:54:18 bouyer Exp $");
+__KERNEL_RCSID(1, "$NetBSD: awin_can.c,v 1.1.2.3 2017/04/20 13:00:52 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -60,6 +60,15 @@
 #include <arm/allwinner/awin_reg.h>
 #include <arm/allwinner/awin_var.h>
 
+/* shortcut for all error interrupts */
+#define AWIN_CAN_INT_ALLERRS (\
+       AWIN_CAN_INT_BERR | \
+       AWIN_CAN_INT_ARB_LOST | \
+       AWIN_CAN_INT_ERR_PASSIVE | \
+       AWIN_CAN_INT_DATA_OR | \
+       AWIN_CAN_INT_ERR \
+    )
+
 struct awin_can_softc {
        struct canif_softc sc_cansc;
        bus_space_tag_t sc_bst;
@@ -164,6 +173,8 @@
            CAN_LINKMODE_3SAMPLES | CAN_LINKMODE_LISTENONLY |
            CAN_LINKMODE_LOOPBACK;
        can_ifinit_timings(&sc->sc_cansc);
+       sc->sc_timings.clt_prop = 0;
+       sc->sc_timings.clt_sjw = 1;
 
        aprint_naive("\n");
        aprint_normal(": CAN bus controller\n");
@@ -222,6 +233,7 @@
        int dlc;
        int regd, i;
 
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
        reg0v = awin_can_read(sc, AWIN_CAN_TXBUF0_REG);
        dlc = reg0v & AWIN_CAN_TXBUF0_DL;
 
@@ -268,6 +280,7 @@
        ifp->if_ibytes += m->m_len;
        m_set_rcvif(m, ifp);
        bpf_mtap(ifp, m);
+       printf("can_input1\n");
        can_input(ifp, m);
 }
 
@@ -281,11 +294,13 @@
        uint32_t reg0val;
        int i;
 
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
        if ((m = sc->sc_m_transmit) != NULL) {
                ifp->if_obytes += m->m_len;
                ifp->if_opackets++;
                can_mbuf_tag_clean(m);
                m_set_rcvif(m, ifp);
+               printf("can_input2\n");
                can_input(ifp, m); /* loopback */
                sc->sc_m_transmit = NULL;
        }
@@ -331,11 +346,68 @@
        }
        awin_can_write(sc, AWIN_CAN_TXBUF0_REG, reg0val);
 
-       awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_TANS_REQ);
+       if (sc->sc_linkmodes & CAN_LINKMODE_LOOPBACK) {
+               awin_can_write(sc, AWIN_CAN_CMD_REG,
+                       AWIN_CAN_CMD_TANS_REQ | AWIN_CAN_CMD_SELF_REQ);
+       } else {
+               awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_TANS_REQ);
+       }
        ifp->if_flags |= IFF_OACTIVE;
+       ifp->if_timer = 5;
        bpf_mtap(ifp, m);
 }
 
+static int
+awin_can_tx_abort(struct awin_can_softc *sc)
+{
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
+       if (sc->sc_m_transmit) {
+               m_freem(sc->sc_m_transmit);
+               sc->sc_m_transmit = NULL;
+               sc->sc_ifp->if_timer = 0;
+               /*
+                * the transmit abort will trigger a TX interrupt
+                * which will restart the queue or cleae OACTIVE,
+                * as appropriate
+                */
+               awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_ABT_REQ);
+               return 1;
+       }
+       return 0;
+}
+
+static void
+awin_can_err_intr(struct awin_can_softc *sc, uint32_t irq, uint32_t sts)
+{
+       struct ifnet * const ifp = sc->sc_ifp;
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
+       int txerr = 0;
+
+       if (irq & AWIN_CAN_INT_DATA_OR) {
+               ifp->if_ierrors++;
+               awin_can_write(sc, AWIN_CAN_CMD_REG, AWIN_CAN_CMD_CLR_OR);
+       }
+       if (irq & AWIN_CAN_INT_ERR) {
+               /* XXX todo */
+       }
+       if (irq & AWIN_CAN_INT_BERR) {
+               if (sts & AWIN_CAN_STA_TX)
+                       txerr++;
+               if (sts & AWIN_CAN_STA_RX)
+                       ifp->if_ierrors++;
+       }
+       if (irq & AWIN_CAN_INT_ERR_PASSIVE) {
+               /* XXX todo */
+       }
+       if (irq & AWIN_CAN_INT_ARB_LOST) {
+               txerr++;
+       }
+       if (txerr) {
+               ifp->if_oerrors += txerr;
+               (void) awin_can_tx_abort(sc);
+       }
+}
+
 int
 awin_can_intr(void *arg)
 {
@@ -358,6 +430,9 @@
                                sts = awin_can_read(sc, AWIN_CAN_STA_REG);
                        }
                }
+               if (irq & AWIN_CAN_INT_ALLERRS) {
+                       awin_can_err_intr(sc, irq, sts);
+               }
                awin_can_write(sc, AWIN_CAN_INT_REG, irq);
                 rnd_add_uint32(&sc->sc_rnd_source, irq);
 
@@ -424,7 +499,7 @@
 
        awin_can_exit_reset(sc);
        awin_can_write(sc, AWIN_CAN_INTE_REG,
-           AWIN_CAN_INT_TX_FLAG | AWIN_CAN_INT_RX_FLAG);
+           AWIN_CAN_INT_TX_FLAG | AWIN_CAN_INT_RX_FLAG | AWIN_CAN_INT_ALLERRS);
        sc->sc_ifp->if_flags |= IFF_RUNNING;
        return 0;
 }
@@ -433,6 +508,7 @@
 awin_can_ifdown(struct awin_can_softc * const sc)
 {
        sc->sc_ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+       sc->sc_ifp->if_timer = 0;
        awin_can_enter_reset(sc);
        awin_can_write(sc, AWIN_CAN_INTE_REG, 0);
        awin_can_write(sc, AWIN_CAN_INT_REG,
@@ -484,6 +560,22 @@
 void
 awin_can_ifwatchdog(struct ifnet *ifp)
 {
+       struct awin_can_softc * const sc = ifp->if_softc;
+       printf("%s: watchdog timeout\n", device_xname(sc->sc_dev));
+
+       mutex_enter(&sc->sc_intr_lock);
+       printf("irq 0x%x en 0x%x mode 0x%x status 0x%x timings 0x%x err 0x%x\n",
+           awin_can_read(sc, AWIN_CAN_INT_REG),
+           awin_can_read(sc, AWIN_CAN_INTE_REG),
+           awin_can_read(sc, AWIN_CAN_MODSEL_REG),
+           awin_can_read(sc, AWIN_CAN_STA_REG),
+           awin_can_read(sc, AWIN_CAN_BUS_TIME_REG),
+           awin_can_read(sc, AWIN_CAN_REC_REG));
+       /* if there is a transmit in progress abort */
+       if (awin_can_tx_abort(sc)) {
+               ifp->if_oerrors++;
+       }
+       mutex_exit(&sc->sc_intr_lock);
 }
 
 static void



Home | Main Index | Thread Index | Old Index