From: ppisa Date: Wed, 29 Sep 2004 10:51:16 +0000 (+0000) Subject: Changed SJA1000 chip IRQ handling to loop until all requests are served X-Git-Tag: CLT_COMM_CAN-lincan-0_3~3 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/f911e79d724fdac3af2847cec6383a71e907b00a Changed SJA1000 chip IRQ handling to loop until all requests are served This is not proven to be required for Linux kernel, but it can be possible source of problems for ISA based cards under RT-Linux. --- diff --git a/lincan/CREDITS b/lincan/CREDITS index 132e4ec..8597a9a 100644 --- a/lincan/CREDITS +++ b/lincan/CREDITS @@ -1,3 +1,8 @@ +======================================== +List of developers and code contributors +======================================== + + Arnaud Westenberg, arnaud@wanadoo.nl Original can-0.7.1 author, http://home.wanadoo.nl/arnaud/ Rewrite of LDDK based CAN driver to the simpler infrastructure @@ -19,3 +24,38 @@ http://cmp.felk.cvut.cz/~pisa, http://www.pikron.com Michal Sojka, sojkam1@control.felk.cvut.cz Work on VME support for Unicontrols V-CAN board on the PowerPC PEP VMP1 board + +Jose Pascual josepascual@almudi.com + contributed printer port dongle SJA1000 support + +Michael Moedt xemc@yahoo.com + added support for OSCAR SJA1000 based card connected + to ARM LH7A400 SoC + +======================================== +List of companies and subjects +who donated hardware to LinCAN project +======================================== + +BFAD GmbH & Co.KG +http://www.bfad.de/ + donated BfaD DIMM module CAN card + +PiKRON Ltd. + provided more ISA based cards + +Unicontrols a.s. +http://www.unicontrols.cz/ + provided PC-104, PCI and VME CAN boards + and VMP1 PowerPC based system + +Kvaser AB +http://www.kvaser.com/ + donated PCIcan 4xHS card + +Artificial Vision and Intelligent Vision Lab +Dipartimento di Ingegneria dell'Informazione +Universita' degli Studi di Parma +http://vislab.ce.unipr.it/ + donated EMS CPC-PCI card + diff --git a/lincan/README b/lincan/README index 4b6e4f1..5bc6b4b 100644 --- a/lincan/README +++ b/lincan/README @@ -56,7 +56,7 @@ lincan-0.2-pre heavily rewritten infrastructure of the driver based lincan-0.2 version tested on many bords and 2.2, 2.4, 2.6 Linux (Mar 2004) and RT-Linux enabled 2.4 Linux kernel -lincan-0.3 possible SMP and HT deadlock fixed, driver can take +lincan-0.2.8 possible SMP and HT deadlock fixed, driver can take (Jul 2004) advantage of CMPXCHG instruction if present on CPU, added support for CPC-PCI and PCAN-PCI cards, messages timestamping implemented @@ -214,6 +214,7 @@ The hw argument can be one of: - unican-pci for Unicontrols PCAN-PCI card - unican-vme for Unicontrols VCAN card - ems_cpcpci for EMS CPC-PCI card +- pcan_dongle for PEAK's printer port dongle addapter - oscar for SJA1000 based card connected to ARM LH7A400 SoC - template, for yet unsupported hardware (you need to edit src/template.c) - virtual, CAN channel for testing of software and driver without CAN hardware diff --git a/lincan/include/constants.h b/lincan/include/constants.h index ce3d742..327e5ef 100644 --- a/lincan/include/constants.h +++ b/lincan/include/constants.h @@ -73,15 +73,20 @@ /* These flags can be used for the canchip_t structure flags data entry */ -#define CHIP_CONFIGURED (1<<0) -#define CHIP_SEGMENTED (1<<1) -#define CHIP_IRQ_SETUP (1<<2) -#define CHIP_IRQ_PCI (1<<3) -#define CHIP_IRQ_VME (1<<4) +#define CHIP_CONFIGURED (1<<0) /* chip is configured and prepared for communication */ +#define CHIP_SEGMENTED (1<<1) /* segmented access, ex: i82527 with 16 byte window*/ +#define CHIP_IRQ_SETUP (1<<2) /* IRQ handler has been set */ +#define CHIP_IRQ_PCI (1<<3) /* chip is on PCI board and uses PCI interrupt */ +#define CHIP_IRQ_VME (1<<4) /* interrupt is VME bus and requires VME bridge */ +#define CHIP_IRQ_CUSTOM (1<<5) /* custom interrupt provided by board or chip code */ +#define CHIP_IRQ_FAST (1<<6) /* interrupt handler only schedules postponed processing */ + +#define CHIP_MAX_IRQLOOP 1000 /* System independent defines of IRQ handled state */ #define CANCHIP_IRQ_NONE 0 #define CANCHIP_IRQ_HANDLED 1 +#define CANCHIP_IRQ_STUCK 2 /* These flags can be used for the candevices_t structure flags data entry */ #define CANDEV_PROGRAMMABLE_IRQ (1<<0) diff --git a/lincan/src/can_devrtl.c b/lincan/src/can_devrtl.c index 4557531..5bbc2c0 100644 --- a/lincan/src/can_devrtl.c +++ b/lincan/src/can_devrtl.c @@ -172,7 +172,7 @@ int can_chip_setup_irq(struct canchip_t *chip) attrib_p=&attrib; } - if(chip->chipspecops->irq_handler){ + if(chip->chipspecops->irq_handler && !(chip->flags & CHIP_IRQ_CUSTOM)){ int (*my_request_irq)(unsigned int vector, unsigned int (*rtl_handler)(unsigned int irq, struct pt_regs *regs)); #ifdef CAN_ENABLE_VME_SUPPORT if ((chip->flags & CHIP_IRQ_VME) != 0) @@ -199,7 +199,8 @@ void can_chip_free_irq(struct canchip_t *chip) { if(chip->worker_thread) pthread_delete_np(chip->worker_thread); - if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) { + if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0) + && !(chip->flags & CHIP_IRQ_CUSTOM)) { int (*my_free_irq)(unsigned int vector); #ifdef CAN_ENABLE_VME_SUPPORT if ((chip->flags & CHIP_IRQ_VME) != 0) diff --git a/lincan/src/i82527.c b/lincan/src/i82527.c index d11a79b..fb232f3 100644 --- a/lincan/src/i82527.c +++ b/lincan/src/i82527.c @@ -618,6 +618,7 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) unsigned irq_register; unsigned object; struct msgobj_t *obj; + int loop_cnt=CHIP_MAX_IRQLOOP; /*put_reg=device->hwspecops->write_register;*/ /*get_reg=device->hwspecops->read_register;*/ @@ -632,6 +633,11 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) do { + if(!loop_cnt--) { + CANMSG("i82527_irq_handler IRQ %d stuck\n",irq); + return CANCHIP_IRQ_STUCK; + } + DEBUGMSG("i82527: iIRQ 0x%02x\n",irq_register); if (irq_register == 0x01) { @@ -660,8 +666,10 @@ int i82527_irq_handler(int irq, struct canchip_t *chip) i82527_irq_read_handler(chip, obj, object); } + + irq_register=i82527_seg_read_reg(chip, iIRQ); - } while((irq_register=i82527_seg_read_reg(chip, iIRQ)) != 0); + } while(irq_register != 0); return CANCHIP_IRQ_HANDLED; } diff --git a/lincan/src/pcan_dongle.c b/lincan/src/pcan_dongle.c index 5e6f927..6bd3496 100644 --- a/lincan/src/pcan_dongle.c +++ b/lincan/src/pcan_dongle.c @@ -639,7 +639,7 @@ int pcan_dongle_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH; - candev->chip[chipnr]->flags |= CHIP_IRQ_VME; // I don't want setup call request_irq + candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; // I don't want setup call request_irq // I'm going to do it through parport_register_device } diff --git a/lincan/src/setup.c b/lincan/src/setup.c index c77d03c..9c4af76 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -589,6 +589,8 @@ int can_chip_setup_irq(struct canchip_t *chip) return -1; if(!chip->chipspecops->irq_handler) return 0; + if(chip->flags & CHIP_IRQ_CUSTOM) + return 1; if ((chip->flags & CHIP_IRQ_VME) == 0) { if (request_irq(chip->chip_irq,can_default_irq_dispatch,SA_SHIRQ,DEVICE_NAME,chip)) @@ -620,6 +622,9 @@ int can_chip_setup_irq(struct canchip_t *chip) void can_chip_free_irq(struct canchip_t *chip) { if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) { + if(chip->flags & CHIP_IRQ_CUSTOM) + return; + if ((chip->flags & CHIP_IRQ_VME) == 0) free_irq(chip->chip_irq, chip); else { diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index 27eebca..127c453 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -335,6 +335,7 @@ int sja1000_irq_handler(int irq, struct canchip_t *chip) { unsigned irq_register; struct msgobj_t *obj=chip->msgobj[0]; + int loop_cnt=CHIP_MAX_IRQLOOP; irq_register=can_read_reg(chip, SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); @@ -344,37 +345,48 @@ int sja1000_irq_handler(int irq, struct canchip_t *chip) if ((irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) == 0) return CANCHIP_IRQ_NONE; - if ((irq_register & sjaIR_RI) != 0) - sja1000_irq_read_handler(chip, obj); + do { + + if(!loop_cnt--) { + CANMSG("sja1000_irq_handler IRQ %d stuck\n",irq); + return CANCHIP_IRQ_STUCK; + } + + if ((irq_register & sjaIR_RI) != 0) + sja1000_irq_read_handler(chip, obj); - if ((irq_register & sjaIR_TI) != 0) { - can_msgobj_set_fl(obj,TX_REQUEST); - while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ - can_msgobj_clear_fl(obj,TX_REQUEST); + if ((irq_register & sjaIR_TI) != 0) { + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); - if (can_read_reg(chip, SJASR) & sjaSR_TBS) - sja1000_irq_write_handler(chip, obj); + if (can_read_reg(chip, SJASR) & sjaSR_TBS) + sja1000_irq_write_handler(chip, obj); - can_msgobj_clear_fl(obj,TX_LOCK); - if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + } } - } - if ((irq_register & (sjaIR_EI|sjaIR_DOI)) != 0) { - // Some error happened + if ((irq_register & (sjaIR_EI|sjaIR_DOI)) != 0) { + // Some error happened // 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 - CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", - can_read_reg(chip, SJASR), irq_register); - obj->ret=-1; - - if(obj->tx_slot){ - canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); - /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); - obj->tx_slot=NULL;*/ + CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", + can_read_reg(chip, SJASR), irq_register); + obj->ret=-1; + + if(obj->tx_slot){ + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); + /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL;*/ + } } - } + irq_register=can_read_reg(chip, SJAIR); + + } while(irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)); + return CANCHIP_IRQ_HANDLED; } diff --git a/lincan/src/sja1000p.c b/lincan/src/sja1000p.c index dd9d696..5deedc6 100644 --- a/lincan/src/sja1000p.c +++ b/lincan/src/sja1000p.c @@ -615,6 +615,7 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip) { int irq_register, status, error_code; struct msgobj_t *obj=chip->msgobj[0]; + int loop_cnt=CHIP_MAX_IRQLOOP; irq_register=can_read_reg(chip,SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); @@ -629,58 +630,69 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip) return CANCHIP_IRQ_NONE; } - if ((irq_register & sjaIR_RI) != 0) { - DEBUGMSG("sja1000_irq_handler: RI\n"); - sja1000p_read(chip,obj); - obj->ret = 0; - } - if ((irq_register & sjaIR_TI) != 0) { - DEBUGMSG("sja1000_irq_handler: TI\n"); - obj->ret = 0; - can_msgobj_set_fl(obj,TX_REQUEST); - while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ - can_msgobj_clear_fl(obj,TX_REQUEST); - - if (can_read_reg(chip, SJASR) & sjaSR_TBS) - sja1000p_irq_write_handler(chip, obj); - - can_msgobj_clear_fl(obj,TX_LOCK); - if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; - DEBUGMSG("TX looping in sja1000_irq_handler\n"); + do { + + if(!loop_cnt--) { + CANMSG("sja1000p_irq_handler IRQ %d stuck\n",irq); + return CANCHIP_IRQ_STUCK; } - } - if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { - // Some error happened - status=can_read_reg(chip,SJASR); - 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); + + if ((irq_register & sjaIR_RI) != 0) { + DEBUGMSG("sja1000_irq_handler: RI\n"); + sja1000p_read(chip,obj); + obj->ret = 0; + } + if ((irq_register & sjaIR_TI) != 0) { + DEBUGMSG("sja1000_irq_handler: TI\n"); + obj->ret = 0; + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); + + if (can_read_reg(chip, SJASR) & sjaSR_TBS) + sja1000p_irq_write_handler(chip, obj); + + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + DEBUGMSG("TX looping in sja1000_irq_handler\n"); + } + } + if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { + // Some error happened + status=can_read_reg(chip,SJASR); + 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); // 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; - if(error_code == 0xd9) { - obj->ret= -ENXIO; - /* no such device or address - no ACK received */ - } - if(obj->tx_retry_cnt++>MAX_RETR) { - can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition - obj->tx_retry_cnt = 0; - } - if(status&sjaSR_BS) { - CANMSG("bus-off, resetting sja1000p\n"); - can_write_reg(chip, 0, SJAMOD); - } - - if(obj->tx_slot){ - canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); - /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); - obj->tx_slot=NULL;*/ + if(error_code == 0xd9) { + obj->ret= -ENXIO; + /* no such device or address - no ACK received */ + } + if(obj->tx_retry_cnt++>MAX_RETR) { + can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition + obj->tx_retry_cnt = 0; + } + if(status&sjaSR_BS) { + CANMSG("bus-off, resetting sja1000p\n"); + can_write_reg(chip, 0, SJAMOD); + } + + if(obj->tx_slot){ + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); + /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL;*/ + } + + } else { + obj->tx_retry_cnt=0; } - } else { - obj->tx_retry_cnt=0; - } + irq_register=can_read_reg(chip,SJAIR); + + } while(irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)); return CANCHIP_IRQ_HANDLED; }