Changeset 2d3d8f96 in rtems


Ignore:
Timestamp:
Apr 3, 2017, 11:27:49 AM (3 years ago)
Author:
Martin Aberg <maberg@…>
Branches:
master
Children:
3a650d3b
Parents:
ca4c4164
git-author:
Martin Aberg <maberg@…> (04/03/17 11:27:49)
git-committer:
Daniel Hellstrom <daniel@…> (05/14/17 10:31:58)
Message:

leon, grcan: redesigned bus-off and AHB error handling

When bus-off condition is detected by the ISR, it sets the started flag to
STATE_BUSOFF. This is monitored by the user functions grcan_read() and
grcan_write() each time they want to enable DMA or update interrupt mask. If
they detect that ISR has detected bus-off then they will return either with an
error or with the number of CAN messages processed. Future calls to functions
which require STARTED mode will be rejected and grcan_isstarted() will return

  1. The next call to grcan_stop() will do the transition from BUSOFF->STOPPED

and the device can then be started again with grcan_start().

Similar to a bus-off condition, the AHB error condition detected by the ISR
will trigger the same shut-down logic of the driver. The difference is that
the state entered is STATE_AHBERR and the routines will return a different
value to indicate AHB error state.

This commit also fixes an issue where ISR was not always unregistered on close.

User functions can cause these transitions:

STATE_STOPPED -> STATE_STARTED (grcan_start)
STATE_STARTED -> STATE_STOPPED (grcan_stop)
STATE_BUSOFF -> STATE_STOPPED (grcan_stop, grcan_close)
STATE_AHBERR -> STATE_STOPPED (grcan_stop, grcan_close)

ISR can cause these transition

STATE_STARTED -> STATE_BUSOFF (grcan_interrupt)
STATE_STARTED -> STATE_AHBERR (grcan_interrupt)

STATE_BUSOFF/AHBERR is entered from ISR on bus-off condition. At transition
the ISR disables DMA, masks all interrupts and flushes semaphores.

Other related updates:

  • Statistics are updated from the ISR. Update is now spin-locked to ensure a consistent user view.
  • The debug output has been updated to include state changes.
  • For read/write/flush, return error (-4) if driver aborted the operation due to bus-off. Likewise if abourted due to AHB error -5 is returned.
  • Collect bus-off statistics

Related to the new BUSOFF and AHBERR states the API has been updated to
reflect the current SW driver state. The isstarted() function has been
replaced with get_state().

