Commit 137f59d5 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde
Browse files

can: at91_can: switch to rx-offload implementation

The current at91_can driver uses NAPI to handle RX'ed CAN frames, the
RX IRQ is disabled and a NAPI poll is scheduled. Then in
at91_poll_rx() the RX'ed CAN frames are tried to read in order from
the device.

This approach has 2 drawbacks:

- Under high system load it might take too long from the initial RX
  IRQ to the NAPI poll function to run. This causes RX buffer
  overflows.
- The algorithm to read the CAN frames in order is not bullet proof
  and may fail under certain use cases/system loads.

The rx-offload helper fixes these problems by reading the RX'ed CAN
frames in the interrupt handler and adding it to a list sorted by RX
timestamp. This list of RX'ed SKBs is then passed to the networking
stack via NAPI.

Convert the RX path to rx-offload, pass all CAN error frames with
can_rx_offload_queue_timestamp().

Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-27-9987d53600e0@pengutronix.de


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent dd94a2f1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ config CAN_RX_OFFLOAD
config CAN_AT91
	tristate "Atmel AT91 onchip CAN controller"
	depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
	select CAN_RX_OFFLOAD
	help
	  This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
	  and AT91SAM9X5 processors.
+99 −241
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 * at91_can.c - CAN network driver for AT91 SoC CAN controller
 *
 * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
 * (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde <kernel@pengutronix.de>
 * (C) 2008, 2009, 2010, 2011, 2023 by Marc Kleine-Budde <kernel@pengutronix.de>
 */

#include <linux/bitfield.h>
@@ -26,6 +26,7 @@

#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/rx-offload.h>

#define AT91_MB_MASK(i) ((1 << (i)) - 1)

@@ -142,7 +143,6 @@ enum at91_devtype {

struct at91_devtype_data {
	unsigned int rx_first;
	unsigned int rx_split;
	unsigned int rx_last;
	unsigned int tx_shift;
	enum at91_devtype type;
@@ -150,14 +150,13 @@ struct at91_devtype_data {

struct at91_priv {
	struct can_priv can;		/* must be the first member! */
	struct napi_struct napi;
	struct can_rx_offload offload;
	struct phy *transceiver;

	void __iomem *reg_base;

	unsigned int tx_head;
	unsigned int tx_tail;
	unsigned int rx_next;
	struct at91_devtype_data devtype_data;

	struct clk *clk;
@@ -166,9 +165,13 @@ struct at91_priv {
	canid_t mb0_id;
};

static inline struct at91_priv *rx_offload_to_priv(struct can_rx_offload *offload)
{
	return container_of(offload, struct at91_priv, offload);
}

static const struct at91_devtype_data at91_at91sam9263_data = {
	.rx_first = 1,
	.rx_split = 8,
	.rx_last = 11,
	.tx_shift = 2,
	.type = AT91_DEVTYPE_SAM9263,
@@ -176,7 +179,6 @@ static const struct at91_devtype_data at91_at91sam9263_data = {

static const struct at91_devtype_data at91_at91sam9x5_data = {
	.rx_first = 0,
	.rx_split = 4,
	.rx_last = 5,
	.tx_shift = 1,
	.type = AT91_DEVTYPE_SAM9X5,
@@ -213,27 +215,6 @@ static inline unsigned int get_mb_rx_last(const struct at91_priv *priv)
	return priv->devtype_data.rx_last;
}

static inline unsigned int get_mb_rx_split(const struct at91_priv *priv)
{
	return priv->devtype_data.rx_split;
}

static inline unsigned int get_mb_rx_num(const struct at91_priv *priv)
{
	return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1;
}

static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv)
{
	return get_mb_rx_split(priv) - 1;
}

static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv)
{
	return AT91_MB_MASK(get_mb_rx_split(priv)) &
		~AT91_MB_MASK(get_mb_rx_first(priv));
}

static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv)
{
	return priv->devtype_data.tx_shift;
@@ -374,9 +355,8 @@ static void at91_setup_mailboxes(struct net_device *dev)
	for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++)
		set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);

	/* Reset tx and rx helper pointers */
	/* Reset tx helper pointers */
	priv->tx_head = priv->tx_tail = 0;
	priv->rx_next = get_mb_rx_first(priv);
}

static int at91_set_bittiming(struct net_device *dev)
@@ -548,34 +528,6 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
	return NETDEV_TX_OK;
}

/**
 * at91_activate_rx_low - activate lower rx mailboxes
 * @priv: a91 context
 *
 * Reenables the lower mailboxes for reception of new CAN messages
 */
static inline void at91_activate_rx_low(const struct at91_priv *priv)
{
	u32 mask = get_mb_rx_low_mask(priv);

	at91_write(priv, AT91_TCR, mask);
}

/**
 * at91_activate_rx_mb - reactive single rx mailbox
 * @priv: a91 context
 * @mb: mailbox to reactivate
 *
 * Reenables given mailbox for reception of new CAN messages
 */
static inline void at91_activate_rx_mb(const struct at91_priv *priv,
				       unsigned int mb)
{
	u32 mask = 1 << mb;

	at91_write(priv, AT91_TCR, mask);
}

static inline u32 at91_get_timestamp(const struct at91_priv *priv)
{
	return at91_read(priv, AT91_TIM);
@@ -600,37 +552,60 @@ static void at91_rx_overflow_err(struct net_device *dev)
{
	struct net_device_stats *stats = &dev->stats;
	struct sk_buff *skb;
	struct at91_priv *priv = netdev_priv(dev);
	struct can_frame *cf;
	u32 timestamp;
	int err;

	netdev_dbg(dev, "RX buffer overflow\n");
	stats->rx_over_errors++;
	stats->rx_errors++;

	skb = alloc_can_err_skb(dev, &cf);
	skb = at91_alloc_can_err_skb(dev, &cf, &timestamp);
	if (unlikely(!skb))
		return;

	cf->can_id |= CAN_ERR_CRTL;
	cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;

	netif_receive_skb(skb);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	if (err)
		stats->rx_fifo_errors++;
}

/**
 * at91_read_mb - read CAN msg from mailbox (lowlevel impl)
 * @dev: net device
 * at91_mailbox_read - read CAN msg from mailbox
 * @offload: rx-offload
 * @mb: mailbox number to read from
 * @cf: can frame where to store message
 * @timestamp: pointer to 32 bit timestamp
 * @drop: true indicated mailbox to mark as read and drop frame
 *
 * Reads a CAN message from the given mailbox and stores data into
 * given can frame. "mb" and "cf" must be valid.
 * Reads a CAN message from the given mailbox if not empty.
 */
static void at91_read_mb(struct net_device *dev, unsigned int mb,
			 struct can_frame *cf)
static struct sk_buff *at91_mailbox_read(struct can_rx_offload *offload,
					 unsigned int mb, u32 *timestamp,
					 bool drop)
{
	const struct at91_priv *priv = netdev_priv(dev);
	const struct at91_priv *priv = rx_offload_to_priv(offload);
	struct can_frame *cf;
	struct sk_buff *skb;
	u32 reg_msr, reg_mid;

	reg_msr = at91_read(priv, AT91_MSR(mb));
	if (!(reg_msr & AT91_MSR_MRDY))
		return NULL;

	if (unlikely(drop)) {
		skb = ERR_PTR(-ENOBUFS);
		goto mark_as_read;
	}

	skb = alloc_can_skb(offload->dev, &cf);
	if (unlikely(!skb)) {
		skb = ERR_PTR(-ENOMEM);
		goto mark_as_read;
	}

	reg_mid = at91_read(priv, AT91_MID(mb));
	if (reg_mid & AT91_MID_MIDE)
		cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK | AT91_MID_MIDVB_MASK, reg_mid) |
@@ -638,7 +613,9 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
	else
		cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK, reg_mid);

	reg_msr = at91_read(priv, AT91_MSR(mb));
	/* extend timestamp to full 32 bit */
	*timestamp = FIELD_GET(AT91_MSR_MTIMESTAMP_MASK, reg_msr) << 16;

	cf->len = can_cc_dlc2len(FIELD_GET(AT91_MSR_MDLC_MASK, reg_msr));

	if (reg_msr & AT91_MSR_MRTR) {
@@ -652,151 +629,12 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
	at91_write(priv, AT91_MID(mb), AT91_MID_MIDE);

	if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI))
		at91_rx_overflow_err(dev);
}

