diff mbox

[v2,5/5] can: flexcan: Add support for non RX-FIFO mode

Message ID 1431603215-25546-6-git-send-email-bhupesh.sharma@freescale.com (mailing list archive)
State New, archived
Headers show

Commit Message

bhupesh.sharma@freescale.com May 14, 2015, 11:33 a.m. UTC
This patch adds support for non RX-FIFO (legacy) mode in
the flexcan driver.

On certain SoCs, the RX-FIFO support might be broken, as
a result we need to fall-back on the legacy (non RX-FIFO)
mode to receive CAN frames.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
---
 drivers/net/can/flexcan.c |  188 +++++++++++++++++++++++++++++++++------------
 1 file changed, 138 insertions(+), 50 deletions(-)

Comments

Marc Kleine-Budde May 14, 2015, 3:41 p.m. UTC | #1
On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
> This patch adds support for non RX-FIFO (legacy) mode in
> the flexcan driver.
> 
> On certain SoCs, the RX-FIFO support might be broken, as
> a result we need to fall-back on the legacy (non RX-FIFO)
> mode to receive CAN frames.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
> Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>

The non FIFO mode doesn't guarantee the order of the incoming frames,
not does not even try to...this is not acceptable. I'm currently working
on a patch by David Jander that brings in non FIFO mode, but tries to
keep the order of the frames.

Marc
bhupesh.sharma@freescale.com May 14, 2015, 3:44 p.m. UTC | #2
> -----Original Message-----
> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> Sent: Thursday, May 14, 2015 9:12 PM
> To: Sharma Bhupesh-B45370; arnd@arndb.de; linux-can@vger.kernel.org
> Cc: bhupesh.linux@gmail.com; Arora Sakar-B45205; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO
> mode
> 
> On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
> > This patch adds support for non RX-FIFO (legacy) mode in the flexcan
> > driver.
> >
> > On certain SoCs, the RX-FIFO support might be broken, as a result we
> > need to fall-back on the legacy (non RX-FIFO) mode to receive CAN
> > frames.
> >
> > Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
> > Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
> 
> The non FIFO mode doesn't guarantee the order of the incoming frames, not
> does not even try to...this is not acceptable. I'm currently working on a
> patch by David Jander that brings in non FIFO mode, but tries to keep the
> order of the frames.

That is already WIP at our end. V3 will contain the same change.
If you are already working on it, I don't know how to proceed further
as we had already v1 of this patchset with the non FIFO mode out
since a month or so.

Regards,
Bhupesh
Tom Evans May 15, 2015, 12:09 a.m. UTC | #3
On 15/05/15 01:41, Marc Kleine-Budde wrote:
> On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
>> This patch adds support for non RX-FIFO (legacy) mode in
>> the flexcan driver.
>>
>> On certain SoCs, the RX-FIFO support might be broken, as
>> a result we need to fall-back on the legacy (non RX-FIFO)
>> mode to receive CAN frames.
>>
>> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
>> Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
>
> The non FIFO mode doesn't guarantee the order of the incoming frames,
> not does not even try to...this is not acceptable. I'm currently working
> on a patch by David Jander that brings in non FIFO mode, but tries to
> keep the order of the frames.
>
> Marc

In case it is of any help as a reference, here's a thread on the problems of 
receiving messages in order on another non-FIFO chip. This applies to the 
normal Microchip CAN controllers, in this case the very-hard-to-program 
on-the-end-of-an-SPI-bus MCP2515:

http://www.microchip.com/forums/tm.aspx?m=620741

It has two receive buffers, and a "rollover" setting. This does not make the 
registers operate as a FIFO and it needs a state machine to keep track of 
which buffer holds which sequence message.

Tom
bhupesh.sharma@freescale.com Dec. 10, 2015, 11:05 a.m. UTC | #4
Hi Mark,

> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-
> bounces@lists.infradead.org] On Behalf Of Sharma Bhupesh
> Sent: Thursday, May 14, 2015 9:14 PM
> To: Marc Kleine-Budde; arnd@arndb.de; linux-can@vger.kernel.org
> Cc: bhupesh.linux@gmail.com; linux-arm-kernel@lists.infradead.org; Arora
> Sakar-B45205
> Subject: RE: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO
> mode
> 
> > -----Original Message-----
> > From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> > Sent: Thursday, May 14, 2015 9:12 PM
> > To: Sharma Bhupesh-B45370; arnd@arndb.de; linux-can@vger.kernel.org
> > Cc: bhupesh.linux@gmail.com; Arora Sakar-B45205; linux-arm-
> > kernel@lists.infradead.org
> > Subject: Re: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO
> > mode
> >
> > On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
> > > This patch adds support for non RX-FIFO (legacy) mode in the flexcan
> > > driver.
> > >
> > > On certain SoCs, the RX-FIFO support might be broken, as a result we
> > > need to fall-back on the legacy (non RX-FIFO) mode to receive CAN
> > > frames.
> > >
> > > Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
> > > Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
> >
> > The non FIFO mode doesn't guarantee the order of the incoming frames,
> > not does not even try to...this is not acceptable. I'm currently
> > working on a patch by David Jander that brings in non FIFO mode, but
> > tries to keep the order of the frames.
> 
> That is already WIP at our end. V3 will contain the same change.
> If you are already working on it, I don't know how to proceed further as
> we had already v1 of this patchset with the non FIFO mode out since a
> month or so.

I don't remember seeing a patch from you which supports non-FIFO mode for flexcan IP.
Since we now have Freescale LS1021A chip out in the field on which the FIFO mode broken,
we cannot use the upstream flexcan driver for enabling flexcan IP on these chips.

Do you still have plans to work on this? Or should I submit my v3 with in-order reception
supported for rx frames.

Regards,
Bhupesh
Marc Kleine-Budde Dec. 10, 2015, 12:19 p.m. UTC | #5
On 12/10/2015 12:05 PM, Sharma Bhupesh wrote:
>>> -----Original Message-----
>>> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
>>> Sent: Thursday, May 14, 2015 9:12 PM
>>> To: Sharma Bhupesh-B45370; arnd@arndb.de; linux-can@vger.kernel.org
>>> Cc: bhupesh.linux@gmail.com; Arora Sakar-B45205; linux-arm-
>>> kernel@lists.infradead.org
>>> Subject: Re: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO
>>> mode
>>>
>>> On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
>>>> This patch adds support for non RX-FIFO (legacy) mode in the flexcan
>>>> driver.
>>>>
>>>> On certain SoCs, the RX-FIFO support might be broken, as a result we
>>>> need to fall-back on the legacy (non RX-FIFO) mode to receive CAN
>>>> frames.
>>>>
>>>> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
>>>> Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
>>>
>>> The non FIFO mode doesn't guarantee the order of the incoming frames,
>>> not does not even try to...this is not acceptable. I'm currently
>>> working on a patch by David Jander that brings in non FIFO mode, but
>>> tries to keep the order of the frames.
>>
>> That is already WIP at our end. V3 will contain the same change.
>> If you are already working on it, I don't know how to proceed further as
>> we had already v1 of this patchset with the non FIFO mode out since a
>> month or so.
> 
> I don't remember seeing a patch from you which supports non-FIFO mode for flexcan IP.
> Since we now have Freescale LS1021A chip out in the field on which the FIFO mode broken,
> we cannot use the upstream flexcan driver for enabling flexcan IP on these chips.
> 
> Do you still have plans to work on this? Or should I submit my v3 with in-order reception
> supported for rx frames.

The problem is, that the current code triggers a ordering issue (at
least on the imx6) in non FIFO mode. The frames are not received as the
documentation states. If you have access, take a look at "SR#
1-4074792564 : CAN Ordering Issues". It seems the freescale support
doesn't have much interest in confirming the issue, nor bringing us in
touch with the people who have access to the IP core source to see
what's going on.

If we have to rely on the timestamps the next logical step is to add
sorting by timestamp to the rx-fifo implementation. I'll send a patch
series of the current state.