Location:
c/src/lib/libbsp/sparc/shared
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/sparc/shared/can/grcan.c

    rca4c4164 r2d3d8f96  
    9393/* Uncomment for debug output */
    9494/****************** DEBUG Definitions ********************/
    95 #define DBG_IOCTRL 1
    9695#define DBG_TX 2
    9796#define DBG_RX 4
    98 
    99 #define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
     97#define DBG_STATE 8
     98
     99#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
    100100/*
    101101#define DEBUG
     
    105105
    106106/*********************************************************/
     107
     108int state2err[4] = {
     109        /* STATE_STOPPED */ GRCAN_RET_NOTSTARTED,
     110        /* STATE_STARTED */ GRCAN_RET_OK,
     111        /* STATE_BUSOFF  */ GRCAN_RET_BUSOFF,
     112        /* STATE_AHBERR  */ GRCAN_RET_AHBERR
     113};
    107114
    108115struct grcan_msg {
     
    157164static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
    158165
    159 static unsigned int grcan_hw_read_try(
     166static int grcan_hw_read_try(
    160167        struct grcan_priv *pDev,
    161168        struct grcan_regs *regs,
     
    163170        int max);
    164171
    165 static unsigned int grcan_hw_write_try(
     172static int grcan_hw_write_try(
    166173        struct grcan_priv *pDev,
    167174        struct grcan_regs *regs,
     
    601608        return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
    602609}
    603 
    604 static int grcan_hw_rx_ongoing(struct grcan_regs *regs)
    605 {
    606         return READ_REG(&regs->rx0ctrl) & GRCAN_RXCTRL_ONGOING;
    607 }
    608 
    609 static int grcan_hw_tx_ongoing(struct grcan_regs *regs)
    610 {
    611         return READ_REG(&regs->tx0ctrl) & GRCAN_TXCTRL_ONGOING;
    612 }
    613 
    614610
    615611#define MIN_TSEG1 1
     
    724720}
    725721
    726 static unsigned int grcan_hw_read_try(
     722static int grcan_hw_read_try(
    727723        struct grcan_priv *pDev,
    728724        struct grcan_regs *regs,
     
    734730        CANMsg *dest;
    735731        struct grcan_msg *source, tmp;
    736         unsigned int wp, rp, size, rxmax, addr, trunk_msg_cnt;
     732        unsigned int wp, rp, size, rxmax, addr;
     733        int trunk_msg_cnt;
    737734
    738735        FUNCDBG();
     
    776773                        tmp.head[0] = READ_DMA_WORD(&source->head[0]);
    777774                        tmp.head[1] = READ_DMA_WORD(&source->head[1]);
     775                        if (tmp.head[1] & 0x4) {
     776                                DBGC(DBG_RX, "overrun\n");
     777                        }
     778                        if (tmp.head[1] & 0x2) {
     779                                DBGC(DBG_RX, "bus-off mode\n");
     780                        }
     781                        if (tmp.head[1] & 0x1) {
     782                                DBGC(DBG_RX, "error-passive mode\n");
     783                        }
    778784                        /* Convert one grcan CAN message to one "software" CAN message */
    779785                        dest->extended = tmp.head[0] >> 31;
     
    795801                        i--;
    796802                }
    797                 /* Increment Hardware READ pointer (mark read byte as read)
    798                  * ! wait for registers to be safely re-configurable
    799                  */
    800                 regs->rx0ctrl = 0;      /* DISABLE RX CHANNEL */
    801                 i = 0;
    802                 while (grcan_hw_rx_ongoing(regs) && (i < 1000)) {
    803                         i++;
    804                 }
    805                 regs->rx0rd = (unsigned int)source - addr;
    806                 regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;    /* ENABLE_RX_CHANNEL */
     803                {
     804                        /* A bus off interrupt may have occured after checking pDev->started */
     805                        SPIN_IRQFLAGS(oldLevel);
     806
     807                        SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     808                        if (pDev->started == STATE_STARTED) {
     809                                regs->rx0rd = (unsigned int) source - addr;
     810                                regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
     811                        } else {
     812                                DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
     813                                trunk_msg_cnt = state2err[pDev->started];
     814                        }
     815                        SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
     816                }
    807817                return trunk_msg_cnt;
    808818        }
     
    810820}
    811821
    812 static unsigned int grcan_hw_write_try(
     822static int grcan_hw_write_try(
    813823        struct grcan_priv *pDev,
    814824        struct grcan_regs *regs,
     
    817827)
    818828{
    819         unsigned int rp, wp, size, txmax, addr, ret;
     829        unsigned int rp, wp, size, txmax, addr;
     830        int ret;
    820831        struct grcan_msg *dest;
    821832        CANMsg *source;
     
    868879        }
    869880
    870         /* Update write pointer
    871          * ! wait for registers to be safely re-configurable
    872          */
    873         regs->tx0ctrl = 0;      /* DISABLE TX CHANNEL */
    874         i = 0;
    875         while ((grcan_hw_tx_ongoing(regs)) && i < 1000) {
    876                 i++;
    877         }
    878         regs->tx0wr = (unsigned int)dest - addr;        /* Update write pointer */
    879         regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;    /* ENABLE_TX_CHANNEL */
     881        {
     882                /* A bus off interrupt may have occured after checking pDev->started */
     883                SPIN_IRQFLAGS(oldLevel);
     884
     885                SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     886                if (pDev->started == STATE_STARTED) {
     887                        regs->tx0wr = (unsigned int) dest - addr;
     888                        regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
     889                } else {
     890                        DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
     891                        ret = state2err[pDev->started];
     892                }
     893                SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
     894        }
    880895        return ret;
    881896}
     
    885900        unsigned int wp, rp, size, irq;
    886901        unsigned int irq_trunk, dataavail;
    887         int wait;
     902        int wait, state;
    888903        SPIN_IRQFLAGS(oldLevel);
    889904
     
    895910         */
    896911        SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     912        state = pDev->started;
     913
     914        /* A bus off interrupt may have occured after checking pDev->started */
     915        if (state != STATE_STARTED) {
     916                SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
     917                if (state == STATE_BUSOFF) {
     918                        DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
     919                } else if (state == STATE_AHBERR) {
     920                        DBGC(DBG_STATE, "cancelled due to a AHB error\n");
     921                } else {
     922                        DBGC(DBG_STATE, "cancelled due to STOP (unexpected) \n");
     923                }
     924                return state2err[state];
     925        }
    897926
    898927        size = READ_REG(&pDev->regs->rx0size);
     
    937966                                RTEMS_NO_TIMEOUT
    938967                        ) == RTEMS_UNSATISFIED
    939                 )
    940                         return -1;      /* Device driver has been closed or stopped, return with error status */
    941         }
    942 
    943         return 0;
    944 }
    945 
    946 /* Wait until min bytes available in TX circular buffer.
    947  * The IRQ RxIrq is used to pin point the location of
     968                ) {
     969                        DBGC(DBG_STATE, "UNSATISFIED\n");
     970                        /* Device driver has been closed or stopped, return with error status */
     971                        return state2err[pDev->started];
     972                }
     973        }
     974
     975        return 0;
     976}
     977
     978/* Wait until min bytes available in TX circular buffer. TXIRQ is used to pin
     979 * point the location of the CAN message corresponding to min.
    948980 *
    949981 * min must be at least WRAP_AROUND_TX_BYTES bytes less
     
    953985static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
    954986{
    955         int wait;
     987        int wait, state;
    956988        unsigned int irq, rp, wp, size, space_left;
    957989        unsigned int irq_trunk;
     
    962994
    963995        SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     996        state = pDev->started;
     997        /* A bus off interrupt may have occured after checking pDev->started */
     998        if (state != STATE_STARTED) {
     999                SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
     1000                if (state == STATE_BUSOFF) {
     1001                        DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
     1002                } else if (state == STATE_AHBERR) {
     1003                        DBGC(DBG_STATE, "cancelled due to a AHB error\n");
     1004                } else {
     1005                        DBGC(DBG_STATE, "cancelled due to STOP (unexpected)\n");
     1006                }
     1007                return state2err[state];
     1008        }
    9641009
    9651010        pDev->regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
     
    10111056                        /* Device driver has flushed us, this may be due to another thread has
    10121057                         * closed the device, this is to avoid deadlock */
    1013                         return -1;
     1058                        DBGC(DBG_STATE, "UNSATISFIED\n");
     1059                        return state2err[pDev->started];
    10141060                }
    10151061        }
     
    10211067static int grcan_tx_flush(struct grcan_priv *pDev)
    10221068{
    1023         int wait;
     1069        int wait, state;
    10241070        unsigned int rp, wp;
    10251071        SPIN_IRQFLAGS(oldLevel);
     
    10371083                /* Wait for TX empty IRQ */
    10381084                SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     1085                state = pDev->started;
     1086
     1087                /* A bus off interrupt may have occured after checking pDev->started */
     1088                if (state != STATE_STARTED) {
     1089                        SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
     1090                        if (state == STATE_BUSOFF) {
     1091                                DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
     1092                        } else if (state == STATE_AHBERR) {
     1093                                DBGC(DBG_STATE, "cancelled due to a AHB error\n");
     1094                        } else {
     1095                                DBGC(DBG_STATE, "cancelled due to STOP (unexpected)\n");
     1096                        }
     1097                        return state2err[state];
     1098                }
     1099
    10391100                /* Clear pending TXEmpty IRQ */
    10401101                pDev->regs->picr = GRCAN_TXEMPTY_IRQ;
     
    10571118                    (pDev->txempty_sem, RTEMS_WAIT,
    10581119                     RTEMS_NO_TIMEOUT) == RTEMS_UNSATISFIED) {
    1059                         return -1;
     1120                        DBGC(DBG_STATE, "UNSATISFIED\n");
     1121                        return state2err[pDev->started];
    10601122                }
    10611123        }
     
    12321294        pDev->txblock = pDev->rxblock = 1;
    12331295        pDev->txcomplete = pDev->rxcomplete = 0;
    1234         pDev->started = 0;
     1296        pDev->started = STATE_STOPPED;
    12351297        pDev->config_changed = 1;
    12361298        pDev->config.silent = 0;
     
    12971359        FUNCDBG();
    12981360
    1299         if ( pDev->started ) {
    1300                 /* Disable interrupts */
    1301                 drvmgr_interrupt_unregister(pDev->dev, 0, grcan_interrupt, pDev);
    1302                 grcan_hw_stop(pDev);
    1303                 pDev->started = 0;
    1304         }
     1361        grcan_stop(d);
    13051362
    13061363        grcan_hw_reset(pDev->regs);
     
    13191376        CANMsg *dest;
    13201377        unsigned int count, left;
     1378        int nread;
    13211379        int req_cnt;
    13221380
     
    13271385
    13281386        if ( (!dest) || (req_cnt<1) )
    1329                 return -1;
    1330 
    1331         if ( !pDev->started )
    1332                 return -2;
    1333 
    1334         /*FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/
    1335 
    1336         count = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
     1387                return GRCAN_RET_INVARG;
     1388
     1389        if (pDev->started != STATE_STARTED) {
     1390                return GRCAN_RET_NOTSTARTED;
     1391        }
     1392
     1393        DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
     1394
     1395        nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
     1396        if (nread < 0) {
     1397                return nread;
     1398        }
     1399        count = nread;
    13371400        if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
    13381401                if ( count > 0 ) {
     
    13441407                if ( !pDev->rxblock ) {
    13451408                        /* non-blocking mode */
    1346                         return -3;
     1409                        return GRCAN_RET_TIMEOUT;
    13471410                }
    13481411        }
     
    13641427                }
    13651428
    1366                 if (grcan_wait_rxdata(pDev, left)) {
     1429                nread = grcan_wait_rxdata(pDev, left);
     1430                if (nread) {
    13671431                        /* The wait has been aborted, probably due to
    13681432                         * the device driver has been closed by another
    1369                          * thread.
     1433                         * thread or a bus-off. Return error code.
    13701434                         */
    1371                         return count;
     1435                        return nread;
    13721436                }
    13731437
    13741438                /* Try read bytes from circular buffer */
    1375                 count += grcan_hw_read_try(
     1439                nread = grcan_hw_read_try(
    13761440                                pDev,
    13771441                                pDev->regs,
    13781442                                dest+count,
    13791443                                req_cnt-count);
     1444
     1445                if (nread < 0) {
     1446                        /* The read was aborted by bus-off. */
     1447                        return nread;
     1448                }
     1449                count += nread;
    13801450        }
    13811451        /* no need to unmask IRQ as IRQ Handler do that for us. */
     
    13881458        CANMsg *source;
    13891459        unsigned int count, left;
     1460        int nwritten;
    13901461        int req_cnt;
    13911462
    13921463        DBGC(DBG_TX,"\n");
    13931464
    1394         if ( !pDev->started || pDev->config.silent || pDev->flushing )
    1395                 return -2;
     1465        if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
     1466                return GRCAN_RET_NOTSTARTED;
    13961467
    13971468        req_cnt = ucount;
     
    14001471        /* check proper length and buffer pointer */
    14011472        if (( req_cnt < 1) || (source == NULL) ){
    1402                 return -1;
    1403         }
    1404 
    1405         count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
     1473                return GRCAN_RET_INVARG;
     1474        }
     1475
     1476        nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
     1477        if (nwritten < 0) {
     1478                return nwritten;
     1479        }
     1480        count = nwritten;
    14061481        if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
    14071482                if ( count > 0 ) {
     
    14131488                if ( !pDev->txblock ) {
    14141489                        /* non-blocking mode */
    1415                         return -3;
     1490                        return GRCAN_RET_TIMEOUT;
    14161491                }
    14171492        }
     
    14371512                }
    14381513
     1514                nwritten = grcan_wait_txspace(pDev,left);
    14391515                /* Wait until more room in transmit buffer */
    1440                 if ( grcan_wait_txspace(pDev,left) ){
     1516                if ( nwritten ) {
    14411517                        /* The wait has been aborted, probably due to
    14421518                         * the device driver has been closed by another
     
    14441520                         * with error status.
    14451521                         */
    1446                         return count;
     1522                        return nwritten;
    14471523                }
    14481524
     
    14561532
    14571533                /* Try read bytes from circular buffer */
    1458                 count += grcan_hw_write_try(
     1534                nwritten = grcan_hw_write_try(
    14591535                        pDev,
    14601536                        pDev->regs,
    14611537                        source+count,
    14621538                        req_cnt-count);
     1539
     1540                if (nwritten < 0) {
     1541                        /* Write was aborted by bus-off. */
     1542                        return nwritten;
     1543                }
     1544                count += nwritten;
    14631545        }
    14641546        /* no need to unmask IRQ as IRQ Handler do that for us. */
     
    14701552{
    14711553        struct grcan_priv *pDev = d;
    1472         rtems_device_driver status;
    1473 
    1474         FUNCDBG();
    1475 
    1476         if ( pDev->started )
     1554
     1555        FUNCDBG();
     1556
     1557        if (grcan_get_state(d) == STATE_STARTED) {
    14771558                return -1;
    1478 
    1479         if ( (status=grcan_hw_start(pDev)) != RTEMS_SUCCESSFUL ){
     1559        }
     1560
     1561        if ( (grcan_hw_start(pDev)) != RTEMS_SUCCESSFUL ){
    14801562                return -2;
    14811563        }
    14821564
    14831565        /* Read and write are now open... */
    1484         pDev->started = 1;
     1566        pDev->started = STATE_STARTED;
     1567        DBGC(DBG_STATE, "STOPPED|BUSOFF|AHBERR->STARTED\n");
    14851568
    14861569        /* Register interrupt routine and enable IRQ at IRQ ctrl */
     
    14941577{
    14951578        struct grcan_priv *pDev = d;
    1496 
    1497         FUNCDBG();
    1498 
    1499         if ( !pDev->started )
     1579        SPIN_IRQFLAGS(oldLevel);
     1580
     1581        FUNCDBG();
     1582
     1583        if (pDev->started == STATE_STOPPED)
    15001584                return -1;
     1585
     1586        SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
     1587        if (pDev->started == STATE_STARTED) {
     1588                grcan_hw_stop(pDev);
     1589                DBGC(DBG_STATE, "STARTED->STOPPED\n");
     1590        } else {
     1591                /*
     1592                 * started == STATE_[STOPPED|BUSOFF|AHBERR] so grcan_hw_stop()
     1593                 * might already been called from ISR.
     1594                 */
     1595                DBGC(DBG_STATE, "[STOPPED|BUSOFF|AHBERR]->STOPPED\n");
     1596        }
     1597        pDev->started = STATE_STOPPED;
     1598        SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
    15011599
    15021600        /* Disable interrupts */
    15031601        drvmgr_interrupt_unregister(pDev->dev, 0, grcan_interrupt, pDev);
    15041602
    1505         grcan_hw_stop(pDev);
    1506         pDev->started = 0;
    1507 
    1508         return 0;
    1509 }
    1510 
    1511 int grcan_isstarted(void *d)
     1603        return 0;
     1604}
     1605
     1606int grcan_get_state(void *d)
    15121607{
    15131608        struct grcan_priv *pDev = d;
     
    15251620        FUNCDBG();
    15261621
    1527         if ( !pDev->started || pDev->flushing || pDev->config.silent )
     1622        if ((pDev->started != STATE_STARTED) || pDev->flushing || pDev->config.silent)
    15281623                return -1;
    15291624
     
    15481643        FUNCDBG();
    15491644
    1550         if ( pDev->started )
     1645        if (pDev->started == STATE_STARTED)
    15511646                return -1;
    15521647
     
    15631658        FUNCDBG();
    15641659
    1565         if ( pDev->started )
     1660        if (pDev->started == STATE_STARTED)
    15661661                return -1;
    15671662
     
    15801675        FUNCDBG();
    15811676
    1582         if ( pDev->started )
     1677        if (pDev->started == STATE_STARTED)
    15831678                return -1;
    15841679
     
    16761771
    16771772        /* cannot change speed during run mode */
    1678         if ( pDev->started )
     1773        if (pDev->started == STATE_STARTED)
    16791774                return -1;
    16801775
     
    17001795         * Read GRCAN/HurriCANe Manual.
    17011796         */
    1702         if ( pDev->started )
     1797        if (pDev->started == STATE_STARTED)
    17031798                return -1;
    17041799
     
    17781873}
    17791874
     1875/* Error indicators */
     1876#define GRCAN_IRQ_ERRORS \
     1877                (GRCAN_RXAHBERR_IRQ | GRCAN_TXAHBERR_IRQ | GRCAN_OFF_IRQ)
     1878#define GRCAN_STAT_ERRORS (GRCAN_STAT_AHBERR | GRCAN_STAT_OFF)
     1879/* Warning & RX/TX sync indicators */
     1880#define GRCAN_IRQ_WARNS \
     1881                (GRCAN_ERR_IRQ | GRCAN_OR_IRQ | GRCAN_TXLOSS_IRQ | \
     1882                 GRCAN_RXSYNC_IRQ | GRCAN_TXSYNC_IRQ)
     1883#define GRCAN_STAT_WARNS (GRCAN_STAT_OR | GRCAN_STAT_PASS)
     1884
    17801885/* Handle the IRQ */
    17811886static void grcan_interrupt(void *arg)
     
    17841889        unsigned int status = READ_REG(&pDev->regs->pimsr);
    17851890        unsigned int canstat = READ_REG(&pDev->regs->stat);
     1891        unsigned int imr_clear;
    17861892        SPIN_ISR_IRQFLAGS(irqflags);
    17871893
     
    17901896                return;
    17911897
    1792         FUNCDBG();
    1793 
    1794         /* Increment number of interrupts counter */
    1795         pDev->stats.ints++;
    1796 
    1797         if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ){
    1798                 /* Error-Passive interrupt */
    1799                 pDev->stats.passive_cnt++;
    1800         }
    1801 
    1802         if ( (status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF) ){
    1803                 /* Bus-off condition interrupt
     1898        if (pDev->started != STATE_STARTED) {
     1899                DBGC(DBG_STATE, "not STARTED (unexpected interrupt)\n");
     1900                pDev->regs->picr = status;
     1901                return;
     1902        }
     1903
     1904        FUNCDBG();
     1905
     1906        if ( (status & GRCAN_IRQ_ERRORS) || (canstat & GRCAN_STAT_ERRORS) ) {
     1907                /* Bus-off condition interrupt
    18041908                 * The link is brought down by hardware, we wake all threads
    18051909                 * that is blocked in read/write calls and stop futher calls
     
    18071911                 */
    18081912                SPIN_LOCK(&pDev->devlock, irqflags);
    1809                 pDev->started = 0;
     1913                DBGC(DBG_STATE, "STARTED->BUSOFF|AHBERR\n");
     1914                pDev->stats.ints++;
     1915                if ((status & GRCAN_OFF_IRQ) || (canstat & GRCAN_STAT_OFF)) {
     1916                        /* CAN Bus-off interrupt */
     1917                        DBGC(DBG_STATE, "BUSOFF: status: 0x%x, canstat: 0x%x\n",
     1918                                status, canstat);
     1919                        pDev->started = STATE_BUSOFF;
     1920                        pDev->stats.busoff_cnt++;
     1921                } else {
     1922                        /* RX or Tx AHB Error interrupt */
     1923                        printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",
     1924                                status, canstat);
     1925                        pDev->started = STATE_AHBERR;
     1926                        pDev->stats.ahberr_cnt++;
     1927                }
    18101928                grcan_hw_stop(pDev); /* this mask all IRQ sources */
     1929                pDev->regs->picr = 0x1ffff; /* clear all interrupts */
     1930                /*
     1931                 * Prevent driver from affecting bus. Driver can be started
     1932                 * again with grcan_start().
     1933                 */
    18111934                SPIN_UNLOCK(&pDev->devlock, irqflags);
    1812                 status=0x1ffff; /* clear all interrupts */
    1813                 goto out;
    1814         }
    1815 
    1816         if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ){
    1817                 /* Over-run during reception interrupt */
    1818                 pDev->stats.overrun_cnt++;
    1819         }
    1820 
    1821         if ( (status & GRCAN_RXAHBERR_IRQ) ||
    1822              (status & GRCAN_TXAHBERR_IRQ) ||
    1823              (canstat & GRCAN_STAT_AHBERR) ){
    1824                 /* RX or Tx AHB Error interrupt */
    1825                 printk("AHBERROR: status: 0x%x, canstat: 0x%x\n",status,canstat);
    1826                 pDev->stats.ahberr_cnt++;
    1827         }
    1828 
    1829         if ( status & GRCAN_TXLOSS_IRQ ) {
    1830                 pDev->stats.txloss_cnt++;
    1831         }
    1832 
    1833         if ( status & GRCAN_RXIRQ_IRQ ){
    1834                 /* RX IRQ pointer interrupt */
    1835                 /*printk("RxIrq 0x%x\n",status);*/
    1836                 SPIN_LOCK(&pDev->devlock, irqflags);
    1837                 pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
     1935                /*
     1936                 * NOTE: Another interrupt may be pending now so ISR could be
     1937                 * executed one more time aftert this (first) return.
     1938                 */
     1939                return;
     1940        }
     1941
     1942        /* Mask interrupts in one place under spin-lock. */
     1943        imr_clear = status & (GRCAN_RXIRQ_IRQ | GRCAN_TXIRQ_IRQ | GRCAN_TXEMPTY_IRQ);
     1944
     1945        SPIN_LOCK(&pDev->devlock, irqflags);
     1946
     1947        /* Increment number of interrupts counter */
     1948        pDev->stats.ints++;
     1949        if ((status & GRCAN_IRQ_WARNS) || (canstat & GRCAN_STAT_WARNS)) {
     1950
     1951                if ( (status & GRCAN_ERR_IRQ) || (canstat & GRCAN_STAT_PASS) ) {
     1952                        /* Error-Passive interrupt */
     1953                        pDev->stats.passive_cnt++;
     1954                }
     1955
     1956                if ( (status & GRCAN_OR_IRQ) || (canstat & GRCAN_STAT_OR) ) {
     1957                        /* Over-run during reception interrupt */
     1958                        pDev->stats.overrun_cnt++;
     1959                }
     1960
     1961                if ( status & GRCAN_TXLOSS_IRQ ) {
     1962                        pDev->stats.txloss_cnt++;
     1963                }
     1964
     1965                if ( status & GRCAN_TXSYNC_IRQ ) {
     1966                        /* TxSync message transmitted interrupt */
     1967                        pDev->stats.txsync_cnt++;
     1968                }
     1969
     1970                if ( status & GRCAN_RXSYNC_IRQ ) {
     1971                        /* RxSync message received interrupt */
     1972                        pDev->stats.rxsync_cnt++;
     1973                }
     1974        }
     1975
     1976        if (imr_clear) {
     1977                pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~imr_clear;
     1978
    18381979                SPIN_UNLOCK(&pDev->devlock, irqflags);
    1839                 rtems_semaphore_release(pDev->rx_sem);
    1840         }
    1841 
    1842         if ( status & GRCAN_TXIRQ_IRQ ){
    1843                 /* TX IRQ pointer interrupt */
    1844                 SPIN_LOCK(&pDev->devlock, irqflags);
    1845                 pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
     1980
     1981                if ( status & GRCAN_RXIRQ_IRQ ) {
     1982                        /* RX IRQ pointer interrupt */
     1983                        rtems_semaphore_release(pDev->rx_sem);
     1984                }
     1985
     1986                if ( status & GRCAN_TXIRQ_IRQ ) {
     1987                        /* TX IRQ pointer interrupt */
     1988                        rtems_semaphore_release(pDev->tx_sem);
     1989                }
     1990
     1991                if (status & GRCAN_TXEMPTY_IRQ ) {
     1992                        rtems_semaphore_release(pDev->txempty_sem);
     1993                }
     1994        } else {
    18461995                SPIN_UNLOCK(&pDev->devlock, irqflags);
    1847                 rtems_semaphore_release(pDev->tx_sem);
    1848         }
    1849 
    1850         if ( status & GRCAN_TXSYNC_IRQ ){
    1851                 /* TxSync message transmitted interrupt */
    1852                 pDev->stats.txsync_cnt++;
    1853         }
    1854 
    1855         if ( status & GRCAN_RXSYNC_IRQ ){
    1856                 /* RxSync message received interrupt */
    1857                 pDev->stats.rxsync_cnt++;
    1858         }
    1859 
    1860         if ( status & GRCAN_TXEMPTY_IRQ ){
    1861                 SPIN_LOCK(&pDev->devlock, irqflags);
    1862                 pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
    1863                 SPIN_UNLOCK(&pDev->devlock, irqflags);
    1864                 rtems_semaphore_release(pDev->txempty_sem);
    1865         }
    1866 
    1867 out:
     1996        }
     1997
    18681998        /* Clear IRQs */
    18691999        pDev->regs->picr = status;
  • c/src/lib/libbsp/sparc/shared/include/grcan.h

    rca4c4164 r2d3d8f96  
    6969        unsigned int ahberr_cnt;
    7070        unsigned int ints;
     71        unsigned int busoff_cnt;
    7172};
    7273
     
    99100        unsigned int id;
    100101} CANMsg;
     102
     103enum {
     104        GRCAN_RET_OK            =  0,
     105        GRCAN_RET_INVARG        = -1,
     106        GRCAN_RET_NOTSTARTED    = -2,
     107        GRCAN_RET_TIMEOUT       = -3,
     108        /* Bus-off condition detected (request aborted by driver) */
     109        GRCAN_RET_BUSOFF        = -4,
     110        /* AHB error condition detected (request aborted by driver) */
     111        GRCAN_RET_AHBERR        = -5,
     112};
     113
     114/*
     115 * User functions can cause these transitions:
     116 *   STATE_STOPPED -> STATE_STARTED
     117 *   STATE_STARTED -> STATE_STOPPED
     118 *   STATE_BUSOFF  -> STATE_STOPPED
     119 *   STATE_AHBERR  -> STATE_STOPPED
     120 *
     121 * ISR can cause these transition
     122 *   STATE_STARTED -> STATE_BUSOFF
     123 *   STATE_STARTED -> STATE_AHBERR
     124 *
     125 * STATE_BUSOFF is entered from ISR on bus-off condition. STATE_AHBERR is
     126 * entered from ISR on AHB DMA errors on RX/TX operations. At transition the ISR
     127 * disables DMA, masks all interrupts and releases semaphores.
     128 */
     129enum grcan_state {
     130        STATE_STOPPED           = 0,
     131        STATE_STARTED           = 1,
     132        STATE_BUSOFF            = 2,
     133        STATE_AHBERR            = 3,
     134};
    101135
    102136#define GRCAN_CFG_ABORT      0x00000001
     
    199233 *
    200234 * return:
    201  *   >=0:       Number of CAN messages received. This can be less than the
    202  *              count parameter.
    203  *   -1:        count parameter less than size of struct grcan_msg or NULL msg.
    204  *   -2:        Device not in started mode
    205  *   -3:        Timeout in non-blocking mode
    206  *   -4:        A blocking read was interrupted by a Bus-off error. Device has
    207  *              left started mode.
     235 *   >=0:                       Number of CAN messages received. This can be
     236 *                              less than the count parameter.
     237 *   GRCAN_RET_INVARG:          count parameter less than one or NULL msg.
     238 *   GRCAN_RET_NOTSTARTED:      Device not in started mode
     239 *   GRCAN_RET_TIMEOUT:         Timeout in non-blocking mode
     240 *   GRCAN_RET_BUSOFF:          A read was interrupted by a bus-off error.
     241 *                              Device has left started mode.
     242 *   GRCAN_RET_AHBERR:          Similar to BUSOFF, but was caused by AHB Error.
    208243 */
    209244extern int grcan_read(
     
    223258 *
    224259 * return:
    225  *   >=0:       Number of CAN messages transmitted. This can be less than the
    226  *              count parameter.
    227  *   -1:        count parameter less than size of struct grcan_msg
    228  *   -2:        Device not in started mode
    229  *   -3:        Timeout in non-blocking mode
    230  *   -4:        Bus-off error. Device has left started mode
     260 *   >=0:                       Number of CAN messages transmitted. This can be
     261 *                              less than the count parameter.
     262 *   GRCAN_RET_INVARG:          count parameter less than one.
     263 *   GRCAN_RET_NOTSTARTED:      Device not in started mode
     264 *   GRCAN_RET_TIMEOUT:         Timeout in non-blocking mode
     265 *   GRCAN_RET_BUSOFF:          A write was interrupted by a Bus-off error.
     266 *                              Device has left started mode
     267 *   GRCAN_RET_AHBERR:          Similar to BUSOFF, but was caused by AHB Error.
    231268 */
    232269extern int grcan_write(
     
    236273);
    237274
     275/*
     276 * Returns current GRCAN software state
     277 *
     278 * If STATE_BUSOFF or STATE_AHBERR is returned then the function grcan_stop()
     279 * shall be called before continue using the driver.
     280 *
     281 * d: Device handle
     282 * return:
     283 *   STATE_STOPPED              Stopped
     284 *   STATE_STARTED              Started
     285 *   STATE_BUSOFF               Bus-off has been detected
     286 *   STATE_AHBERR               AHB error has been detected
     287 */
     288extern int grcan_get_state(void *d);
     289
    238290/* The remaining functions return 0 on success and non-zero on failure. */
    239291
     
    245297/* stop to change baud rate/config or closing down */
    246298extern int grcan_stop(void *d);
    247 /* return 1 when started, othervise 0 */
    248 extern int grcan_isstarted(void *d);
    249299/* Wait until all TX messages have been sent */
    250300extern int grcan_flush(void *d);
Note: See TracChangeset for help on using the changeset viewer.