/**
 * at91_read_msg - read CAN message from mailbox
 * @dev: net device
 * @mb: mail box to read from
 *
 * Reads a CAN message from given mailbox, and put into linux network
 * RX queue, does all housekeeping chores (stats, ...)
 */
static void at91_read_msg(struct net_device *dev, unsigned int mb)
{
	struct net_device_stats *stats = &dev->stats;
	struct can_frame *cf;
	struct sk_buff *skb;

	skb = alloc_can_skb(dev, &cf);
	if (unlikely(!skb)) {
		stats->rx_dropped++;
		return;
	}

	at91_read_mb(dev, mb, cf);
		at91_rx_overflow_err(offload->dev);

	stats->rx_packets++;
	if (!(cf->can_id & CAN_RTR_FLAG))
		stats->rx_bytes += cf->len;
 mark_as_read:
	at91_write(priv, AT91_MCR(mb), AT91_MCR_MTCR);

	netif_receive_skb(skb);
}

/**
 * at91_poll_rx - read multiple CAN messages from mailboxes
 * @dev: net device
 * @quota: max number of pkgs we're allowed to receive
 *
 * Theory of Operation:
 *
 * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last())
 * on the chip are reserved for RX. We split them into 2 groups. The
 * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last().
 *
 * Like it or not, but the chip always saves a received CAN message
 * into the first free mailbox it finds (starting with the
 * lowest). This makes it very difficult to read the messages in the
 * right order from the chip. This is how we work around that problem:
 *
 * The first message goes into mb nr. 1 and issues an interrupt. All
 * rx ints are disabled in the interrupt handler and a napi poll is
 * scheduled. We read the mailbox, but do _not_ re-enable the mb (to
 * receive another message).
 *
 *    lower mbxs      upper
 *     ____^______    __^__
 *    /           \  /     \
 * +-+-+-+-+-+-+-+-++-+-+-+-+
 * | |x|x|x|x|x|x|x|| | | | |
 * +-+-+-+-+-+-+-+-++-+-+-+-+
 *  0 0 0 0 0 0  0 0 0 0 1 1  \ mail
 *  0 1 2 3 4 5  6 7 8 9 0 1  / box
 *  ^
 *  |
 *   \
 *     unused, due to chip bug
 *
 * The variable priv->rx_next points to the next mailbox to read a
 * message from. As long we're in the lower mailboxes we just read the
 * mailbox but not re-enable it.
 *
 * With completion of the last of the lower mailboxes, we re-enable the
 * whole first group, but continue to look for filled mailboxes in the
 * upper mailboxes. Imagine the second group like overflow mailboxes,
 * which takes CAN messages if the lower goup is full. While in the
 * upper group we re-enable the mailbox right after reading it. Giving
 * the chip more room to store messages.
 *
 * After finishing we look again in the lower group if we've still
 * quota.
 *
 */
