The first phase of integration of Hynix HMS30c7202 C_CAN support
[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.2  9 Jul 2003
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                         pmsgobj->tx_slot->msg.flags |= MSG_LOCAL;
56                         canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->tx_slot->msg);
57                 }
58                 /* Free transmitted slot */
59                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
60                 pmsgobj->tx_slot=NULL;
61         }
62    
63         // Get ready to send next message
64         spin_lock( &c_can_spwlock );
65
66         cmd=canque_test_outslot(pmsgobj->qends, &pmsgobj->tx_qedge, &pmsgobj->tx_slot);
67         if(cmd<0){
68                 DEBUGMSG("(c%dm%d)Nothin to write\n",
69                         pchip->chip_idx, pmsgobj->object);
70                 spin_unlock( &c_can_spwlock );
71                 return;
72         }
73
74         // Send the message
75         if ( pchip->chipspecops->send_msg( pchip, pmsgobj,&pmsgobj->tx_slot->msg) ) {
76                 pmsgobj->ret = -1;
77                 canque_notify_inends(pmsgobj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
78                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
79                 pmsgobj->tx_slot=NULL;
80                 spin_unlock( &c_can_spwlock );
81                 DEBUGMSG("(c%dm%d)c_can_irq_handler: Unable to send message\n",
82                         pchip->chip_idx, pmsgobj->object );
83                 return;
84         } else {
85                 // Another message sent
86             #ifdef CAN_WITH_STATISTICS
87                 pchip->stat.cntTxPkt++;
88                 pchip->stat.cntTxData += pmsgobj->tx_slot->length;
89             #endif /*CAN_WITH_STATISTICS*/
90         }
91         spin_unlock( &c_can_spwlock );
92
93         // Wake up any waiting writer
94         return;
95 }
96
97 ///////////////////////////////////////////////////////////////////////////////
98 // c_can_irq_read_handler
99 //
100 // Message received form the line. Write it in the input fifo->
101 //
102
103 inline void c_can_irq_read_handler( struct chip_t *pchip,
104                                     int idxobj, u32 msgid  )
105 {
106         int i=0;
107         u16 bDataAvail=1 ;
108         u16 msgCntlReg = 0;
109         union c_can_data readData;
110         struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
111                 
112         DEBUGMSG("(c%dm%d)calling c_can_irq_read_handler(...)\n",
113                 pchip->chip_idx, pmsgobj->object);
114         
115         while ( bDataAvail ) {
116              
117             #ifdef CAN_WITH_STATISTICS
118                 pchip->stat.cntRxFifoOvr++;
119             #endif /*CAN_WITH_STATISTICS*/
120                 // Message length
121                 msgCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
122         
123                 pmsgobj->rx_msg.length = msgCntlReg & 0x000F;
124         
125                 // Message id
126                 pmsgobj->rx_msg.id = (u32)msgid;
127         
128                 // Fetch message bytes
129                 if (pmsgobj->rx_msg.length > 0)
130                         readData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
131                 if (pmsgobj->rx_msg.length > 2)
132                         readData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
133                 if (pmsgobj->rx_msg.length > 4)
134                         readData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
135                 if (pmsgobj->rx_msg.length > 6)
136                         readData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
137                 
138                 for ( i=0; i < pmsgobj->rx_msg.length; i++ ) {
139                         pmsgobj->rx_msg.data[ i ] = readData.bdata[i];
140                 }
141                 DEBUGMSG("(c%dm%d)Received Message:\n",
142                       pchip->chip_idx, pmsgobj->object);
143                 DEBUGMSG(" id = %d\n",
144                       pmsgobj->rx_msg.id);
145                 DEBUGMSG(" length = %d\n",
146                       pmsgobj->rx_msg.length);
147                 for ( i=0; i < pmsgobj->rx_msg.length; i++ )
148                         DEBUGMSG(" data[%d] = 0x%.2x\n", i, pmsgobj->rx_msg.data[i]);
149                 
150                 canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->rx_msg);
151             
152             #ifdef CAN_WITH_STATISTICS
153                 // Another received packet
154                 pchip->stat.cntRxPkt++;
155
156                 // Add databytes read to statistics block
157                 pchip->stat.cntRxData += pmsgobj->rx_msg.length;
158             #endif /*CAN_WITH_STATISTICS*/
159
160                 spin_unlock( &c_can_sprlock );
161
162                 // Check if new data arrived
163                 if (c_can_if1_busycheck(pchip)) ;
164                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
165                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
166                 if (c_can_if1_busycheck(pchip)) ;
167                 if ( !( ( bDataAvail = c_can_read_reg_w( pchip, CCIF1DMC ) ) &
168                         IFXMC_NEWDAT ) ) {
169                         break;
170                 }
171
172                 if ( bDataAvail & IFXMC_MSGLST ) {
173                         CANMSG("(c%dm%d)c-can fifo full: Message lost!\n",
174                         pchip->chip_idx, pmsgobj->object);
175                 }
176
177         }
178         // while
179 }
180
181 void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj)
182 {
183         while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) {
184
185                 /*if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) {
186                         if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
187                                 i82527_irq_write_handler(chip, obj);
188                 }
189
190                 if(!obj->tx_slot) {
191                         if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) {
192                                 i82527_irq_update_filter(chip, obj);
193                         }
194                 }*/
195                 /* FIXME: these functionality has to be implemented to start TX */
196
197                 can_msgobj_clear_fl(obj,TX_LOCK);
198                 if(can_msgobj_test_fl(obj,TX_REQUEST))
199                         continue;
200                 if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot)
201                         continue;
202                 break;
203         }
204 }
205
206
207 ///////////////////////////////////////////////////////////////////////////////
208 // c_can_irq_handler
209 //
210
211 can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
212 {
213         struct rtr_id *rtr_search = hardware_p->rtr_queue;
214         struct chip_t *pchip = (struct chip_t *)dev_id;
215         u16 chip_status;
216         int id0=0, id1=0;
217         u16 errcount = 0;
218         u16 irqreg = 0;
219         u32 msgid = 0;
220         u16 tempCntlReg = 0;
221         //#ifdef CAN_DEBUG
222         // u32 intCntrVAddr = 0;
223         //#endif
224         //unsigned short flags = 0;
225
226         //if (pchip->ntype != CAN_CHIPTYPE_C_CAN)       {
227         //      DEBUGMSG("\n(c%d)IRQ not for c_can_irq_handler(...)\n", pchip->chip_idx);
228         //      return;
229         //}
230
231         irqreg = c_can_read_reg_w( pchip, CCINTR );
232
233         if(!irqreg) {
234                 DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx spurious interrupt\n",
235                         pchip->chip_idx,
236                         (long)( pchip->/*v*/base_addr/* + CCSR*/));
237                 return CAN_IRQ_NONE;
238         }
239         
240         DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx irqreg=0x%.4x\n",
241              pchip->chip_idx,
242              (long)( pchip->/*v*/base_addr/* + CCSR*/),
243              irqreg);
244
245
246         
247     #ifdef REGDUMP
248         c_can_registerdump(pchip);
249     #endif
250
251 /*
252 #ifdef CAN_DEBUG
253         if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))) {
254                 DEBUGMSG("Failed to map Interrupt Controller IO-memory\n");
255         }
256         else {
257
258    DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
259                 (unsigned long)0X80024000,
260               (unsigned long)0X800240CC,
261               (unsigned long)intCntrVAddr);
262         }
263
264         DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
265                                 (long)readl(intCntrVAddr + 4));
266         DEBUGMSG("Current Interrupt ID: %d\n",
267                                 (int)(readl(intCntrVAddr + 0x90) & 0xF));
268         iounmap( (void*)intCntrVAddr);
269         DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
270               (unsigned long)intCntrVAddr);
271 #endif
272 */
273         while ( irqreg ){
274                 // Handle change in status register
275             
276                 if ( irqreg == INT_STAT ) {
277                         chip_status = c_can_read_reg_w( pchip, CCSR );
278                         DEBUGMSG( "(c%d)Status register: 0x%x\n",
279                                 pchip->chip_idx, chip_status );
280                 
281                         if ( chip_status & SR_EWARN ) {
282                                 // There is an abnormal # of errors
283                             #ifdef CAN_WITH_STATISTICS
284                                 pchip->stat.cntWarnings++;
285                             #endif /*CAN_WITH_STATISTICS*/
286                                 errcount = c_can_read_reg_w( pchip, CCEC);
287                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n"
288                                          "       txErr=%d, rxErr=%d\n",
289                                         pchip->chip_idx, (errcount&0x00ff), ((errcount&0x7f00)>>8));
290
291                                 /*
292                                 // this code deactivates the chip if the transmiterrorcounter grew above 127
293                                 if ((pchip->stat.cntWarnings > 100) && ((errcount&0x00ff) > 127))
294                                 {
295                                         CANMSG("(c%d)to much Errornumber warnings (>100), deactivating chip",
296                                         pchip->chip_idx);
297                                         pchip->config_irqs(pchip, 0);
298                                         pchip->enable_configuration(pchip);
299                                         pchip->clear_objects(pchip);
300                                         pchip->flags &= ~CHANNEL_CONFIGURED;
301                                         return;
302                                 }*/
303                         }
304
305                         if ( chip_status & SR_EPASS ) {
306                                 // There is an abnormal # of errors
307                             #ifdef CAN_WITH_STATISTICS
308                                 pchip->stat.cntErrPassive++;
309                             #endif /*CAN_WITH_STATISTICS*/
310                                 DEBUGMSG("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n",
311                                 pchip->chip_idx);
312                         }
313
314                         if ( chip_status & SR_BOFF ) {
315                                 // We have a bus off condition
316                             #ifdef CAN_WITH_STATISTICS
317                                 pchip->stat.cntBusOff++;
318                             #endif /*CAN_WITH_STATISTICS*/
319                                 //pchip->fifo->tx_in_progress = 0;
320                                 //reset init bit
321                                 CANMSG("(c%d)stat: c_can_irq_handler: Bus Off\n",
322                                         pchip->chip_idx);
323                                 /*if (pchip->stat.cntBusOff > 100)
324                                 {
325                                 CANMSG("(c%d)to much busoff warnings (>100), deactivating chip",
326                                         pchip->chip_idx);
327                                 pchip->config_irqs(pchip, 0);
328                                 pchip->enable_configuration(pchip);
329                                 pchip->clear_objects(pchip);
330                                 pchip->flags &= ~CHANNEL_CONFIGURED;
331                                 return;
332                                 }
333                                 else*/
334                                 CANMSG("(c%d)try to reconnect",
335                                         pchip->chip_idx);
336                                 pchip->chipspecops->disable_configuration(pchip);
337                         }
338
339                         if (chip_status & SR_TXOK) {
340                                 DEBUGMSG("(c%d)stat: Transmitted a Message successfully\n",
341                                         pchip->chip_idx);
342                                 c_can_write_reg_w(pchip, chip_status & ~SR_TXOK, CCSR);
343                         }
344                 
345                         if (chip_status & SR_RXOK) {
346                                 DEBUGMSG("(c%d)stat: Received a Message successfully\n",
347                                         pchip->chip_idx);
348                                 c_can_write_reg_w(pchip, chip_status & ~SR_RXOK, CCSR);
349                         }
350                 
351                     #ifdef CAN_WITH_STATISTICS
352                         // Errors to statistics
353                         switch( chip_status & 0x07 )
354                         {
355                                 case SRLEC_NE: // No error
356                                         break;
357                                 case SRLEC_SE: // Stuff error
358                                         pchip->stat.cntStuffErr++;
359                                         break;
360                                 case SRLEC_FE: // Form error
361                                         pchip->stat.cntFormErr++;
362                                         break;
363                                 case SRLEC_AE: // Ack error
364                                         pchip->stat.cntAckErr++;
365                                         break;
366                                 case SRLEC_B1: // Bit 1 error
367                                         pchip->stat.cntBit1Err++;
368                                         break;
369                                 case SRLEC_B0: // Bit 0 error
370                                         pchip->stat.cntBit0Err++;
371                                         break;
372                                 case SRLEC_CR: // CRC error
373                                         pchip->stat.cntCrcErr++;
374                                         break;
375                                 case 7: // unused
376                                         break;
377                         }
378                     #endif /*CAN_WITH_STATISTICS*/
379                         //return; // continue?
380                 } else {
381                         if (irqreg >0 && irqreg <33) {
382                                 struct msgobj_t *pmsgobj;
383                                 int idxobj;
384                                 
385                                 //get id
386                                 idxobj = irqreg-1;
387                                 pmsgobj=pchip->msgobj[idxobj];
388                                 
389                                 //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n",
390                                 //            (unsigned long)pchip->vbase_addr + iIRQ,
391                                 //      (unsigned long)dev_id,
392                                 //      irqreg,
393                                 //      statreg );
394                                 //
395                                 spin_lock( &c_can_if1lock );
396                 
397                                 //Message Lost Check
398                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
399                                 c_can_write_reg_w(pchip, msgLstReadMaskCM, CCIF1CM);
400                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
401                 
402                                 if (c_can_if1_busycheck(pchip)) ; /*??????????*/
403                                 tempCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
404
405                                 if (tempCntlReg & IFXMC_MSGLST) {
406                                         CANMSG("(c%dm%d)Chip lost a message\n",
407                                                 pchip->chip_idx, pmsgobj->object);
408                                     #ifdef CAN_WITH_STATISTICS
409                                         pchip->stat.cntMsgLst++;
410                                     #endif /*CAN_WITH_STATISTICS*/
411                        
412                                         //Reset Message Lost Bit
413                                         tempCntlReg = tempCntlReg & (~IFXMC_MSGLST);
414                                         c_can_write_reg_w(pchip, tempCntlReg, CCIF1DMC);
415                                         c_can_write_reg_w(pchip, msgLstWriteMaskCM, CCIF1CM);
416                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
417                                 }
418
419                                 //transfer Message Object to IF1 Buffer
420                                 if (c_can_if1_busycheck(pchip)) ;
421                                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
422                                 c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
423
424                                 if (c_can_if1_busycheck(pchip)) ;
425                                 if (c_can_read_reg_w(pchip, CCIF1A2) & IFXARB2_DIR) {
426                                         spin_unlock( &c_can_if1lock );
427                                         c_can_irq_write_handler(pchip,idxobj);
428                                 } else {
429                                         if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) {
430                                                 id0=c_can_read_reg_w(pchip, CCIF1A1);
431                                                 id1=(c_can_read_reg_w(pchip, CCIF1A2)&0x1FFF)<<16;
432                                                 msgid= id0|id1;
433                                         } else {
434                                                 msgid=((c_can_read_reg_w(pchip, CCIF1A2)&0x1FFC)>>2)&0x7FF;
435                                         }
436                                         spin_unlock( &c_can_if1lock );
437
438                                         spin_lock(&hardware_p->rtr_lock);
439                                         while ( rtr_search != NULL )
440                                         {
441                                                 if ( rtr_search->id == msgid ) {
442                                                         break;
443                                                 }
444                                                 rtr_search = rtr_search->next;
445                                         }
446                                         spin_unlock(&hardware_p->rtr_lock);
447
448                                         spin_lock( &c_can_if1lock );
449
450                                         //transfer Message Object to IF1 Buffer
451                                         if (c_can_if1_busycheck(pchip)) ;
452                                         c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
453                                         c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
454                         
455                                         if (c_can_if1_busycheck(pchip)) ;
456                         
457                                         if ( ( rtr_search != NULL ) && (rtr_search->id == msgid ) ) {
458                                                 c_can_irq_rtr_handler( pchip, idxobj, msgid );
459                                         } else {
460                                                 c_can_irq_read_handler( pchip, idxobj, msgid );
461                                         }
462                                         spin_unlock( &c_can_if1lock );
463                         
464                                         //}
465                                 }
466                         //else
467                         }
468                 //if
469                 }
470                 // Get irq status again
471                 irqreg = c_can_read_reg_w( pchip, CCINTR );
472         }
473         return CAN_IRQ_HANDLED;
474 }
475
476 ///////////////////////////////////////////////////////////////////////////////
477 // c_can_irq_rtr_handler
478 //
479
480 void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid   )
481 {
482         short int i=0;
483         struct rtr_id *prtr_search = hardware_p->rtr_queue;
484         union c_can_data rtrData;
485         
486         spin_lock( &hardware_p->rtr_lock );
487         
488         prtr_search->rtr_message->id = msgid;
489         prtr_search->rtr_message->length =
490                 ( c_can_read_reg_w( pchip, CCIF1DMC ) & 0x000f);
491         
492         // Fetch message bytes
493         if (prtr_search->rtr_message->length > 0)
494                 rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
495         if (prtr_search->rtr_message->length > 2)
496                 rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
497         if (prtr_search->rtr_message->length > 4)
498                 rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
499         if (prtr_search->rtr_message->length > 6)
500                 rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
501         
502         for ( i=0; i<prtr_search->rtr_message->length; i++ ) {
503                 prtr_search->rtr_message->data[ i ] = rtrData.bdata[i];
504         }
505         
506         spin_unlock( &hardware_p->rtr_lock );
507         wake_up_interruptible( &prtr_search->rtr_wq );
508         return;
509 }
510