]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/c_can_irq.c
72ac0b5154cfb52435611ff34f64f47e5cebd753
[lincan.git] / lincan / src / c_can_irq.c
1 /* c_can_irq.c - Hynix HMS30c7202 ARM IRQ handling code
2  * Linux CAN-bus device driver.
3  * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
4  * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
5  * and Ake Hedman, eurosource, akhe@eurosource.se
6  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
7  * email:pisa@cmp.felk.cvut.cz
8  * This software is released under the GPL-License.
9  * Version lincan-0.3  17 Jun 2004
10  */
11  
12 #include "../include/can.h"
13 #include "../include/can_sysdep.h"
14 #include "../include/main.h"
15 #include "../include/c_can.h"
16
17 union c_can_data
18 {
19    unsigned short wdata[4];
20    unsigned char bdata[8];
21 };
22
23
24
25 // prototypes
26 inline void c_can_irq_read_handler( struct canchip_t *pchip, int idxobj, u32 msgid  );
27
28 inline void c_can_irq_write_handler( struct canchip_t *pchip, int idxobj);
29
30 void c_can_irq_rtr_handler( struct canchip_t *pchip, int idxobj, u32 msgid );
31
32 u16 readMaskCM = IFXCM_ARB | IFXCM_CNTRL | IFXCM_CLRINTPND
33   | IFXCM_TRND | IFXCM_DA | IFXCM_DB;
34
35 u16 msgLstReadMaskCM = IFXCM_CNTRL;
36 u16 msgLstWriteMaskCM =  IFXCM_CNTRL | IFXCM_WRRD;
37
38 ///////////////////////////////////////////////////////////////////////////////
39 // c_can_irq_write_handler
40 //
41 // Send a message from the output fifo ( if any ).
42 //
43
44 inline void c_can_irq_write_handler( struct canchip_t *pchip, int idxobj)
45 {
46         int cmd;
47         struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
48
49         DEBUGMSG("(c%dm%d)calling c_can_irq_write_handler(...)\n",
50                 pchip->chip_idx, pmsgobj->object);
51
52         if(pmsgobj->tx_slot){
53                 /* Do local transmitted message distribution if enabled */
54                 if (processlocal){
55                         /* fill CAN message timestamp */
56                         can_filltimestamp(&pmsgobj->tx_slot->msg.timestamp);
57
58                         pmsgobj->tx_slot->msg.flags |= MSG_LOCAL;
59                         canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->tx_slot->msg);
60                 }
61                 /* Free transmitted slot */
62                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
63                 pmsgobj->tx_slot=NULL;
64         }
65    
66         // Get ready to send next message
67         spin_lock( &c_can_spwlock );
68
69         cmd=canque_test_outslot(pmsgobj->qends, &pmsgobj->tx_qedge, &pmsgobj->tx_slot);
70         if(cmd<0){
71                 DEBUGMSG("(c%dm%d)Nothin to write\n",
72                         pchip->chip_idx, pmsgobj->object);
73                 spin_unlock( &c_can_spwlock );
74                 return;
75         }
76
77         // Send the message
78         if ( pchip->chipspecops->send_msg( pchip, pmsgobj,&pmsgobj->tx_slot->msg) ) {
79                 pmsgobj->ret = -1;
80                 canque_notify_inends(pmsgobj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
81                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
82                 pmsgobj->tx_slot=NULL;
83                 spin_unlock( &c_can_spwlock );
84                 DEBUGMSG("(c%dm%d)c_can_irq_handler: Unable to send message\n",
85                         pchip->chip_idx, pmsgobj->object );
86                 return;
87         } else {
88                 // Another message sent
89             #ifdef CAN_WITH_STATISTICS
90                 pchip->stat.cntTxPkt++;
91                 pchip->stat.cntTxData += pmsgobj->tx_slot->length;
92             #endif /*CAN_WITH_STATISTICS*/
93         }
94         spin_unlock( &c_can_spwlock );
95
96         // Wake up any waiting writer
97         return;
98 }
99
100 ///////////////////////////////////////////////////////////////////////////////
101 // c_can_irq_read_handler
102 //
103 // Message received form the line. Write it in the input fifo->
104 //
105
106 inline void c_can_irq_read_handler( struct canchip_t *pchip,
107                                     int idxobj, u32 msgid  )
108 {
109         int i=0;
110         u16 bDataAvail=1 ;
111         u16 msgCntlReg = 0;
112         union c_can_data readData;
113         struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
114                 
115         DEBUGMSG("(c%dm%d)calling c_can_irq_read_handler(...)\n",
116                 pchip->chip_idx, pmsgobj->object);
117         
118         while ( bDataAvail ) {
119              
120             #ifdef CAN_WITH_STATISTICS
121                 pchip->stat.cntRxFifoOvr++;
122             #endif /*CAN_WITH_STATISTICS*/
123                 // Message length
124                 msgCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
125         
126                 pmsgobj->rx_msg.length = msgCntlReg & 0x000F;
127         
128                 // Message id
129                 pmsgobj->rx_msg.id = (u32)msgid;
130         
131                 // Fetch message bytes
132                 if (pmsgobj->rx_msg.length > 0)
133                         readData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
134                 if (pmsgobj->rx_msg.length > 2)
135                         readData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
136                 if (pmsgobj->rx_msg.length > 4)
137                         readData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
138                 if (pmsgobj->rx_msg.length > 6)
139                         readData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
140                 
141                 for ( i=0; i < pmsgobj->rx_msg.length; i++ ) {
142                         pmsgobj->rx_msg.data[ i ] = readData.bdata[i];
143                 }
144                 DEBUGMSG("(c%dm%d)Received Message:\n",
145                       pchip->chip_idx, pmsgobj->object);
146                 DEBUGMSG(" id = %ld\n",
147                       pmsgobj->rx_msg.id);
148                 DEBUGMSG(" length = %d\n",
149                       pmsgobj->rx_msg.length);
150                 for ( i=0; i < pmsgobj->rx_msg.length; i++ )
151                         DEBUGMSG(" data[%d] = 0x%.2x\n", i, pmsgobj->rx_msg.data[i]);
152                 
153                 /* fill CAN message timestamp */
154                 can_filltimestamp(&pmsgobj->rx_msg.timestamp);
155
156                 canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->rx_msg);
157             
158             #ifdef CAN_WITH_STATISTICS
159                 // Another received packet
160                 pchip->stat.cntRxPkt++;
161
162                 // Add databytes read to statistics block
163                 pchip->stat.cntRxData += pmsgobj->rx_msg.length;
164             #endif /*CAN_WITH_STATISTICS*/
165
166                 // Check if new data arrived
167                 if (c_can_if1_busycheck(pchip)) ;
168                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
169                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
170                 if (c_can_if1_busycheck(pchip)) ;
171                 if ( !( ( bDataAvail = c_can_read_reg_w( pchip, CCIF1DMC ) ) &
172                         IFXMC_NEWDAT ) ) {
173                         break;
174                 }
175
176                 if ( bDataAvail & IFXMC_MSGLST ) {
177                         CANMSG("(c%dm%d)c-can fifo full: Message lost!\n",
178                         pchip->chip_idx, pmsgobj->object);
179                 }
180
181         }
182         // while
183 }
184
185 void c_can_irq_sync_activities(struct canchip_t *chip, struct msgobj_t *obj)
186 {
187         while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) {
188
189                 /*if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) {
190                         if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
191                                 i82527_irq_write_handler(chip, obj);
192                 }
193
194                 if(!obj->tx_slot) {
195                         if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) {
196                                 i82527_irq_update_filter(chip, obj);
197                         }
198                 }*/
199                 /* FIXME: these functionality has to be implemented to start TX */
200
201                 can_msgobj_clear_fl(obj,TX_LOCK);
202                 if(can_msgobj_test_fl(obj,TX_REQUEST))
203                         continue;
204                 if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot)
205                         continue;
206                 break;
207         }
208 }
209
210
211 ///////////////////////////////////////////////////////////////////////////////
212 // c_can_irq_handler
213 //
214
215 int c_can_irq_handler(int irq, struct canchip_t *pchip)
216 {
217         struct rtr_id *rtr_search = hardware_p->rtr_queue;
218         u16 chip_status;
219         int id0=0, id1=0;
220         u16 errcount = 0;
221         u16 irqreg = 0;
222         u32 msgid = 0;
223         u16 tempCntlReg = 0;
224
225
226         irqreg = c_can_read_reg_w( pchip, CCINTR );
227
228         if(!irqreg) {
229                 DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx spurious interrupt\n",
230                         pchip->chip_idx,
231                         (long)( pchip->/*v*/chip_base_addr/* + CCSR*/));
232                 return CANCHIP_IRQ_NONE;
233         }
234         
235         DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx irqreg=0x%.4x\n",
236              pchip->chip_idx,
237              (long)( pchip->/*v*/chip_base_addr/* + CCSR*/),
238              irqreg);
239
240
241         
242     #ifdef REGDUMP
243         c_can_registerdump(pchip);
244     #endif
245
246         while ( irqreg ){
247                 // Handle change in status register
248             
249                 if ( irqreg == INT_STAT ) {
250                         chip_status = c_can_read_reg_w( pchip, CCSR );
251                         DEBUGMSG( "(c%d)Status register: 0x%x\n",
252                                 pchip->chip_idx, chip_status );
253                 
254                         if ( chip_status & SR_EWARN ) {
255                                 // There is an abnormal # of errors
256                             #ifdef CAN_WITH_STATISTICS
257                                 pchip->stat.cntWarnings++;
258                             #endif /*CAN_WITH_STATISTICS*/
259                                 errcount = c_can_read_reg_w( pchip, CCEC);
260                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n"
261                                          "       txErr=%d, rxErr=%d\n",
262                                         pchip->chip_idx, (errcount&0x00ff), ((errcount&0x7f00)>>8));
263
264                                 /*
265                                 // this code deactivates the chip if the transmiterrorcounter grew above 127
266                                 if ((pchip->stat.cntWarnings > 100) && ((errcount&0x00ff) > 127))
267                                 {
268                                         CANMSG("(c%d)to much Errornumber warnings (>100), deactivating chip",
269                                         pchip->chip_idx);
270                                         pchip->config_irqs(pchip, 0);
271                                         pchip->enable_configuration(pchip);
272                                         pchip->clear_objects(pchip);
273                                         pchip->flags &= ~CHANNEL_CONFIGURED;
274                                         return;
275                                 }*/
276                         }
277
278                         if ( chip_status & SR_EPASS ) {
279                                 // There is an abnormal # of errors
280                             #ifdef CAN_WITH_STATISTICS
281                                 pchip->stat.cntErrPassive++;
282                             #endif /*CAN_WITH_STATISTICS*/
283                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n",
284                                 pchip->chip_idx);
285                         }
286
287                         if ( chip_status & SR_BOFF ) {
288                                 // We have a bus off condition
289                             #ifdef CAN_WITH_STATISTICS
290                                 pchip->stat.cntBusOff++;
291                             #endif /*CAN_WITH_STATISTICS*/
292                                 //pchip->fifo->tx_in_progress = 0;
293                                 //reset init bit
294                                 CANMSG("(c%d)stat: c_can_irq_handler: Bus Off\n",
295                                         pchip->chip_idx);
296                                 /*if (pchip->stat.cntBusOff > 100)
297                                 {
298                                 CANMSG("(c%d)to much busoff warnings (>100), deactivating chip",
299                                         pchip->chip_idx);
300                                 pchip->config_irqs(pchip, 0);
301                                 pchip->enable_configuration(pchip);
302                                 pchip->clear_objects(pchip);
303                                 pchip->flags &= ~CHANNEL_CONFIGURED;
304                                 return;
305                                 }
306                                 else*/
307                                 CANMSG("(c%d)try to reconnect",
308                                         pchip->chip_idx);
309                                 pchip->chipspecops->disable_configuration(pchip);
310                         }
311
312                         if (chip_status & SR_TXOK) {
313                                 DEBUGMSG("(c%d)stat: Transmitted a Message successfully\n",
314                                         pchip->chip_idx);
315                                 c_can_write_reg_w(pchip, chip_status & ~SR_TXOK, CCSR);
316                         }
317                 
318                         if (chip_status & SR_RXOK) {
319                                 DEBUGMSG("(c%d)stat: Received a Message successfully\n",
320                                         pchip->chip_idx);
321                                 c_can_write_reg_w(pchip, chip_status & ~SR_RXOK, CCSR);
322                         }
323                 
324                     #ifdef CAN_WITH_STATISTICS
325                         // Errors to statistics
326                         switch( chip_status & 0x07 )
327                         {
328                                 case SRLEC_NE: // No error
329                                         break;
330                                 case SRLEC_SE: // Stuff error
331                                         pchip->stat.cntStuffErr++;
332                                         break;
333                                 case SRLEC_FE: // Form error
334                                         pchip->stat.cntFormErr++;
335                                         break;
336                                 case SRLEC_AE: // Ack error
337                                         pchip->stat.cntAckErr++;
338                                         break;
339                                 case SRLEC_B1: // Bit 1 error
340                                         pchip->stat.cntBit1Err++;
341                                         break;
342                                 case SRLEC_B0: // Bit 0 error
343                                         pchip->stat.cntBit0Err++;
344                                         break;
345                                 case SRLEC_CR: // CRC error
346                                         pchip->stat.cntCrcErr++;
347                                         break;
348                                 case 7: // unused
349                                         break;
350                         }
351                     #endif /*CAN_WITH_STATISTICS*/
352                         //return; // continue?
353                 } else {
354                         if (irqreg >0 && irqreg <33) {
355                                 struct msgobj_t *pmsgobj;
356                                 int idxobj;
357                                 
358                                 //get id
359                                 idxobj = irqreg-1;
360                                 pmsgobj=pchip->msgobj[idxobj];
361                                 
362                                 //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n",
363                                 //            (unsigned long)pchip->vbase_addr + iIRQ,
364                                 //      (unsigned long)dev_id,
365                                 //      irqreg,
366                                 //      statreg );
367                                 //
368                                 spin_lock( &c_can_if1lock );
369                 
370                                 //Message Lost Check
371                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
372                                 c_can_write_reg_w(pchip, msgLstReadMaskCM, CCIF1CM);
373                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
374                 
375                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
376                                 tempCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
377
378                                 if (tempCntlReg & IFXMC_MSGLST) {
379                                         CANMSG("(c%dm%d)Chip lost a message\n",
380                                                 pchip->chip_idx, pmsgobj->object);
381                                     #ifdef CAN_WITH_STATISTICS
382                                         pchip->stat.cntMsgLst++;
383                                     #endif /*CAN_WITH_STATISTICS*/
384                        
385                                         //Reset Message Lost Bit
386                                         tempCntlReg = tempCntlReg & (~IFXMC_MSGLST);
387                                         c_can_write_reg_w(pchip, tempCntlReg, CCIF1DMC);
388                                         c_can_write_reg_w(pchip, msgLstWriteMaskCM, CCIF1CM);
389                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
390                                 }
391
392                                 //transfer Message Object to IF1 Buffer
393                                 if (c_can_if1_busycheck(pchip)) ;
394                                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
395                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
396
397                                 if (c_can_if1_busycheck(pchip)) ;
398                                 if (c_can_read_reg_w(pchip, CCIF1A2) & IFXARB2_DIR) {
399                                         spin_unlock( &c_can_if1lock );
400                                         c_can_irq_write_handler(pchip,idxobj);
401                                 } else {
402                                         if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) {
403                                                 id0=c_can_read_reg_w(pchip, CCIF1A1);
404                                                 id1=(c_can_read_reg_w(pchip, CCIF1A2)&0x1FFF)<<16;
405                                                 msgid= id0|id1;
406                                         } else {
407                                                 msgid=((c_can_read_reg_w(pchip, CCIF1A2)&0x1FFC)>>2)&0x7FF;
408                                         }
409                                         spin_unlock( &c_can_if1lock );
410
411                                         spin_lock(&hardware_p->rtr_lock);
412                                         while ( rtr_search != NULL )
413                                         {
414                                                 if ( rtr_search->id == msgid ) {
415                                                         break;
416                                                 }
417                                                 rtr_search = rtr_search->next;
418                                         }
419                                         spin_unlock(&hardware_p->rtr_lock);
420
421                                         spin_lock( &c_can_if1lock );
422
423                                         //transfer Message Object to IF1 Buffer
424                                         if (c_can_if1_busycheck(pchip)) ;
425                                         c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
426                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
427                         
428                                         if (c_can_if1_busycheck(pchip)) ;
429                         
430                                         if ( ( rtr_search != NULL ) && (rtr_search->id == msgid ) ) {
431                                                 c_can_irq_rtr_handler( pchip, idxobj, msgid );
432                                         } else {
433                                                 c_can_irq_read_handler( pchip, idxobj, msgid );
434                                         }
435                                         spin_unlock( &c_can_if1lock );
436                         
437                                         //}
438                                 }
439                         //else
440                         }
441                 //if
442                 }
443                 // Get irq status again
444                 irqreg = c_can_read_reg_w( pchip, CCINTR );
445         }
446         return CANCHIP_IRQ_HANDLED;
447 }
448
449 ///////////////////////////////////////////////////////////////////////////////
450 // c_can_irq_rtr_handler
451 //
452
453 void c_can_irq_rtr_handler( struct canchip_t *pchip, int idxobj, u32 msgid   )
454 {
455         short int i=0;
456         struct rtr_id *prtr_search = hardware_p->rtr_queue;
457         union c_can_data rtrData;
458         
459         spin_lock( &hardware_p->rtr_lock );
460         
461         prtr_search->rtr_message->id = msgid;
462         prtr_search->rtr_message->length =
463                 ( c_can_read_reg_w( pchip, CCIF1DMC ) & 0x000f);
464         
465         // Fetch message bytes
466         if (prtr_search->rtr_message->length > 0)
467                 rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
468         if (prtr_search->rtr_message->length > 2)
469                 rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
470         if (prtr_search->rtr_message->length > 4)
471                 rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
472         if (prtr_search->rtr_message->length > 6)
473                 rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
474         
475         for ( i=0; i<prtr_search->rtr_message->length; i++ ) {
476                 prtr_search->rtr_message->data[ i ] = rtrData.bdata[i];
477         }
478         
479         spin_unlock( &hardware_p->rtr_lock );
480         wake_up_interruptible( &prtr_search->rtr_wq );
481         return;
482 }
483