static int at91_poll_rx(struct net_device *dev, int quota)
{
	struct at91_priv *priv = netdev_priv(dev);
	u32 reg_sr = at91_read(priv, AT91_SR);
	const unsigned long *addr = (unsigned long *)&reg_sr;
	unsigned int mb;
	int received = 0;

	if (priv->rx_next > get_mb_rx_low_last(priv) &&
	    reg_sr & get_mb_rx_low_mask(priv))
		netdev_info(dev,
			    "order of incoming frames cannot be guaranteed\n");

 again:
	for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next);
	     mb < get_mb_tx_first(priv) && quota > 0;
	     reg_sr = at91_read(priv, AT91_SR),
	     mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) {
		at91_read_msg(dev, mb);

		/* reactivate mailboxes */
		if (mb == get_mb_rx_low_last(priv))
			/* all lower mailboxed, if just finished it */
			at91_activate_rx_low(priv);
		else if (mb > get_mb_rx_low_last(priv))
			/* only the mailbox we read */
			at91_activate_rx_mb(priv, mb);

		received++;
		quota--;
	}

	/* upper group completed, look again in lower */
	if (priv->rx_next > get_mb_rx_low_last(priv) &&
	    mb > get_mb_rx_last(priv)) {
		priv->rx_next = get_mb_rx_first(priv);
		if (quota > 0)
			goto again;
	}

	return received;
}

static int at91_poll(struct napi_struct *napi, int quota)
{
	struct net_device *dev = napi->dev;
	const struct at91_priv *priv = netdev_priv(dev);
	u32 reg_sr = at91_read(priv, AT91_SR);
	int work_done = 0;

	if (reg_sr & get_irq_mb_rx(priv))
		work_done += at91_poll_rx(dev, quota - work_done);

	if (work_done < quota) {
		/* enable IRQs for frame errors and all mailboxes >= rx_next */
		u32 reg_ier = AT91_IRQ_ERR_FRAME;

		reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next);

		napi_complete_done(napi, work_done);
		at91_write(priv, AT91_IER, reg_ier);
	}

	return work_done;
	return skb;
}

/* theory of operation:
@@ -816,8 +654,6 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
	u32 reg_msr;
	unsigned int mb;

	/* masking of reg_sr not needed, already done by at91_irq */

	for (/* nix */; (priv->tx_head - priv->tx_tail) > 0; priv->tx_tail++) {
		mb = get_tx_tail_mb(priv);

@@ -855,11 +691,14 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)

static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr)
{
	struct net_device_stats *stats = &dev->stats;
	enum can_state new_state, rx_state, tx_state;
	struct at91_priv *priv = netdev_priv(dev);
	struct can_berr_counter bec;
	struct sk_buff *skb;
	struct can_frame *cf;
	u32 timestamp;
	int err;

	at91_get_berr_counter(dev, &bec);
	can_state_get_by_berr_counter(dev, &bec, &tx_state, &rx_state);
@@ -889,7 +728,7 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr)
	/* The skb allocation might fail, but can_change_state()
	 * handles cf == NULL.
	 */
	skb = alloc_can_err_skb(dev, &cf);
	skb = at91_alloc_can_err_skb(dev, &cf, &timestamp);
	can_change_state(dev, cf, tx_state, rx_state);

	if (new_state == CAN_STATE_BUS_OFF) {
@@ -906,19 +745,23 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr)
		cf->data[7] = bec.rxerr;
	}

	netif_rx(skb);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	if (err)
		stats->rx_fifo_errors++;
}

