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