]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/sja1000p.c
The SJA1000 interrupt support modified to provide more robust error recovery handling.
[lincan.git] / lincan / src / sja1000p.c
index 59fa68dcb39ed4a807ca054fd9a04445c2f165a8..ffadb6c74347aceebec1510aa675ca524690a3f1 100644 (file)
 #include "../include/main.h"
 #include "../include/sja1000p.h"
 
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+
+static const char *sja1000_ecc_errc_str[]={
+       "bit error",
+       "form error",
+       "stuff error",
+       "other type of error"
+};
+
+static const char *sja1000_ecc_seg_str[]={
+       "?0?",
+       "?1?",
+       "ID.28 to ID.21",
+       "start of frame",
+       "bit SRTR",
+       "bit IDE",
+       "ID.20 to ID.18",
+       "ID.17 to ID.13",
+       "CRC sequence",
+       "reserved bit 0",
+       "data field",
+       "data length code",
+       "bit RTR",
+       "reserved bit 1",
+       "ID.4 to ID.0",
+       "ID.12 to ID.5",
+       "?16?"
+       "active error flag",
+       "intermission",
+       "tolerate dominant bits",
+       "?20?",
+       "?21?",
+       "passive error flag",
+       "error delimiter",
+       "CRC delimiter",
+       "acknowledge slot",
+       "end of frame",
+       "acknowledge delimiter",
+       "overload flag",
+       "?29?",
+       "?30?",
+       "?31?"
+};
+
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+
+static int sja1000_report_error_limit_counter;
+
+static void sja1000_report_error(struct canchip_t *chip,
+                               unsigned sr, unsigned ir, unsigned ecc)
+{
+       if(sja1000_report_error_limit_counter>=100)
+               return;
+
+       CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
+               sr, ir, ecc);
+
+       sja1000_report_error_limit_counter+=10;
+
+       if(sja1000_report_error_limit_counter>=100){
+               sja1000_report_error_limit_counter+=10;
+               CANMSG("Error: too many errors, reporting disabled\n");
+               return;
+       }
+
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+       CANMSG("SR: BS=%c  ES=%c  TS=%c  RS=%c  TCS=%c TBS=%c DOS=%c RBS=%c\n",
+               sr&sjaSR_BS?'1':'0',sr&sjaSR_ES?'1':'0',
+               sr&sjaSR_TS?'1':'0',sr&sjaSR_RS?'1':'0',
+               sr&sjaSR_TCS?'1':'0',sr&sjaSR_TBS?'1':'0',
+               sr&sjaSR_DOS?'1':'0',sr&sjaSR_RBS?'1':'0');
+       CANMSG("IR: BEI=%c ALI=%c EPI=%c WUI=%c DOI=%c EI=%c  TI=%c  RI=%c\n",
+               sr&sjaIR_BEI?'1':'0',sr&sjaIR_ALI?'1':'0',
+               sr&sjaIR_EPI?'1':'0',sr&sjaIR_WUI?'1':'0',
+               sr&sjaIR_DOI?'1':'0',sr&sjaIR_EI?'1':'0',
+               sr&sjaIR_TI?'1':'0',sr&sjaIR_RI?'1':'0');
+       if((sr&sjaIR_EI) || 1){
+               CANMSG("EI: %s %s %s\n",
+                      sja1000_ecc_errc_str[(ecc&(sjaECC_ERCC1|sjaECC_ERCC0))/sjaECC_ERCC0],
+                      ecc&sjaECC_DIR?"RX":"TX",
+                      sja1000_ecc_seg_str[ecc&sjaECC_SEG_M]
+                     );
+       }
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+}
+
+
 /**
  * sja1000p_enable_configuration - enable chip configuration mode
  * @chip: pointer to chip state structure
@@ -470,6 +557,8 @@ int sja1000p_start_chip(struct canchip_t *chip)
        flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM);
        can_write_reg(chip, flags, SJAMOD);
 
+       sja1000_report_error_limit_counter=0;
+
        return 0;
 }
 
@@ -678,7 +767,8 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
 
                /* (irq_register & sjaIR_TI) */
                /*      old variant using SJAIR, collides with intended use with irq_accept */
-               if ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) {
+               if (((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING))||
+                   (can_msgobj_test_fl(obj,TX_REQUEST))) {
                        DEBUGMSG("sja1000_irq_handler: TI or TX_PENDING and TBS\n");
                        obj->ret = 0;
                        can_msgobj_set_fl(obj,TX_REQUEST);
@@ -696,11 +786,10 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { 
                        // Some error happened
                        error_code=can_read_reg(chip,SJAECC);
-                       CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
-                               status, irq_register, error_code);
+                       sja1000_report_error(chip, status, irq_register, error_code);
 // FIXME: chip should be brought to usable state. Transmission cancelled if in progress.
 // Reset flag set to 0 if chip is already off the bus. Full state report
-               obj->ret=-1;
+                       obj->ret=-1;
                
                        if(error_code == 0xd9) {
                                obj->ret= -ENXIO;
@@ -722,15 +811,21 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                        }
 
                } else {
+                       if(sja1000_report_error_limit_counter)
+                               sja1000_report_error_limit_counter--;
                        obj->tx_retry_cnt=0;
                }
 
                irq_register=can_read_reg(chip,SJAIR);
-       
+
                status=can_read_reg(chip,SJASR);
 
-       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) ||
-               ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+               if(((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+                  (irq_register & sjaIR_TI))
+                        can_msgobj_set_fl(obj,TX_REQUEST);
+
+       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_RI)) ||
+               (can_msgobj_test_fl(obj,TX_REQUEST) && !can_msgobj_test_fl(obj,TX_LOCK)) ||
                (status & sjaSR_RBS));
 
        return CANCHIP_IRQ_HANDLED;