]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/c_can_irq.c
b689032ed702e275e37c7531a39a6537cc7c02bb
[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         unsigned short wdata[4];
19         unsigned char bdata[8];
20 };
21
22 // prototypes
23 inline void c_can_irq_read_handler(struct canchip_t *pchip, int idxobj,
24                                    u32 msgid);
25
26 inline void c_can_irq_write_handler(struct canchip_t *pchip, int idxobj);
27
28 void c_can_irq_rtr_handler(struct canchip_t *pchip, int idxobj, u32 msgid);
29
30 u16 readMaskCM = IFXCM_ARB | IFXCM_CNTRL | IFXCM_CLRINTPND
31     | IFXCM_TRND | IFXCM_DA | IFXCM_DB;
32
33 u16 msgLstReadMaskCM = IFXCM_CNTRL;
34 u16 msgLstWriteMaskCM = IFXCM_CNTRL | IFXCM_WRRD;
35
36 ///////////////////////////////////////////////////////////////////////////////
37 // c_can_irq_write_handler
38 //
39 // Send a message from the output fifo ( if any ).
40 //
41
42 inline void c_can_irq_write_handler(struct canchip_t *pchip, int idxobj)
43 {
44         int cmd;
45         struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
46
47         DEBUGMSG("(c%dm%d)calling c_can_irq_write_handler(...)\n",
48                  pchip->chip_idx, pmsgobj->object);
49
50         if (pmsgobj->tx_slot) {
51                 /* Do local transmitted message distribution if enabled */
52                 if (processlocal) {
53                         /* fill CAN message timestamp */
54                         can_filltimestamp(&pmsgobj->tx_slot->msg.timestamp);
55
56                         pmsgobj->tx_slot->msg.flags |= MSG_LOCAL;
57                         canque_filter_msg2edges(pmsgobj->qends,
58                                                 &pmsgobj->tx_slot->msg);
59                 }
60                 /* Free transmitted slot */
61                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge,
62                                     pmsgobj->tx_slot);
63                 pmsgobj->tx_slot = NULL;
64         }
65         // Get ready to send next message
66         spin_lock(&c_can_spwlock);
67
68         cmd =
69             canque_test_outslot(pmsgobj->qends, &pmsgobj->tx_qedge,
70                                 &pmsgobj->tx_slot);
71         if (cmd < 0) {
72                 DEBUGMSG("(c%dm%d)Nothin to write\n",
73                          pchip->chip_idx, pmsgobj->object);
74                 spin_unlock(&c_can_spwlock);
75                 return;
76         }
77         // Send the message
78         if (pchip->chipspecops->
79             send_msg(pchip, pmsgobj, &pmsgobj->tx_slot->msg)) {
80                 pmsgobj->ret = -1;
81                 canque_notify_inends(pmsgobj->tx_qedge,
82                                      CANQUEUE_NOTIFY_ERRTX_SEND);
83                 canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge,
84                                     pmsgobj->tx_slot);
85                 pmsgobj->tx_slot = NULL;
86                 spin_unlock(&c_can_spwlock);
87                 DEBUGMSG("(c%dm%d)c_can_irq_handler: Unable to send message\n",
88                          pchip->chip_idx, pmsgobj->object);
89                 return;
90         } else {
91                 // Another message sent
92 #ifdef CAN_WITH_STATISTICS
93                 pchip->stat.cntTxPkt++;
94                 pchip->stat.cntTxData += pmsgobj->tx_slot->length;
95 #endif /*CAN_WITH_STATISTICS */
96         }
97         spin_unlock(&c_can_spwlock);
98
99         // Wake up any waiting writer
100         return;
101 }
102
103 ///////////////////////////////////////////////////////////////////////////////
104 // c_can_irq_read_handler
105 //
106 // Message received form the line. Write it in the input fifo->
107 //
108
109 inline void c_can_irq_read_handler(struct canchip_t *pchip,
110                                    int idxobj, u32 msgid)
111 {
112         int i = 0;
113         u16 bDataAvail = 1;
114         u16 msgCntlReg = 0;
115         union c_can_data readData;
116         struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
117
118         DEBUGMSG("(c%dm%d)calling c_can_irq_read_handler(...)\n",
119                  pchip->chip_idx, pmsgobj->object);
120
121         while (bDataAvail) {
122
123 #ifdef CAN_WITH_STATISTICS
124                 pchip->stat.cntRxFifoOvr++;
125 #endif /*CAN_WITH_STATISTICS */
126                 // Message length
127                 msgCntlReg = c_can_read_reg_w(pchip, CCIF1DMC);
128
129                 pmsgobj->rx_msg.length = msgCntlReg & 0x000F;
130
131                 // Message id
132                 pmsgobj->rx_msg.id = (u32) msgid;
133
134                 // Fetch message bytes
135                 if (pmsgobj->rx_msg.length > 0)
136                         readData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
137                 if (pmsgobj->rx_msg.length > 2)
138                         readData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
139                 if (pmsgobj->rx_msg.length > 4)
140                         readData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
141                 if (pmsgobj->rx_msg.length > 6)
142                         readData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
143
144                 for (i = 0; i < pmsgobj->rx_msg.length; i++) {
145                         pmsgobj->rx_msg.data[i] = readData.bdata[i];
146                 }
147                 DEBUGMSG("(c%dm%d)Received Message:\n",
148                          pchip->chip_idx, pmsgobj->object);
149                 DEBUGMSG(" id = %ld\n", pmsgobj->rx_msg.id);
150                 DEBUGMSG(" length = %d\n", pmsgobj->rx_msg.length);
151                 for (i = 0; i < pmsgobj->rx_msg.length; i++)
152                         DEBUGMSG(" data[%d] = 0x%.2x\n", i,
153                                  pmsgobj->rx_msg.data[i]);
154
155                 /* fill CAN message timestamp */
156                 can_filltimestamp(&pmsgobj->rx_msg.timestamp);
157
158                 canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->rx_msg);
159
160 #ifdef CAN_WITH_STATISTICS
161                 // Another received packet
162                 pchip->stat.cntRxPkt++;
163
164                 // Add databytes read to statistics block
165                 pchip->stat.cntRxData += pmsgobj->rx_msg.length;
166 #endif /*CAN_WITH_STATISTICS */
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 // c_can_irq_handler
214 //
215
216 int c_can_irq_handler(int irq, struct canchip_t *pchip)
217 {
218         struct rtr_id *rtr_search = hardware_p->rtr_queue;
219         u16 chip_status;
220         int id0 = 0, id1 = 0;
221         u16 errcount = 0;
222         u16 irqreg = 0;
223         u32 msgid = 0;
224         u16 tempCntlReg = 0;
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 #ifdef REGDUMP
241         c_can_registerdump(pchip);
242 #endif
243
244         while (irqreg) {
245                 // Handle change in status register
246
247                 if (irqreg == INT_STAT) {
248                         chip_status = c_can_read_reg_w(pchip, CCSR);
249                         DEBUGMSG("(c%d)Status register: 0x%x\n",
250                                  pchip->chip_idx, chip_status);
251
252                         if (chip_status & SR_EWARN) {
253                                 // There is an abnormal # of errors
254 #ifdef CAN_WITH_STATISTICS
255                                 pchip->stat.cntWarnings++;
256 #endif /*CAN_WITH_STATISTICS */
257                                 errcount = c_can_read_reg_w(pchip, CCEC);
258                                 DEBUGMSG
259                                     ("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n"
260                                      "       txErr=%d, rxErr=%d\n",
261                                      pchip->chip_idx, (errcount & 0x00ff),
262                                      ((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
284                                     ("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n",
285                                      pchip->chip_idx);
286                         }
287
288                         if (chip_status & SR_BOFF) {
289                                 // We have a bus off condition
290 #ifdef CAN_WITH_STATISTICS
291                                 pchip->stat.cntBusOff++;
292 #endif /*CAN_WITH_STATISTICS */
293                                 //pchip->fifo->tx_in_progress = 0;
294                                 //reset init bit
295                                 CANMSG
296                                     ("(c%d)stat: c_can_irq_handler: Bus Off\n",
297                                      pchip->chip_idx);
298                                 /*if (pchip->stat.cntBusOff > 100)
299                                    {
300                                    CANMSG("(c%d)to much busoff 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                                    else */
309                                 CANMSG("(c%d)try to reconnect",
310                                        pchip->chip_idx);
311                                 pchip->chipspecops->
312                                     disable_configuration(pchip);
313                         }
314
315                         if (chip_status & SR_TXOK) {
316                                 DEBUGMSG
317                                     ("(c%d)stat: Transmitted a Message successfully\n",
318                                      pchip->chip_idx);
319                                 c_can_write_reg_w(pchip, chip_status & ~SR_TXOK,
320                                                   CCSR);
321                         }
322
323                         if (chip_status & SR_RXOK) {
324                                 DEBUGMSG
325                                     ("(c%d)stat: Received a Message successfully\n",
326                                      pchip->chip_idx);
327                                 c_can_write_reg_w(pchip, chip_status & ~SR_RXOK,
328                                                   CCSR);
329                         }
330 #ifdef CAN_WITH_STATISTICS
331                         // Errors to statistics
332                         switch (chip_status & 0x07) {
333                         case SRLEC_NE:  // No error
334                                 break;
335                         case SRLEC_SE:  // Stuff error
336                                 pchip->stat.cntStuffErr++;
337                                 break;
338                         case SRLEC_FE:  // Form error
339                                 pchip->stat.cntFormErr++;
340                                 break;
341                         case SRLEC_AE:  // Ack error
342                                 pchip->stat.cntAckErr++;
343                                 break;
344                         case SRLEC_B1:  // Bit 1 error
345                                 pchip->stat.cntBit1Err++;
346                                 break;
347                         case SRLEC_B0:  // Bit 0 error
348                                 pchip->stat.cntBit0Err++;
349                                 break;
350                         case SRLEC_CR:  // CRC error
351                                 pchip->stat.cntCrcErr++;
352                                 break;
353                         case 7: // unused
354                                 break;
355                         }
356 #endif /*CAN_WITH_STATISTICS */
357                         //return; // continue?
358                 } else {
359                         if (irqreg > 0 && irqreg < 33) {
360                                 struct msgobj_t *pmsgobj;
361                                 int idxobj;
362
363                                 //get id
364                                 idxobj = irqreg - 1;
365                                 pmsgobj = pchip->msgobj[idxobj];
366
367                                 //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n",
368                                 //            (unsigned long)pchip->vbase_addr + iIRQ,
369                                 //      (unsigned long)dev_id,
370                                 //      irqreg,
371                                 //      statreg );
372                                 //
373                                 spin_lock(&c_can_if1lock);
374
375                                 //Message Lost Check
376                                 if (c_can_if1_busycheck(pchip)) ;       /*?????????? */
377                                 c_can_write_reg_w(pchip, msgLstReadMaskCM,
378                                                   CCIF1CM);
379                                 c_can_write_reg_w(pchip, idxobj + 1, CCIF1CR);
380
381                                 if (c_can_if1_busycheck(pchip)) ;       /*?????????? */
382                                 tempCntlReg = c_can_read_reg_w(pchip, CCIF1DMC);
383
384                                 if (tempCntlReg & IFXMC_MSGLST) {
385                                         CANMSG("(c%dm%d)Chip lost a message\n",
386                                                pchip->chip_idx,
387                                                pmsgobj->object);
388 #ifdef CAN_WITH_STATISTICS
389                                         pchip->stat.cntMsgLst++;
390 #endif /*CAN_WITH_STATISTICS */
391
392                                         //Reset Message Lost Bit
393                                         tempCntlReg =
394                                             tempCntlReg & (~IFXMC_MSGLST);
395                                         c_can_write_reg_w(pchip, tempCntlReg,
396                                                           CCIF1DMC);
397                                         c_can_write_reg_w(pchip,
398                                                           msgLstWriteMaskCM,
399                                                           CCIF1CM);
400                                         c_can_write_reg_w(pchip, idxobj + 1,
401                                                           CCIF1CR);
402                                 }
403                                 //transfer Message Object to IF1 Buffer
404                                 if (c_can_if1_busycheck(pchip)) ;
405                                 c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
406                                 c_can_write_reg_w(pchip, idxobj + 1, CCIF1CR);
407
408                                 if (c_can_if1_busycheck(pchip)) ;
409                                 if (c_can_read_reg_w(pchip, CCIF1A2) &
410                                     IFXARB2_DIR) {
411                                         spin_unlock(&c_can_if1lock);
412                                         c_can_irq_write_handler(pchip, idxobj);
413                                 } else {
414                                         if (can_msgobj_test_fl
415                                             (pmsgobj, RX_MODE_EXT)) {
416                                                 id0 =
417                                                     c_can_read_reg_w(pchip,
418                                                                      CCIF1A1);
419                                                 id1 =
420                                                     (c_can_read_reg_w
421                                                      (pchip,
422                                                       CCIF1A2) & 0x1FFF) << 16;
423                                                 msgid = id0 | id1;
424                                         } else {
425                                                 msgid =
426                                                     ((c_can_read_reg_w
427                                                       (pchip,
428                                                        CCIF1A2) & 0x1FFC) >> 2)
429                                                     & 0x7FF;
430                                         }
431                                         spin_unlock(&c_can_if1lock);
432
433                                         spin_lock(&hardware_p->rtr_lock);
434                                         while (rtr_search != NULL) {
435                                                 if (rtr_search->id == msgid) {
436                                                         break;
437                                                 }
438                                                 rtr_search = rtr_search->next;
439                                         }
440                                         spin_unlock(&hardware_p->rtr_lock);
441
442                                         spin_lock(&c_can_if1lock);
443
444                                         //transfer Message Object to IF1 Buffer
445                                         if (c_can_if1_busycheck(pchip)) ;
446                                         c_can_write_reg_w(pchip, readMaskCM,
447                                                           CCIF1CM);
448                                         c_can_write_reg_w(pchip, idxobj + 1,
449                                                           CCIF1CR);
450
451                                         if (c_can_if1_busycheck(pchip)) ;
452
453                                         if ((rtr_search != NULL)
454                                             && (rtr_search->id == msgid)) {
455                                                 c_can_irq_rtr_handler(pchip,
456                                                                       idxobj,
457                                                                       msgid);
458                                         } else {
459                                                 c_can_irq_read_handler(pchip,
460                                                                        idxobj,
461                                                                        msgid);
462                                         }
463                                         spin_unlock(&c_can_if1lock);
464
465                                         //}
466                                 }
467                                 //else
468                         }
469                         //if
470                 }
471                 // Get irq status again
472                 irqreg = c_can_read_reg_w(pchip, CCINTR);
473         }
474         return CANCHIP_IRQ_HANDLED;
475 }
476
477 ///////////////////////////////////////////////////////////////////////////////
478 // c_can_irq_rtr_handler
479 //
480
481 void c_can_irq_rtr_handler(struct canchip_t *pchip, int idxobj, u32 msgid)
482 {
483         short int i = 0;
484         struct rtr_id *prtr_search = hardware_p->rtr_queue;
485         union c_can_data rtrData;
486
487         spin_lock(&hardware_p->rtr_lock);
488
489         prtr_search->rtr_message->id = msgid;
490         prtr_search->rtr_message->length =
491             (c_can_read_reg_w(pchip, CCIF1DMC) & 0x000f);
492
493         // Fetch message bytes
494         if (prtr_search->rtr_message->length > 0)
495                 rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
496         if (prtr_search->rtr_message->length > 2)
497                 rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
498         if (prtr_search->rtr_message->length > 4)
499                 rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
500         if (prtr_search->rtr_message->length > 6)
501                 rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
502
503         for (i = 0; i < prtr_search->rtr_message->length; i++) {
504                 prtr_search->rtr_message->data[i] = rtrData.bdata[i];
505         }
506
507         spin_unlock(&hardware_p->rtr_lock);
508         wake_up_interruptible(&prtr_search->rtr_wq);
509         return;
510 }