From: Marc Kleine-Budde <mkl@pengutronix.de>
To: linux-can@vger.kernel.org
Cc: kernel@pengutronix.de, bhupesh.sharma@freescale.com,
Marc Kleine-Budde <mkl@pengutronix.de>,
David Jander <david@protonic.nl>
Subject: [PATCH v2 09/11] can: rx-fifo: introduce software rx-fifo implementation
Date: Thu, 10 Dec 2015 13:33:55 +0100 [thread overview]
Message-ID: <1449750837-11376-10-git-send-email-mkl@pengutronix.de> (raw)
In-Reply-To: <1449750837-11376-1-git-send-email-mkl@pengutronix.de>
This patch adds a software rx-fifo implementation for CAN controllers which
offer only a number of mailboxes, where the incoming message is stored int othe
first free one. Both controllers which start with the lowest or highest free
mailbox are supported.
The mailboxes are copied to a ring buffer during the interrupt and then
transmitted in a NAPI context.
Signed-off-by: David Jander <david@protonic.nl>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rx-fifo.c | 178 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/can/rx-fifo.h | 14 ++++
2 files changed, 192 insertions(+)
diff --git a/drivers/net/can/rx-fifo.c b/drivers/net/can/rx-fifo.c
index 7896a1034588..53c01d3cd157 100644
--- a/drivers/net/can/rx-fifo.c
+++ b/drivers/net/can/rx-fifo.c
@@ -19,6 +19,50 @@
#include <linux/can/dev.h>
#include <linux/can/rx-fifo.h>
+static bool can_rx_fifo_ge(struct can_rx_fifo *fifo, unsigned int a, unsigned int b)
+{
+ if (fifo->inc)
+ return a >= b;
+ else
+ return a <= b;
+}
+
+static bool can_rx_fifo_le(struct can_rx_fifo *fifo, unsigned int a, unsigned int b)
+{
+ if (fifo->inc)
+ return a <= b;
+ else
+ return a >= b;
+}
+
+static unsigned int can_rx_fifo_inc(struct can_rx_fifo *fifo, unsigned int *val)
+{
+ if (fifo->inc)
+ return (*val)++;
+ else
+ return (*val)--;
+}
+
+static u64 can_rx_fifo_mask_low(struct can_rx_fifo *fifo)
+{
+ if (fifo->inc)
+ return ~0LLU >> (64 + fifo->low_first - fifo->high_first)
+ << fifo->low_first;
+ else
+ return ~0LLU >> (64 - fifo->low_first + fifo->high_first)
+ << (fifo->high_first + 1);
+}
+
+static u64 can_rx_fifo_mask_high(struct can_rx_fifo *fifo)
+{
+ if (fifo->inc)
+ return ~0LLU >> (64 + fifo->high_first - fifo->high_last - 1)
+ << fifo->high_first;
+ else
+ return ~0LLU >> (64 - fifo->high_first + fifo->high_last - 1)
+ << fifo->high_last;
+}
+
static int can_rx_fifo_napi_read_frame(struct can_rx_fifo *fifo, int index)
{
struct net_device *dev = fifo->dev;
@@ -109,6 +153,68 @@ static unsigned int can_rx_fifo_offload_one(struct can_rx_fifo *fifo, unsigned i
return ret;
}
+int can_rx_fifo_irq_offload(struct can_rx_fifo *fifo)
+{
+ unsigned int i;
+ unsigned int ret;
+ unsigned int received = 0;
+
+ if (fifo->scan_high_first) {
+ fifo->scan_high_first = false;
+ for (i = fifo->high_first;
+ can_rx_fifo_le(fifo, i, fifo->high_last);
+ can_rx_fifo_inc(fifo, &i)) {
+ received += can_rx_fifo_offload_one(fifo, i);
+ fifo->active |= BIT_ULL(i);
+ fifo->mailbox_enable(fifo, i);
+ }
+ }
+
+ /* Copy and disable FULL MBs */
+ for (i = fifo->low_first;
+ can_rx_fifo_le(fifo, i, fifo->high_last);
+ can_rx_fifo_inc(fifo, &i)) {
+ if (!(fifo->active & BIT_ULL(i)))
+ continue;
+
+ ret = can_rx_fifo_offload_one(fifo, i);
+ if (!ret)
+ break;
+
+ received += ret;
+ fifo->active &= ~BIT_ULL(i);
+ }
+
+ if (can_rx_fifo_ge(fifo, i, fifo->high_first) && fifo->scan_high_first)
+ netdev_warn(fifo->dev, "%s: RX order cannot be guaranteed. (count=%d)\n",
+ __func__, i);
+
+ /* No EMPTY MB in first half? */
+ if (can_rx_fifo_ge(fifo, i, fifo->high_first)) {
+ /* Re-enable all disabled MBs */
+ fifo->active = fifo->mask_low | fifo->mask_high;
+ fifo->mailbox_enable_mask(fifo, fifo->active);
+
+ /* Next time we need to check the second half first */
+ fifo->scan_high_first = true;
+ }
+
+ if (WARN(!received, "%s: No messages found, RX-FIFO out of sync?\n",
+ __func__)) {
+ /* This should only happen if the CAN conroller was
+ * reset, but can_rx_fifo_reset() was not
+ * called. WARN() the user and try to recover. This
+ * may fail and the system may hang though.
+ */
+ can_rx_fifo_reset(fifo);
+ } else {
+ can_rx_fifo_schedule(fifo);
+ }
+
+ return received;
+}
+EXPORT_SYMBOL_GPL(can_rx_fifo_irq_offload);
+
int can_rx_fifo_irq_offload_simple(struct can_rx_fifo *fifo)
{
unsigned int received = 0;
@@ -139,11 +245,72 @@ static int can_rx_fifo_init_ring(struct net_device *dev,
return -ENOMEM;
fifo->ring_head = fifo->ring_tail = 0;
+ can_rx_fifo_reset(fifo);
netif_napi_add(dev, &fifo->napi, can_rx_fifo_napi_poll, weight);
return 0;
}
+static void rx_fifo_enable_mask_default(struct can_rx_fifo *fifo, u64 mask)
+{
+ unsigned int i;
+
+ for (i = fifo->low_first;
+ can_rx_fifo_le(fifo, i, fifo->high_last);
+ can_rx_fifo_inc(fifo, &i)) {
+ if (mask & BIT_ULL(i))
+ fifo->mailbox_enable(fifo, i);
+ }
+}
+
+static void rx_fifo_enable_default(struct can_rx_fifo *fifo, unsigned int mb)
+{
+ fifo->mailbox_enable_mask(fifo, BIT_ULL(mb));
+}
+
+int can_rx_fifo_add(struct net_device *dev, struct can_rx_fifo *fifo)
+{
+ unsigned int weight;
+ int ret;
+
+ if ((fifo->low_first < fifo->high_first) &&
+ (fifo->high_first < fifo->high_last)) {
+ fifo->inc = true;
+ weight = fifo->high_last - fifo->low_first;
+ } else if ((fifo->low_first > fifo->high_first) &&
+ (fifo->high_first > fifo->high_last)) {
+ fifo->inc = false;
+ weight = fifo->low_first - fifo->high_last;
+ } else {
+ return -EINVAL;
+ }
+
+ if ((!fifo->mailbox_enable_mask && !fifo->mailbox_enable) ||
+ !fifo->mailbox_read)
+ return -EINVAL;
+
+ if (!fifo->mailbox_enable_mask)
+ fifo->mailbox_enable_mask = rx_fifo_enable_mask_default;
+ if (!fifo->mailbox_enable)
+ fifo->mailbox_enable = rx_fifo_enable_default;
+
+ /* init variables */
+ fifo->mask_low = can_rx_fifo_mask_low(fifo);
+ fifo->mask_high = can_rx_fifo_mask_high(fifo);
+
+ ret = can_rx_fifo_init_ring(dev, fifo, weight);
+ if (ret)
+ return ret;
+
+ netdev_dbg(dev, "%s: low_first=%d, high_first=%d, high_last=%d\n", __func__,
+ fifo->low_first, fifo->high_first, fifo->high_last);
+ netdev_dbg(dev, "%s: mask_low=0x%016llx mask_high=0x%016llx\n", __func__,
+ fifo->mask_low, fifo->mask_high);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(can_rx_fifo_add);
+
int can_rx_fifo_add_simple(struct net_device *dev, struct can_rx_fifo *fifo, unsigned int weight)
{
if (!fifo->mailbox_read)
@@ -155,6 +322,9 @@ EXPORT_SYMBOL_GPL(can_rx_fifo_add_simple);
void can_rx_fifo_enable(struct can_rx_fifo *fifo)
{
+ can_rx_fifo_reset(fifo);
+ if (fifo->mailbox_enable_mask)
+ fifo->mailbox_enable_mask(fifo, fifo->active);
napi_enable(&fifo->napi);
}
EXPORT_SYMBOL_GPL(can_rx_fifo_enable);
@@ -172,3 +342,11 @@ void can_rx_fifo_del(struct can_rx_fifo *fifo)
kfree(fifo->ring);
}
EXPORT_SYMBOL_GPL(can_rx_fifo_del);
+
+void can_rx_fifo_reset(struct can_rx_fifo *fifo)
+{
+ fifo->scan_high_first = false;
+ fifo->poll_errors = false;
+ fifo->active = fifo->mask_low | fifo->mask_high;
+}
+EXPORT_SYMBOL_GPL(can_rx_fifo_reset);
diff --git a/include/linux/can/rx-fifo.h b/include/linux/can/rx-fifo.h
index fc157f23722c..cd1614118b33 100644
--- a/include/linux/can/rx-fifo.h
+++ b/include/linux/can/rx-fifo.h
@@ -23,25 +23,39 @@
struct can_rx_fifo {
struct net_device *dev;
+ void (*mailbox_enable_mask)(struct can_rx_fifo *fifo, u64 mask);
+ void (*mailbox_enable)(struct can_rx_fifo *fifo, unsigned int mb);
void (*poll_error_interrupts_enable)(struct can_rx_fifo *fifo);
unsigned int (*mailbox_read)(struct can_rx_fifo *fifo, struct can_frame *cf, unsigned int mb);
unsigned int (*poll_pre_read)(struct can_rx_fifo *fifo);
unsigned int (*poll_post_read)(struct can_rx_fifo *fifo);
+ u64 mask_low;
+ u64 mask_high;
+ u64 active;
+
unsigned int ring_size;
unsigned int ring_head;
unsigned int ring_tail;
+ unsigned int low_first;
+ unsigned int high_first;
+ unsigned int high_last;
struct can_frame *ring;
struct can_frame overflow;
struct napi_struct napi;
+ bool inc;
+ bool scan_high_first;
bool poll_errors;
};
+int can_rx_fifo_add(struct net_device *dev, struct can_rx_fifo *fifo);
int can_rx_fifo_add_simple(struct net_device *dev, struct can_rx_fifo *fifo, unsigned int weight);
+int can_rx_fifo_irq_offload(struct can_rx_fifo *fifo);
int can_rx_fifo_irq_offload_simple(struct can_rx_fifo *fifo);
void can_rx_fifo_irq_error(struct can_rx_fifo *fifo);
+void can_rx_fifo_reset(struct can_rx_fifo *fifo);
void can_rx_fifo_del(struct can_rx_fifo *fifo);
void can_rx_fifo_enable(struct can_rx_fifo *fifo);
--
2.6.2
next prev parent reply other threads:[~2015-12-10 12:33 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-10 12:33 [PATCH v2 00/11] RFC: cleanup flexcan driver, introduce and make use of IRQ offloading Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 01/11] can: flexcan: calculate default value for imask1 during runtime Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 02/11] can: flexcan: make TX mailbox selectable " Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 03/11] can: rx-fifo: Add support for simple irq offloading Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 04/11] can: flexcan: make use of rx-fifo's irq_offload_simple Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 05/11] can: flexcan: add missing register definitions Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 06/11] can: flexcan: activate individual RX masking and initialize reg_rximr Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 07/11] can: flexcan: add quirk FLEXCAN_QUIRK_ENABLE_EACEN_RRS Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 08/11] can: flexcan: reg_imask2_default Marc Kleine-Budde
2015-12-10 12:33 ` Marc Kleine-Budde [this message]
2015-12-10 12:33 ` [PATCH v2 10/11] can: flexcan: add support for rx-fifo based software FIFO implementation Marc Kleine-Budde
2015-12-10 12:33 ` [PATCH v2 11/11] can: flexcan: switch imx6 and vf610 to software based fifo Marc Kleine-Budde
[not found] ` <CAOpc7mGK9WEnbowHJONbP-szW7mVQbU46uUPXF8V09omqWLQMA@mail.gmail.com>
2015-12-10 14:04 ` [PATCH v2 00/11] RFC: cleanup flexcan driver, introduce and make use of IRQ offloading Marc Kleine-Budde
2016-01-18 11:14 ` Holger Schurig
2016-01-18 22:04 ` Marc Kleine-Budde
2016-01-19 0:26 ` Tom Evans
2016-02-22 15:16 ` Mirza Krak
2016-02-22 15:19 ` Marc Kleine-Budde
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1449750837-11376-10-git-send-email-mkl@pengutronix.de \
--to=mkl@pengutronix.de \
--cc=bhupesh.sharma@freescale.com \
--cc=david@protonic.nl \
--cc=kernel@pengutronix.de \
--cc=linux-can@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).