From f7bcff3d1274326fc23033fcfd09a6deef69cd28 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 6 Aug 2015 11:50:41 -0600 Subject: [PATCH] SAMV7 MCAN: Fix filter configuration when now filters are defined. We need to accept all messages in this case --- arch/arm/src/samv7/sam_mcan.c | 149 ++++++++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 26 deletions(-) diff --git a/arch/arm/src/samv7/sam_mcan.c b/arch/arm/src/samv7/sam_mcan.c index f3358196627..94bb7e4af50 100644 --- a/arch/arm/src/samv7/sam_mcan.c +++ b/arch/arm/src/samv7/sam_mcan.c @@ -858,6 +858,11 @@ struct sam_mcan_s { const struct sam_config_s *config; /* The constant configuration */ bool initialized; /* True: Device has been initialized */ +#ifdef CONFIG_CAN_EXTID + uint8_t nextalloc; /* Number of allocated extended filters */ +#else + uint8_t nstdalloc; /* Number of allocated standard filters */ +#endif sem_t locksem; /* Enforces mutually exclusive access */ sem_t txfsem; /* Used to wait for TX FIFO availability */ uint32_t rxints; /* Configured RX interrupts */ @@ -1522,12 +1527,12 @@ static uint8_t mcan_bytes2dlc(FAR struct sam_mcan_s *priv, uint8_t nbytes) * Name: mcan_add_extfilter * * Description: - * Add an address filter for a extended 28 bit address. + * Add an address filter for a extended 29 bit address. * * Input Parameters: * priv - An instance of the MCAN driver state structure. - * id - The 28-bit extended address to filter - * mask - A 28-bit extended address mask + * id - The 29-bit extended address to filter + * mask - A 29-bit extended address mask * * Returned Value: * A non-negative filter ID is returned on success. Otherwise a negated @@ -1547,7 +1552,7 @@ static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id, int ndx; DEBUGASSERT(priv != NULL && priv->config != NULL && - id < (1 << 28) && mask < (1 << 28)); + id < (1 << 29) && mask < (1 << 29)); config = priv->config; /* Get exclusive excess to the MCAN hardware */ @@ -1565,7 +1570,11 @@ static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id, if ((priv->extfilters[word] & (1 << bit)) == 0) { - /* No, then this is the one that we will use */ + /* No, assign the filter */ + + DEBUGASSERT(priv->nextalloc < priv->config->nstdfilters); + priv->extfilters[word] |= (1 << bit); + priv->nextalloc++; extfilter = config->msgram.extfilters + (ndx << 1); @@ -1577,11 +1586,30 @@ static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id, /* Flush the filter entry into physical RAM */ arch_clean_dcache((uintptr_t)extfilter, (uintptr_t)exfilter + 8); + + /* Is this the first extended filter? */ + + if (priv->nextalloc == 1) + { + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFE=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + mcan_dev_unlock(priv); return ndx; } } + DEBUGASSERT(priv->nextalloc == priv->config->nextfilters); mcan_dev_unlock(priv); return -EAGAIN; } @@ -1591,7 +1619,7 @@ static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id, * Name: mcan_del_extfilter * * Description: - * Remove an address filter for a standard 28 bit address. + * Remove an address filter for a standard 29 bit address. * * Input Parameters: * priv - An instance of the MCAN driver state structure. @@ -1608,6 +1636,7 @@ static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx) { FAR const struct sam_config_s *config; FAR uint32_t *extfilter; + uint32_t regval; int word; int bit; @@ -1619,18 +1648,38 @@ static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx) mcan_dev_lock(priv); - /* Deactivate the filter */ - - extfilter = config->msgram.extfilters + (ndx << 1); - *extfilter++ = 0; - *extfilter = 0; - /* Release the filter */ word = ndx >> 5; bit = ndx & 0x1f; priv->extfilters[word] &= ~(1 << bit); + DEBUGASSERT(priv->nextalloc > 0); + priv->nextalloc--; + + /* Was that the last extended filter? */ + + if (priv->nextalloc == 0) + { + /* If there are no extended filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFE=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + extfilter = config->msgram.extfilters + (ndx << 1); + *extfilter++ = 0; + *extfilter = 0; + mcan_dev_unlock(priv); return OK; } @@ -1671,7 +1720,7 @@ static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id) /* Find an unused standard filter */ - for (ndx = 0; ndx < config->nstdfilters; ndx++) + for (ndx = 0; ndx < config->nstdfilters; ndx++) { /* Is this filter assigned? */ @@ -1680,7 +1729,11 @@ static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id) if ((priv->stdfilters[word] & (1 << bit)) == 0) { - /* No, then this is the one that we will use */ + /* No, assign the filter */ + + DEBUGASSERT(priv->nstdalloc < priv->config->nstdfilters); + priv->stdfilters[word] |= (1 << bit); + priv->nstdalloc++; stdfilter = config->msgram.stdfilters + ndx; regval = STDFILTER_S0_SFT_CLASSIC | STDFILTER_S0_SFID1(id); @@ -1693,11 +1746,30 @@ static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id) /* Flush the filter entry into physical RAM */ arch_clean_dcache((uintptr_t)stdfilter, (uintptr_t)stdfilter + 4); + + /* Is this the first standard filter? */ + + if (priv->nstdalloc == 1) + { + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFS=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + mcan_dev_unlock(priv); return ndx; } } + DEBUGASSERT(priv->nstdalloc == priv->config->nstdfilters); mcan_dev_unlock(priv); return -EAGAIN; } @@ -1707,7 +1779,7 @@ static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id) * Name: mcan_del_stdfilter * * Description: - * Remove an address filter for a standard 28 bit address. + * Remove an address filter for a standard 29 bit address. * * Input Parameters: * priv - An instance of the MCAN driver state structure. @@ -1724,6 +1796,7 @@ static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx) { FAR const struct sam_config_s *config; FAR uint32_t *stdfilter; + uint32_t regval; int word; int bit; @@ -1735,17 +1808,37 @@ static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx) mcan_dev_lock(priv); - /* Deactivate the filter */ - - stdfilter = config->msgram.stdfilters + ndx; - *stdfilter = 0; - /* Release the filter */ word = ndx >> 5; bit = ndx & 0x1f; priv->stdfilters[word] &= ~(1 << bit); + DEBUGASSERT(priv->nstdalloc > 0); + priv->nstdalloc--; + + /* Was that the last standard filter? */ + + if (priv->nstdalloc == 0) + { + /* If there are no standard filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + stdfilter = config->msgram.stdfilters + ndx; + *stdfilter = 0; + mcan_dev_unlock(priv); return OK; } @@ -2036,7 +2129,7 @@ static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) { #ifdef CONFIG_CAN_EXTID /* CANIOC_ADD_EXTFILTER: - * Description: Add an address filter for a extended 28 bit + * Description: Add an address filter for a extended 29 bit * address. * Argument: A reference to struct canioc_extfilter_s * Returned Value: A non-negative filter ID is returned on success. @@ -2054,7 +2147,7 @@ static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) break; /* CANIOC_DEL_EXTFILTER: - * Description: Remove an address filter for a standard 28 bit address. + * Description: Remove an address filter for a standard 29 bit address. * Argument: The filter index previously returned by the * CANIOC_ADD_EXTFILTER command * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR) @@ -2831,12 +2924,16 @@ static int mcan_hw_initialize(struct sam_mcan_s *priv) regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); - /* Global Filter Configuration: Reject remote frames, reject non-matching - * frames. + /* Global Filter Configuration: + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + * ANFE=0: Store all rejected extended frame in RX FIFO0 + * FFSE=1: Reject all remote frames with 11-bit standard IDs. + * RRFE=1: Reject all remote frames with 29-bit extended IDs. */ - regval = MCAN_GFC_RRFE | MCAN_GFC_RRFS | MCAN_GFC_ANFE_REJECTED | - MCAN_GFC_ANFS_REJECTED; + regval = MCAN_GFC_RRFE | MCAN_GFC_RRFS | MCAN_GFC_ANFE_RX_FIFO0 | + MCAN_GFC_ANFS_RX_FIFO0; mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); /* Extended ID Filter AND mask */