regards,
Marc
bhupesh.sharma@freescale.com Dec. 10, 2015, 12:22 p.m. UTC | #6
> -----Original Message-----
> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> Sent: Thursday, December 10, 2015 5:49 PM
> 
> On 12/10/2015 12:05 PM, Sharma Bhupesh wrote:
> >>> -----Original Message-----
> >>> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> >>> Sent: Thursday, May 14, 2015 9:12 PM
> >>> To: Sharma Bhupesh-B45370; arnd@arndb.de; linux-can@vger.kernel.org
> >>> Cc: bhupesh.linux@gmail.com; Arora Sakar-B45205; linux-arm-
> >>> kernel@lists.infradead.org
> >>> Subject: Re: [PATCH v2 5/5] can: flexcan: Add support for non
> >>> RX-FIFO mode
> >>>
> >>> On 05/14/2015 01:33 PM, Bhupesh Sharma wrote:
> >>>> This patch adds support for non RX-FIFO (legacy) mode in the
> >>>> flexcan driver.
> >>>>
> >>>> On certain SoCs, the RX-FIFO support might be broken, as a result
> >>>> we need to fall-back on the legacy (non RX-FIFO) mode to receive
> >>>> CAN frames.
> >>>>
> >>>> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
> >>>> Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
> >>>
> >>> The non FIFO mode doesn't guarantee the order of the incoming
> >>> frames, not does not even try to...this is not acceptable. I'm
> >>> currently working on a patch by David Jander that brings in non FIFO
> >>> mode, but tries to keep the order of the frames.
> >>
> >> That is already WIP at our end. V3 will contain the same change.
> >> If you are already working on it, I don't know how to proceed further
> >> as we had already v1 of this patchset with the non FIFO mode out
> >> since a month or so.
> >
> > I don't remember seeing a patch from you which supports non-FIFO mode
> for flexcan IP.
> > Since we now have Freescale LS1021A chip out in the field on which the
> > FIFO mode broken, we cannot use the upstream flexcan driver for
> enabling flexcan IP on these chips.
> >
> > Do you still have plans to work on this? Or should I submit my v3 with
> > in-order reception supported for rx frames.
> 
> The problem is, that the current code triggers a ordering issue (at least
> on the imx6) in non FIFO mode. The frames are not received as the
> documentation states. If you have access, take a look at "SR#
> 1-4074792564 : CAN Ordering Issues". It seems the freescale support
> doesn't have much interest in confirming the issue, nor bringing us in
> touch with the people who have access to the IP core source to see what's
> going on.
> 
> If we have to rely on the timestamps the next logical step is to add
> sorting by timestamp to the rx-fifo implementation. I'll send a patch
> series of the current state.

With my current v3, I see no rx-frame ordering issues atleast on LS1021A.

I can ask internally about more details on the "SR# 1-4074792564 : CAN Ordering Issues".

Regards,
Bhupesh
Marc Kleine-Budde Dec. 10, 2015, 12:44 p.m. UTC | #7
On 12/10/2015 12:44 PM, Tom Evans wrote:
> I've just had to delve back into the deep murky past and try to get 
> Freescale's Kernel 2.6.35 FlexCAN driver working. That's because the 
> only code base that supports Freescale's Video Hardware is that one and 
> we need working video.

2.6.x I feel your pain. Another option would be to port the flexcan
driver to that old kernel. But I'm getting off topic here :)

> I'm suggesting this code as an "historical reference" that might be 
> useful for anyone looking for simple/simplistic ways to handle a FlexCAN 
> port. It isn't like the driver actually works fully. It can't have ever 
> been tested very much. Which is why I've had to fix it.
> 
> It has the Driver, Register handling and Message Buffer handling split 
> into three separate source files, which is a useful simplification.

YMMV :)

> It can't be configured with "canconfig", but exposes a huge number of 
> variables in the sysfs which is actually quite powerful and extendable.
> 
> Freescale's "2.6.35_maintain" kernel consists of 2.6.35 plus about 1200 
> Freescale patches which basically replace all the hardware drivers.
> 
> The source for this driver in this tree (until someone renames it to NXP):
> 
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/log/?h=imx_2.6.35_maintain
> 
> The Driver is in the expected place:
> 
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/net/can/flexcan?h=imx_2.6.35_maintain
> 
> 1 - It defaults to 32 receive and 32 transmit MBs, but that can be changed.
> 
> 2 - It can't receive in order, but you'd only need to sort on the 
> timestamps to fix that (or use the FIFO).

