net/wan/fsl_ucc_hdlc: error counters
authorMathias Thore <mathias.thore@infinera.com>
Mon, 22 Oct 2018 12:55:50 +0000 (14:55 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 23 Oct 2018 02:58:10 +0000 (19:58 -0700)
Extract error information from rx and tx buffer descriptors,
and update error counters.

Signed-off-by: Mathias Thore <mathias.thore@infinera.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/wan/fsl_ucc_hdlc.c
include/soc/fsl/qe/ucc_fast.h

index 8523ade160307d1570ae6873bb76c0fe99eb3ed2..4d6409605207cca586829d75a7d5b2eeb9f4e8d9 100644 (file)
@@ -36,6 +36,7 @@
 #define DRV_NAME "ucc_hdlc"
 
 #define TDM_PPPOHT_SLIC_MAXIN
+#define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
 
 static struct ucc_tdm_info utdm_primary_info = {
        .uf_info = {
@@ -430,12 +431,25 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
+static int hdlc_tx_restart(struct ucc_hdlc_private *priv)
+{
+       u32 cecr_subblock;
+
+       cecr_subblock =
+               ucc_fast_get_qe_cr_subblock(priv->ut_info->uf_info.ucc_num);
+
+       qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
+                    QE_CR_PROTOCOL_UNSPECIFIED, 0);
+       return 0;
+}
+
 static int hdlc_tx_done(struct ucc_hdlc_private *priv)
 {
        /* Start from the next BD that should be filled */
        struct net_device *dev = priv->ndev;
        struct qe_bd *bd;               /* BD pointer */
        u16 bd_status;
+       int tx_restart = 0;
 
        bd = priv->dirty_tx;
        bd_status = ioread16be(&bd->status);
@@ -444,6 +458,15 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv)
        while ((bd_status & T_R_S) == 0) {
                struct sk_buff *skb;
 
+               if (bd_status & T_UN_S) { /* Underrun */
+                       dev->stats.tx_fifo_errors++;
+                       tx_restart = 1;
+               }
+               if (bd_status & T_CT_S) { /* Carrier lost */
+                       dev->stats.tx_carrier_errors++;
+                       tx_restart = 1;
+               }
+
                /* BD contains already transmitted buffer.   */
                /* Handle the transmitted buffer and release */
                /* the BD to be used with the current frame  */
@@ -475,6 +498,9 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv)
        }
        priv->dirty_tx = bd;
 
+       if (tx_restart)
+               hdlc_tx_restart(priv);
+
        return 0;
 }
 
@@ -493,11 +519,22 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
 
        /* while there are received buffers and BD is full (~R_E) */
        while (!((bd_status & (R_E_S)) || (--rx_work_limit < 0))) {
-               if (bd_status & R_OV_S)
-                       dev->stats.rx_over_errors++;
-               if (bd_status & R_CR_S) {
-                       dev->stats.rx_crc_errors++;
-                       dev->stats.rx_dropped++;
+               if (bd_status & (RX_BD_ERRORS)) {
+                       dev->stats.rx_errors++;
+
+                       if (bd_status & R_CD_S)
+                               dev->stats.collisions++;
+                       if (bd_status & R_OV_S)
+                               dev->stats.rx_fifo_errors++;
+                       if (bd_status & R_CR_S)
+                               dev->stats.rx_crc_errors++;
+                       if (bd_status & R_AB_S)
+                               dev->stats.rx_over_errors++;
+                       if (bd_status & R_NO_S)
+                               dev->stats.rx_frame_errors++;
+                       if (bd_status & R_LG_S)
+                               dev->stats.rx_length_errors++;
+
                        goto recycle;
                }
                bdbuffer = priv->rx_buffer +
@@ -546,7 +583,7 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
                netif_receive_skb(skb);
 
 recycle:
-               iowrite16be(bd_status | R_E_S | R_I_S, &bd->status);
+               iowrite16be((bd_status & R_W_S) | R_E_S | R_I_S, &bd->status);
 
                /* update to point at the next bd */
                if (bd_status & R_W_S) {
@@ -622,7 +659,7 @@ static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id)
 
        /* Errors and other events */
        if (ucce >> 16 & UCC_HDLC_UCCE_BSY)
-               dev->stats.rx_errors++;
+               dev->stats.rx_missed_errors++;
        if (ucce >> 16 & UCC_HDLC_UCCE_TXE)
                dev->stats.tx_errors++;
 
index 3ee9e7c1a7d70c243e69df92c7f700b44f628a7b..dcd6b865b590f15eee245a7546b06293dd3449a6 100644 (file)
 #define R_L_S  0x0800  /* last */
 #define R_F_S  0x0400  /* first */
 #define R_CM_S 0x0200  /* continuous mode */
+#define R_LG_S  0x0020  /* frame length */
+#define R_NO_S  0x0010  /* nonoctet */
+#define R_AB_S  0x0008  /* abort */
 #define R_CR_S 0x0004  /* crc */
-#define R_OV_S 0x0002  /* crc */
+#define R_OV_S 0x0002  /* overrun */
+#define R_CD_S  0x0001  /* carrier detect */
 
 /* transmit BD's status */
 #define T_R_S  0x8000  /* ready bit */
@@ -51,6 +55,8 @@
 #define T_L_S  0x0800  /* last */
 #define T_TC_S 0x0400  /* crc */
 #define T_TM_S 0x0200  /* continuous mode */
+#define T_UN_S  0x0002  /* hdlc underrun */
+#define T_CT_S  0x0001  /* hdlc carrier lost */
 
 /* Rx Data buffer must be 4 bytes aligned in most cases */
 #define UCC_FAST_RX_ALIGN                      4