]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/c_can_irq.c
d114336c68a1cca8b7606ce5ce194b8b2c909026
[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 chip_t *pchip, int idxobj, u32 msgid  );
27
28 inline void c_can_irq_write_handler( struct chip_t *pchip, int idxobj);
29
30 void c_can_irq_rtr_handler( struct chip_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 chip_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 chip_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                 spin_unlock( &c_can_sprlock );
167
168                 // Check if new data arrived
169                 if (c_can_if1_busycheck(pchip)) ;
170                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
171                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
172                 if (c_can_if1_busycheck(pchip)) ;
173                 if ( !( ( bDataAvail = c_can_read_reg_w( pchip, CCIF1DMC ) ) &
174                         IFXMC_NEWDAT ) ) {
175                         break;
176                 }
177
178                 if ( bDataAvail & IFXMC_MSGLST ) {
179                         CANMSG("(c%dm%d)c-can fifo full: Message lost!\n",
180                         pchip->chip_idx, pmsgobj->object);
181                 }
182
183         }
184         // while
185 }
186
187 void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj)
188 {
189         while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) {
190
191                 /*if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) {
192                         if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
193                                 i82527_irq_write_handler(chip, obj);
194                 }
195
196                 if(!obj->tx_slot) {
197                         if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) {
198                                 i82527_irq_update_filter(chip, obj);
199                         }
200                 }*/
201                 /* FIXME: these functionality has to be implemented to start TX */
202
203                 can_msgobj_clear_fl(obj,TX_LOCK);
204                 if(can_msgobj_test_fl(obj,TX_REQUEST))
205                         continue;
206                 if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot)
207                         continue;
208                 break;
209         }
210 }
211
212
213 ///////////////////////////////////////////////////////////////////////////////
214 // c_can_irq_handler
215 //
216
217 can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
218 {
219         struct rtr_id *rtr_search = hardware_p->rtr_queue;
220         struct chip_t *pchip = (struct chip_t *)dev_id;
221         u16 chip_status;
222         int id0=0, id1=0;
223         u16 errcount = 0;
224         u16 irqreg = 0;
225         u32 msgid = 0;
226         u16 tempCntlReg = 0;
227         //#ifdef CAN_DEBUG
228         // u32 intCntrVAddr = 0;
229         //#endif
230         //unsigned short flags = 0;
231
232         //if (pchip->ntype != CAN_CHIPTYPE_C_CAN)       {
233         //      DEBUGMSG("\n(c%d)IRQ not for c_can_irq_handler(...)\n", pchip->chip_idx);
234         //      return;
235         //}
236
237         irqreg = c_can_read_reg_w( pchip, CCINTR );
238
239         if(!irqreg) {
240                 DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx spurious interrupt\n",
241                         pchip->chip_idx,
242                         (long)( pchip->/*v*/chip_base_addr/* + CCSR*/));
243                 return CAN_IRQ_NONE;
244         }
245         
246         DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx irqreg=0x%.4x\n",
247              pchip->chip_idx,
248              (long)( pchip->/*v*/chip_base_addr/* + CCSR*/),
249              irqreg);
250
251
252         
253     #ifdef REGDUMP
254         c_can_registerdump(pchip);
255     #endif
256
257 /*
258 #ifdef CAN_DEBUG
259         if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))) {
260                 DEBUGMSG("Failed to map Interrupt Controller IO-memory\n");
261         }
262         else {
263
264    DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
265                 (unsigned long)0X80024000,
266               (unsigned long)0X800240CC,
267               (unsigned long)intCntrVAddr);
268         }
269
270         DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
271                                 (long)readl(intCntrVAddr + 4));
272         DEBUGMSG("Current Interrupt ID: %d\n",
273                                 (int)(readl(intCntrVAddr + 0x90) & 0xF));
274         iounmap( (void*)intCntrVAddr);
275         DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
276               (unsigned long)intCntrVAddr);
277 #endif
278 */
279         while ( irqreg ){
280                 // Handle change in status register
281             
282                 if ( irqreg == INT_STAT ) {
283                         chip_status = c_can_read_reg_w( pchip, CCSR );
284                         DEBUGMSG( "(c%d)Status register: 0x%x\n",
285                                 pchip->chip_idx, chip_status );
286                 
287                         if ( chip_status & SR_EWARN ) {
288                                 // There is an abnormal # of errors
289                             #ifdef CAN_WITH_STATISTICS
290                                 pchip->stat.cntWarnings++;
291                             #endif /*CAN_WITH_STATISTICS*/
292                                 errcount = c_can_read_reg_w( pchip, CCEC);
293                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n"
294                                          "       txErr=%d, rxErr=%d\n",
295                                         pchip->chip_idx, (errcount&0x00ff), ((errcount&0x7f00)>>8));
296
297                                 /*
298                                 // this code deactivates the chip if the transmiterrorcounter grew above 127
299                                 if ((pchip->stat.cntWarnings > 100) && ((errcount&0x00ff) > 127))
300                                 {
301                                         CANMSG("(c%d)to much Errornumber warnings (>100), deactivating chip",
302                                         pchip->chip_idx);
303                                         pchip->config_irqs(pchip, 0);
304                                         pchip->enable_configuration(pchip);
305                                         pchip->clear_objects(pchip);
306                                         pchip->flags &= ~CHANNEL_CONFIGURED;
307                                         return;
308                                 }*/
309                         }
310
311                         if ( chip_status & SR_EPASS ) {
312                                 // There is an abnormal # of errors
313                             #ifdef CAN_WITH_STATISTICS
314                                 pchip->stat.cntErrPassive++;
315                             #endif /*CAN_WITH_STATISTICS*/
316                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n",
317                                 pchip->chip_idx);
318                         }
319
320                         if ( chip_status & SR_BOFF ) {
321                                 // We have a bus off condition
322                             #ifdef CAN_WITH_STATISTICS
323                                 pchip->stat.cntBusOff++;
324                             #endif /*CAN_WITH_STATISTICS*/
325                                 //pchip->fifo->tx_in_progress = 0;
326                                 //reset init bit
327                                 CANMSG("(c%d)stat: c_can_irq_handler: Bus Off\n",
328                                         pchip->chip_idx);
329                                 /*if (pchip->stat.cntBusOff > 100)
330                                 {
331                                 CANMSG("(c%d)to much busoff warnings (>100), deactivating chip",
332                                         pchip->chip_idx);
333                                 pchip->config_irqs(pchip, 0);
334                                 pchip->enable_configuration(pchip);
335                                 pchip->clear_objects(pchip);
336                                 pchip->flags &= ~CHANNEL_CONFIGURED;
337                                 return;
338                                 }
339                                 else*/
340                                 CANMSG("(c%d)try to reconnect",
341                                         pchip->chip_idx);
342                                 pchip->chipspecops->disable_configuration(pchip);
343                         }
344
345                         if (chip_status & SR_TXOK) {
346                                 DEBUGMSG("(c%d)stat: Transmitted a Message successfully\n",
347                                         pchip->chip_idx);
348                                 c_can_write_reg_w(pchip, chip_status & ~SR_TXOK, CCSR);
349                         }
350                 
351                         if (chip_status & SR_RXOK) {
352                                 DEBUGMSG("(c%d)stat: Received a Message successfully\n",
353                                         pchip->chip_idx);
354                                 c_can_write_reg_w(pchip, chip_status & ~SR_RXOK, CCSR);
355                         }
356                 
357                     #ifdef CAN_WITH_STATISTICS
358                         // Errors to statistics
359                         switch( chip_status & 0x07 )
360                         {
361                                 case SRLEC_NE: // No error
362                                         break;
363                                 case SRLEC_SE: // Stuff error
364                                         pchip->stat.cntStuffErr++;
365                                         break;
366                                 case SRLEC_FE: // Form error
367                                         pchip->stat.cntFormErr++;
368                                         break;
369                                 case SRLEC_AE: // Ack error
370                                         pchip->stat.cntAckErr++;
371                                         break;
372                                 case SRLEC_B1: // Bit 1 error
373                                         pchip->stat.cntBit1Err++;
374                                         break;
375                                 case SRLEC_B0: // Bit 0 error
376                                         pchip->stat.cntBit0Err++;
377                                         break;
378                                 case SRLEC_CR: // CRC error
379                                         pchip->stat.cntCrcErr++;
380                                         break;
381                                 case 7: // unused
382                                         break;
383                         }
384                     #endif /*CAN_WITH_STATISTICS*/
385                         //return; // continue?
386                 } else {
387                         if (irqreg >0 && irqreg <33) {
388                                 struct msgobj_t *pmsgobj;
389                                 int idxobj;
390                                 
391                                 //get id
392                                 idxobj = irqreg-1;
393                                 pmsgobj=pchip->msgobj[idxobj];
394                                 
395                                 //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n",
396                                 //            (unsigned long)pchip->vbase_addr + iIRQ,
397                                 //      (unsigned long)dev_id,
398                                 //      irqreg,
399                                 //      statreg );
400                                 //
401                                 spin_lock( &c_can_if1lock );
402                 
403                                 //Message Lost Check
404                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
405                                 c_can_write_reg_w(pchip, msgLstReadMaskCM, CCIF1CM);
406                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
407                 
408                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
409                                 tempCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
410
411                                 if (tempCntlReg & IFXMC_MSGLST) {
412                                         CANMSG("(c%dm%d)Chip lost a message\n",
413                                                 pchip->chip_idx, pmsgobj->object);
414                                     #ifdef CAN_WITH_STATISTICS
415                                         pchip->stat.cntMsgLst++;
416                                     #endif /*CAN_WITH_STATISTICS*/
417                        
418                                         //Reset Message Lost Bit
419                                         tempCntlReg = tempCntlReg & (~IFXMC_MSGLST);
420                                         c_can_write_reg_w(pchip, tempCntlReg, CCIF1DMC);
421                                         c_can_write_reg_w(pchip, msgLstWriteMaskCM, CCIF1CM);
422                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
423                                 }
424
425                                 //transfer Message Object to IF1 Buffer
426                                 if (c_can_if1_busycheck(pchip)) ;
427                                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
428                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
429
430                                 if (c_can_if1_busycheck(pchip)) ;
431                                 if (c_can_read_reg_w(pchip, CCIF1A2) & IFXARB2_DIR) {
432                                         spin_unlock( &c_can_if1lock );
433                                         c_can_irq_write_handler(pchip,idxobj);
434                                 } else {
435                                         if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) {
436                                                 id0=c_can_read_reg_w(pchip, CCIF1A1);
437                                                 id1=(c_can_read_reg_w(pchip, CCIF1A2)&0x1FFF)<<16;
438                                                 msgid= id0|id1;
439                                         } else {
440                                                 msgid=((c_can_read_reg_w(pchip, CCIF1A2)&0x1FFC)>>2)&0x7FF;
441                                         }
442                                         spin_unlock( &c_can_if1lock );
443
444                                         spin_lock(&hardware_p->rtr_lock);
445                                         while ( rtr_search != NULL )
446                                         {
447                                                 if ( rtr_search->id == msgid ) {
448                                                         break;
449                                                 }
450                                                 rtr_search = rtr_search->next;
451                                         }
452                                         spin_unlock(&hardware_p->rtr_lock);
453
454                                         spin_lock( &c_can_if1lock );
455
456                                         //transfer Message Object to IF1 Buffer
457                                         if (c_can_if1_busycheck(pchip)) ;
458                                         c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
459                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
460                         
461                                         if (c_can_if1_busycheck(pchip)) ;
462                         
463                                         if ( ( rtr_search != NULL ) && (rtr_search->id == msgid ) ) {
464                                                 c_can_irq_rtr_handler( pchip, idxobj, msgid );
465                                         } else {
466                                                 c_can_irq_read_handler( pchip, idxobj, msgid );
467                                         }
468                                         spin_unlock( &c_can_if1lock );
469                         
470                                         //}
471                                 }
472                         //else
473                         }
474                 //if
475                 }
476                 // Get irq status again
477                 irqreg = c_can_read_reg_w( pchip, CCINTR );
478         }
479         return CAN_IRQ_HANDLED;
480 }
481
482 ///////////////////////////////////////////////////////////////////////////////
483 // c_can_irq_rtr_handler
484 //
485
486 void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid   )
487 {
488         short int i=0;
489         struct rtr_id *prtr_search = hardware_p->rtr_queue;
490         union c_can_data rtrData;
491         
492         spin_lock( &hardware_p->rtr_lock );
493         
494         prtr_search->rtr_message->id = msgid;
495         prtr_search->rtr_message->length =
496                 ( c_can_read_reg_w( pchip, CCIF1DMC ) & 0x000f);
497         
498         // Fetch message bytes
499         if (prtr_search->rtr_message->length > 0)
500                 rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
501         if (prtr_search->rtr_message->length > 2)
502                 rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
503         if (prtr_search->rtr_message->length > 4)
504                 rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
505         if (prtr_search->rtr_message->length > 6)
506                 rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
507         
508         for ( i=0; i<prtr_search->rtr_message->length; i++ ) {
509                 prtr_search->rtr_message->data[ i ] = rtrData.bdata[i];
510         }
511         
512         spin_unlock( &hardware_p->rtr_lock );
513         wake_up_interruptible( &prtr_search->rtr_wq );
514         return;
515 }
516