In order reception is crucial.

> 3 - It can't transmit in order either (unless you drop it to one 
> transmit MB), but a simple change to the Transmit MB assignment would 
> fix that.

Same here.

> 4 - It supports FIFO mode, but it doesn't work at all. The FIFO hardware 
> gets so badly screwed by the driver that it has to be power-cycled to 
> get it working again.
> 
> 5 - Transmit doesn't work either. If you push it it'll start sending ONE 
> Message per SECOND. That's an easy fix by changing the code to actually 
> unblock the netif queue instead of what it does.
> 
> 6 - The sysfs variable that reserves receive message buffers is named to 
> reserve transmit buffers, it messes up if the DLC is over 8 (because it 
> doesn't call get_can_dlc()), the Dump routines don't work properly, 
> off-by-one bug, comparison-reversal bug and so on.
> 
> 7 - The only good thing about it is that it doesn't use NAPI, so when 
> fixed it doesn't drop messages when you try to use MMC/eMMC/ESDHC.
> 
> FIFO bug documented and fixed here:
> 
> https://community.freescale.com/thread/381075
> 
> Transmit bug documented and fixed here (and the other ones listed), also 
> MMC/eMMC problem:
> 
> https://community.freescale.com/message/595897
> 
> Patches to fix all of it on the end of this thread:
> 
> https://community.freescale.com/thread/303271

If there's interest in working with this prehistoric kernel, why isn't
there anyone that picks up all the patches and add them to a git repo.
fsl doesn't seem to care either, maybe unless you're using their newest
product :(

just my 2ยข,
Marc
Tom Evans Dec. 10, 2015, 10:53 p.m. UTC | #8
On 10/12/2015 11:44 PM, Marc Kleine-Budde wrote:
> On 12/10/2015 12:44 PM, Tom Evans wrote:
>> I've just had to delve back into the deep murky past and try to get
>> Freescale's Kernel 2.6.35 FlexCAN driver working...

On an i.MX53. That's the last supported kernel Freescale ever released 
for that series of parts.

> 2.6.x I feel your pain. Another option would be to port the flexcan
> driver to that old kernel. But I'm getting off topic here :)

Been there. Options are to port 2.6.38 (Freescale's Android release) 
which has the 2.6.38 mainstream driver, but looks to have a full 
collection of all the bugs fixed since then. Some kind soul has already 
done that and released a patch (but I don't like the bugs). Or the 3.4 
version we're running with our 3.4 kernel or something more modern. I 
don't trust later versions to even compile - the headers and interfaces 
change. Then I can't use modern ones anyway as they use NAPI and that 
simply doesn't work with Linux and CAN. So I'd have to apply all my 
de-NAPI patches. The simplest path was to fix the simple and stupidly 
obvious bugs in the existing driver rather than add new complicated bugs.

>> 2 - It can't receive in order, but you'd only need to sort on the
>> 3 - It can't transmit in order either (unless you drop it to one
>
> In order reception is crucial.

So what mind-set at Freescale doesn't see this as a problem? I suspect 
their CAN knowledge stopped at the HCS08 stage, making tiny devices that 
control just one thing, like a door lock. So just receive and transmit 
one or two messages where "priority order" is more important than 
running any debug or diagnostic protocols.

>> Patches to fix all of it on the end of this thread:
>>
>> https://community.freescale.com/thread/303271
>
> If there's interest in working with this prehistoric kernel, why isn't
> there anyone that picks up all the patches and add them to a git repo.

There was. That's what the above post is meant to be for. But the last 
actual activity was in January 2013. It details how to submit patches, 
but it is too onerous for me. It has to use their exact complete 
distribution (of everything, not just the kernel) running on their exact 
development board. It also needs your .gitconfig set up "just so" 
matching your Freescale registration details. I'm using the thread as a 
dumping ground for "useful patches for customers", and hope google or 
Freescale's search can find them.

> fsl doesn't seem to care either, maybe unless you're using
 > their newest product :(

The team seems to disappear almost before the product is released. They 
all moved to i.MX6 years ago.

Tom
Robert Schwebel Dec. 11, 2015, 4:01 p.m. UTC | #9
On Thu, Dec 10, 2015 at 12:22:55PM +0000, Sharma Bhupesh wrote:
> > If we have to rely on the timestamps the next logical step is to add
> > sorting by timestamp to the rx-fifo implementation. I'll send a
> > patch series of the current state.
> 
> With my current v3, I see no rx-frame ordering issues atleast on
> LS1021A.

Marc can post our testcases here on the list (maybe with the description
from the service request); perhaps this can clarify the issues.

> I can ask internally about more details on the "SR# 1-4074792564 : CAN
> Ordering Issues".

That would be quite helpful, thanks! Understanding the root cause of the
issue is often a good start, maybe there is an option for a software
workaround.

rsc
Tom Evans Dec. 17, 2015, 4:22 a.m. UTC | #10
On 11/12/15 09:53, Tom Evans wrote:
> On 10/12/2015 11:44 PM, Marc Kleine-Budde wrote:
>> On 12/10/2015 12:44 PM, Tom Evans wrote:
>>> I've just had to delve back into the deep murky past and try to get
>>> Freescale's Kernel 2.6.35 FlexCAN driver working...
>
> On an i.MX53. That's the last supported kernel Freescale ever released for
> that series of parts.

> The simplest path was to fix the
> simple and stupidly obvious bugs in the existing driver rather
 > than add new complicated bugs.

There seems to be no end of bugs in this driver. It is a lesson in something.

What's the dumbest driver bug ever? Interrupt hazard. Yes, this one has that too.

The mainline sends a Message Buffer (or tries to) and DISABLES the netif queue 
if it can't send [1]. The transmit interrupt service routine ENABLES the netif 
queue. And when the interrupt routine happens in the middle of the mainline 
transmit routine? It locks forever. You have to power-cycle to get it back. 
Normally taking the interface "down" and "up" should fix it, as the "start" 
and "stop" functions normally stop and start the netif queue. Not these ones. 
They do now.

Note 1: This is in the case where the transmit queues and MBs are full. The 
transmit function is always called twice. The first time it is called it sends 
the MB, leaves the queue running and return "OK". The second time it finds out 
it is full, stops the queue and returns "BUSY". Even better, with the default 
32 transmit MBs it has to scan through all 32 MBs to find out it is full, and 
it may have also had to scan the same 32 to find an empty one. The FlexCAN 
registers are on a slow bus and take 180ns to read or write. So it can take 
the driver up to 12us to send one buffer. Or proportionally longer if you have 
more Transmit MBs (you might have 56).

If you never send enough data to flow-control the driver this won't happen. If 
you have more than one Transmit MB (and can handle out of order transmissions) 
then the subsequent transmit interrupts will repair the damage and you won't 
see it either. That's probably why it passed whatever testing it had.

Bug detailed here:

https://community.freescale.com/message/597952

Patch to fix here:

https://community.freescale.com/message/597951#597951
Tom
Tom Evans Dec. 23, 2015, 12:53 a.m. UTC | #11
On 17/12/15 15:22, Tom Evans wrote:
> On 11/12/15 09:53, Tom Evans wrote:
>> On 10/12/2015 11:44 PM, Marc Kleine-Budde wrote:
 >>
>> The simplest path was to fix the simple and stupidly obvious
 >> bugs in the existing driver rather than add new complicated bugs.
>
> There seems to be no end of bugs in this driver. It is a lesson
 > in something.

The Bus Off Recovery doesn't work either. A Bus Off condition results in the 
module being soft-reset and then never woken up again, mainly because the 
calls to "mod_timer()" forget to add "jiffies", so the timer doesn't trigger. 
Then the Auto/Manual mode recovery test is probably backwards. Then it tests 
MDIS instead of HALT, so it never resets the module after the soft reset. If 
you program it in "Auto Recovery" mode it resets it anyway.

Bugs detailed here:

https://community.freescale.com/message/599099#599099

There'll probably be a link on that page to the patches to fix it after I've 
tested it some more.

Tom
diff mbox

Patch

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index b0222ae..3240472 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -156,6 +156,9 @@ 
 #define FLEXCAN_IFLAG_DEFAULT \
 	(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
 	 FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE \
+	 (FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_RX_MB_RXMASK	((1 << FLEXCAN_TX_BUF_RESERVED) - 1)
 
 /* FLEXCAN message buffers */
 #define FLEXCAN_MB_CNT_CODE(x)		(((x) & 0xf) << 24)
@@ -198,6 +201,8 @@ 
 #define FLEXCAN_HAS_V10_FEATURES	BIT(1) /* For core version >= 10 */
 #define FLEXCAN_HAS_BROKEN_ERR_STATE	BIT(2) /* [TR]WRN_INT not connected */
 #define FLEXCAN_HAS_MECR_FEATURES	BIT(3) /* Memory error detection */
+#define FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT \
+	 BIT(4) /* No RX FIFO mode support */
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -252,6 +257,7 @@  struct flexcan_priv {
 	void __iomem *base;
 	u32 reg_esr;
 	u32 reg_ctrl_default;
+	u32 rx_msg_buf;
 
 	struct clk *clk_ipg;
 	struct clk *clk_per;
@@ -303,8 +309,7 @@  static const struct can_bittiming_const flexcan_bittiming_const = {
 	.brp_inc = 1,
 };
 
-/*
- * FlexCAN module is essentially modelled as a little-endian IP in most
+/* FlexCAN module is essentially modelled as a little-endian IP in most
  * SoCs, i.e the registers as well as the message buffer areas are
  * implemented in a little-endian fashion.
  *
@@ -646,12 +651,10 @@  static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
 	return 1;
 }
 
-static void flexcan_read_fifo(const struct net_device *dev,
-			      struct can_frame *cf)
+static void flexcan_read_can_frame(const struct flexcan_priv *priv,
+				   struct flexcan_mb __iomem *mb,
+				   struct can_frame *cf)
 {
-	const struct flexcan_priv *priv = netdev_priv(dev);
-	struct flexcan_regs __iomem *regs = priv->base;
-	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
 	u32 reg_ctrl, reg_id;
 
 	reg_ctrl = priv->read(&mb->can_ctrl);
@@ -667,14 +670,39 @@  static void flexcan_read_fifo(const struct net_device *dev,
 
 	*(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0]));
 	*(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1]));
+}
+
+static void flexcan_read_fifo(const struct net_device *dev,
+			      struct can_frame *cf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
+
+	flexcan_read_can_frame(priv, mb, cf);
 
 	/* mark as read */
 	priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
 	priv->read(&regs->timer);
 }
 
+static void flexcan_read_msg_buf(const struct net_device *dev,
+				 struct can_frame *cf, u32 msg_buf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[msg_buf];
+
+	flexcan_read_can_frame(priv, mb, cf);
+
+	/* mark as read */
+	priv->write(BIT(msg_buf), &regs->iflag1);
+	priv->read(&regs->timer);
+}
+
 static int flexcan_read_frame(struct net_device *dev)
 {
+	const struct flexcan_priv *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
@@ -685,7 +713,11 @@  static int flexcan_read_frame(struct net_device *dev)
 		return 0;
 	}
 
-	flexcan_read_fifo(dev, cf);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		flexcan_read_msg_buf(dev, cf, priv->rx_msg_buf);
+	else
+		flexcan_read_fifo(dev, cf);
+
 	netif_receive_skb(skb);
 
 	stats->rx_packets++;
@@ -699,9 +731,10 @@  static int flexcan_read_frame(struct net_device *dev)
 static int flexcan_poll(struct napi_struct *napi, int quota)
 {
 	struct net_device *dev = napi->dev;
-	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->base;
 	u32 reg_iflag1, reg_esr;
+	unsigned long iflag1;
 	int work_done = 0;
 
 	/*
@@ -713,12 +746,25 @@  static int flexcan_poll(struct napi_struct *napi, int quota)
 	/* handle state changes */
 	work_done += flexcan_poll_state(dev, reg_esr);
 
-	/* handle RX-FIFO */
 	reg_iflag1 = priv->read(&regs->iflag1);
-	while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
-	       work_done < quota) {
-		work_done += flexcan_read_frame(dev);
-		reg_iflag1 = priv->read(&regs->iflag1);
+
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* handle legacy RX mode */
+		iflag1 = reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK;
+		while ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) &&
+		       work_done < quota) {
+			priv->rx_msg_buf = find_first_bit(&iflag1,
+						(FLEXCAN_TX_BUF_ID - 1));
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
+	} else {
+		/* handle RX-FIFO */
+		while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
+		       work_done < quota) {
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
 	}
 
 	/* report bus errors */
@@ -728,7 +774,13 @@  static int flexcan_poll(struct napi_struct *napi, int quota)
 	if (work_done < quota) {
 		napi_complete(napi);
 		/* enable IRQs */
-		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+		if (priv->devtype_data->features &
+		    FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+				    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+		else
+			priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+
 		priv->write(priv->reg_ctrl_default, &regs->ctrl);
 	}
 
@@ -755,26 +807,45 @@  static irqreturn_t flexcan_irq(int irq, void *dev_id)
 	 * - state change IRQ
 	 * - bus error IRQ and bus error reporting is activated
 	 */
-	if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
-	    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
-	    flexcan_has_and_handle_berr(priv, reg_esr)) {
-		/*
-		 * The error bits are cleared on read,
-		 * save them for later use.
-		 */
-		priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
-		priv->write(FLEXCAN_IFLAG_DEFAULT &
-			~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
-		priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
-		       &regs->ctrl);
-		napi_schedule(&priv->napi);
-	}
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/* The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE &
+				    ~FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+
+			napi_schedule(&priv->napi);
+		}
+	} else {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/*
+			 * The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT &
+				    ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
+				    &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+			napi_schedule(&priv->napi);
+		}
 
-	/* FIFO overflow */
-	if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
-		priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
-		dev->stats.rx_over_errors++;
-		dev->stats.rx_errors++;
+		/* FIFO overflow */
+		if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
+			priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW,
+				    &regs->iflag1);
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
+		}
 	}
 
 	/* transmission complete interrupt */
@@ -869,7 +940,12 @@  static int flexcan_chip_start(struct net_device *dev)
 	 */
 	reg_mcr = priv->read(&regs->mcr);
 	reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
-	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg_mcr &= ~FLEXCAN_MCR_FEN;
+	else
+		reg_mcr |= FLEXCAN_MCR_FEN;
+
+	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
 		FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
 		FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
 		FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
@@ -966,8 +1042,13 @@  static int flexcan_chip_start(struct net_device *dev)
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
-	/* enable FIFO interrupts */
-	priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		/* enable mb interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+			    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+	else
+		/* enable FIFO interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
 
 	/* print chip status */
 	netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
@@ -1125,22 +1206,29 @@  static int register_flexcandev(struct net_device *dev)
 	if (err)
 		goto out_chip_disable;
 
-	/* set freeze, halt and activate FIFO, restrict register access */
+	/* set freeze, halt and activate FIFO/legacy mode, restrict
+	 * register access
+	 */
 	reg = priv->read(&regs->mcr);
-	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg &= ~FLEXCAN_MCR_FEN;
+	else
+		reg |= FLEXCAN_MCR_FEN;
+
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV;
 	priv->write(reg, &regs->mcr);
 
-	/*
-	 * Currently we only support newer versions of this core
-	 * featuring a RX FIFO. Older cores found on some Coldfire
-	 * derivates are not yet supported.
-	 */
-	reg = priv->read(&regs->mcr);
-	if (!(reg & FLEXCAN_MCR_FEN)) {
-		netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
-		err = -ENODEV;
-		goto out_chip_disable;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* Legacy RX mode*/
+		netdev_info(dev, "Legacy mode (non RX-FIFO) enabled\n");
+	} else {
+		/* RX FIFO mode */
+		reg = priv->read(&regs->mcr);
+		if (!(reg & FLEXCAN_MCR_FEN)) {
+			netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
+			err = -ENODEV;
+			goto out_chip_disable;
+		}
 	}
 
 	err = register_candev(dev);