static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr)
{
	struct net_device_stats *stats = &dev->stats;
	struct at91_priv *priv = netdev_priv(dev);
	struct can_frame *cf;
	struct sk_buff *skb;
	struct can_frame *cf = NULL;
	u32 timestamp;
	int err;

	priv->can.can_stats.bus_error++;

	skb = alloc_can_err_skb(dev, &cf);
	skb = at91_alloc_can_err_skb(dev, &cf, &timestamp);
	if (cf)
		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;

@@ -967,50 +810,62 @@ static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr)
	if (!cf)
		return;

	netif_receive_skb(skb);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	if (err)
		stats->rx_fifo_errors++;
}

static u32 at91_get_reg_sr_rx(const struct at91_priv *priv, u32 *reg_sr_p)
{
	const u32 reg_sr = at91_read(priv, AT91_SR);

	*reg_sr_p |= reg_sr;

	return reg_sr & get_irq_mb_rx(priv);
}

/* interrupt handler
 */
static irqreturn_t at91_irq(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct at91_priv *priv = netdev_priv(dev);
	irqreturn_t handled = IRQ_NONE;
	u32 reg_sr, reg_imr;

	reg_sr = at91_read(priv, AT91_SR);
	reg_imr = at91_read(priv, AT91_IMR);

	/* Ignore masked interrupts */
	reg_sr &= reg_imr;
	if (!reg_sr)
		goto exit;
	u32 reg_sr = 0, reg_sr_rx;
	int ret;

	/* Receive interrupt
	 * Some bits of AT91_SR are cleared on read, keep them in reg_sr.
	 */
	while ((reg_sr_rx = at91_get_reg_sr_rx(priv, &reg_sr))) {
		ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
							   reg_sr_rx);
		handled = IRQ_HANDLED;

	/* Receive interrupt? -> napi */
	if (reg_sr & get_irq_mb_rx(priv)) {
		at91_write(priv, AT91_IDR,
			   get_irq_mb_rx(priv));
		napi_schedule(&priv->napi);
		if (!ret)
			break;
	}

	/* Transmission complete interrupt */
	if (reg_sr & get_irq_mb_tx(priv))
	if (reg_sr & get_irq_mb_tx(priv)) {
		at91_irq_tx(dev, reg_sr);
		handled = IRQ_HANDLED;
	}

	/* Line Error interrupt */
	if (reg_sr & AT91_IRQ_ERR_LINE ||
	    priv->can.state > CAN_STATE_ERROR_ACTIVE) {
		at91_irq_err_line(dev, reg_sr);
		handled = IRQ_HANDLED;
	}

	/* Frame Error Interrupt */
	if (reg_sr & AT91_IRQ_ERR_FRAME)
	if (reg_sr & AT91_IRQ_ERR_FRAME) {
		at91_irq_err_frame(dev, reg_sr);
		handled = IRQ_HANDLED;
	}

	if (handled)
		can_rx_offload_irq_finish(&priv->offload);

 exit:
	return handled;
}

@@ -1040,7 +895,7 @@ static int at91_open(struct net_device *dev)

	/* start chip and queuing */
	at91_chip_start(dev);
	napi_enable(&priv->napi);
	can_rx_offload_enable(&priv->offload);
	netif_start_queue(dev);

	return 0;
@@ -1062,7 +917,7 @@ static int at91_close(struct net_device *dev)
	struct at91_priv *priv = netdev_priv(dev);

	netif_stop_queue(dev);
	napi_disable(&priv->napi);
	can_rx_offload_disable(&priv->offload);
	at91_chip_stop(dev, CAN_STATE_STOPPED);

	free_irq(dev->irq, dev);
@@ -1265,8 +1120,11 @@ static int at91_can_probe(struct platform_device *pdev)
	priv->clk = clk;
	priv->pdata = dev_get_platdata(&pdev->dev);
	priv->mb0_id = 0x7ff;
	priv->offload.mailbox_read = at91_mailbox_read;
	priv->offload.mb_first = devtype_data->rx_first;
	priv->offload.mb_last = devtype_data->rx_last;

	netif_napi_add_weight(dev, &priv->napi, at91_poll, get_mb_rx_num(priv));
	can_rx_offload_add_timestamp(dev, &priv->offload);

	if (transceiver)
		priv->can.bitrate_max = transceiver->attrs.max_link_rate;