Linux CAN drivers development
 help / color / mirror / Atom feed
From: Torin Cooper-Bennun <torin@maxiluxsystems.com>
To: linux-can@vger.kernel.org
Cc: Marc Kleine-Budde <mkl@pengutronix.de>,
	Pankaj Sharma <pankj.sharma@samsung.com>,
	Torin Cooper-Bennun <torin@maxiluxsystems.com>
Subject: [PATCH 3/3] can: m_can: fix RX path: use rx-offload to ensure skbs are sent from softirq context
Date: Fri,  5 Mar 2021 17:20:15 +0000	[thread overview]
Message-ID: <20210305172015.1506525-4-torin@maxiluxsystems.com> (raw)
In-Reply-To: <20210305172015.1506525-1-torin@maxiluxsystems.com>

For peripheral devices, m_can sent skbs directly from a threaded irq
instead of from a softirq context. This patch transitions the driver to
use the rx-offload helper, ensuring the skbs are sent from the correct
context, with h/w timestamping to ensure correct ordering.

Signed-off-by: Torin Cooper-Bennun <torin@maxiluxsystems.com>
---
 drivers/net/can/m_can/m_can.c | 50 ++++++++++++++++++++++++++---------
 drivers/net/can/m_can/m_can.h |  2 ++
 2 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 83a673417e7c..ebdec9c6c0b5 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -467,7 +467,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
 	struct m_can_classdev *cdev = netdev_priv(dev);
 	struct canfd_frame *cf;
 	struct sk_buff *skb;
-	u32 id, fgi, dlc;
+	u32 id, fgi, dlc, timestamp;
 	int i;
 
 	/* calculate the fifo get index for where to read data */
@@ -516,7 +516,9 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
 	stats->rx_packets++;
 	stats->rx_bytes += cf->len;
 
-	netif_receive_skb(skb);
+	timestamp = ((dlc & RX_BUF_RXTS_MASK) >> RX_BUF_RXTS_SHIFT) << 16;
+
+	can_rx_offload_queue_sorted(&cdev->offload, skb, timestamp);
 }
 
 static int m_can_do_rx_poll(struct net_device *dev, int quota)
@@ -547,6 +549,7 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota)
 
 static int m_can_handle_lost_msg(struct net_device *dev)
 {
+	struct m_can_classdev *cdev = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	struct sk_buff *skb;
 	struct can_frame *frame;
@@ -563,7 +566,8 @@ static int m_can_handle_lost_msg(struct net_device *dev)
 	frame->can_id |= CAN_ERR_CRTL;
 	frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
 
-	netif_receive_skb(skb);
+	can_rx_offload_queue_sorted(&cdev->offload, skb,
+				    m_can_get_timestamp(cdev));
 
 	return 1;
 }
@@ -620,7 +624,8 @@ static int m_can_handle_lec_err(struct net_device *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->len;
-	netif_receive_skb(skb);
+	can_rx_offload_queue_sorted(&cdev->offload, skb,
+				    m_can_get_timestamp(cdev));
 
 	return 1;
 }
@@ -739,7 +744,8 @@ static int m_can_handle_state_change(struct net_device *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->len;
-	netif_receive_skb(skb);
+	can_rx_offload_queue_sorted(&cdev->offload, skb,
+				    m_can_get_timestamp(cdev));
 
 	return 1;
 }
@@ -825,7 +831,8 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
 		netdev_dbg(dev, "allocation of skb failed\n");
 		return 0;
 	}
-	netif_receive_skb(skb);
+	can_rx_offload_queue_sorted(&cdev->offload, skb,
+				    m_can_get_timestamp(cdev));
 
 	return 1;
 }
@@ -926,6 +933,19 @@ static int m_can_poll(struct napi_struct *napi, int quota)
 	return work_done;
 }
 
+static void m_can_tx_update_stats(struct m_can_classdev *cdev,
+				  unsigned int msg_mark)
+{
+	struct net_device_stats *stats = &cdev->net->stats;
+
+	stats->tx_bytes +=
+		can_rx_offload_get_echo_skb(&cdev->offload,
+					    msg_mark,
+					    m_can_get_timestamp(cdev),
+					    NULL);
+	stats->tx_packets++;
+}
+
 static void m_can_echo_tx_event(struct net_device *dev)
 {
 	u32 txe_count = 0;
@@ -935,7 +955,6 @@ static void m_can_echo_tx_event(struct net_device *dev)
 	unsigned int msg_mark;
 
 	struct m_can_classdev *cdev = netdev_priv(dev);
-	struct net_device_stats *stats = &dev->stats;
 
 	/* read tx event fifo status */
 	m_can_txefs = m_can_read(cdev, M_CAN_TXEFS);
@@ -958,8 +977,7 @@ static void m_can_echo_tx_event(struct net_device *dev)
 						(fgi << TXEFA_EFAI_SHIFT)));
 
 		/* update stats */
-		stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
-		stats->tx_packets++;
+		m_can_tx_update_stats(cdev, msg_mark);
 	}
 }
 
@@ -967,7 +985,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
 	struct m_can_classdev *cdev = netdev_priv(dev);
-	struct net_device_stats *stats = &dev->stats;
 	u32 ir;
 
 	if (pm_runtime_suspended(cdev->dev))
@@ -1000,8 +1017,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
 	if (cdev->version == 30) {
 		if (ir & IR_TC) {
 			/* Transmission Complete Interrupt*/
-			stats->tx_bytes += can_get_echo_skb(dev, 0, NULL);
-			stats->tx_packets++;
+			m_can_tx_update_stats(cdev, 0);
 			can_led_event(dev, CAN_LED_EVENT_TX);
 			netif_wake_queue(dev);
 		}
@@ -1463,6 +1479,7 @@ static int m_can_close(struct net_device *dev)
 		cdev->tx_wq = NULL;
 	}
 
+	can_rx_offload_disable(&cdev->offload);
 	close_candev(dev);
 	can_led_event(dev, CAN_LED_EVENT_STOP);
 
@@ -1661,6 +1678,8 @@ static int m_can_open(struct net_device *dev)
 		goto exit_disable_clks;
 	}
 
+	can_rx_offload_enable(&cdev->offload);
+
 	/* register interrupt handler */
 	if (cdev->is_peripheral) {
 		cdev->tx_skb = NULL;
@@ -1702,6 +1721,7 @@ static int m_can_open(struct net_device *dev)
 	if (cdev->is_peripheral)
 		destroy_workqueue(cdev->tx_wq);
 out_wq_fail:
+	can_rx_offload_disable(&cdev->offload);
 	close_candev(dev);
 exit_disable_clks:
 	m_can_clk_stop(cdev);
@@ -1855,6 +1875,11 @@ int m_can_class_register(struct m_can_classdev *cdev)
 			return ret;
 	}
 
+	ret = can_rx_offload_add_manual(cdev->net, &cdev->offload,
+					M_CAN_NAPI_WEIGHT);
+	if (ret)
+		goto clk_disable;
+
 	ret = m_can_dev_setup(cdev);
 	if (ret)
 		goto clk_disable;
@@ -1885,6 +1910,7 @@ EXPORT_SYMBOL_GPL(m_can_class_register);
 
 void m_can_class_unregister(struct m_can_classdev *cdev)
 {
+	can_rx_offload_del(&cdev->offload);
 	unregister_candev(cdev->net);
 }
 EXPORT_SYMBOL_GPL(m_can_class_unregister);
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index 3fda84cef351..ace071c3e58c 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -8,6 +8,7 @@
 
 #include <linux/can/core.h>
 #include <linux/can/led.h>
+#include <linux/can/rx-offload.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
@@ -71,6 +72,7 @@ struct m_can_ops {
 
 struct m_can_classdev {
 	struct can_priv can;
+	struct can_rx_offload offload;
 	struct napi_struct napi;
 	struct net_device *net;
 	struct device *dev;
-- 
2.30.1


  parent reply	other threads:[~2021-03-05 17:22 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-05 17:20 [PATCH 0/3] can: m_can: stabilise peripheral m_can RX and TX Torin Cooper-Bennun
2021-03-05 17:20 ` [PATCH 1/3] can: m_can: add infrastructure for internal timestamps Torin Cooper-Bennun
2021-03-05 21:28   ` Marc Kleine-Budde
2021-03-05 17:20 ` [PATCH 2/3] can: m_can: m_can_chip_config(): enable and configure " Torin Cooper-Bennun
2021-03-05 21:34   ` Marc Kleine-Budde
2021-03-08  9:09     ` Torin Cooper-Bennun
2021-03-05 17:20 ` Torin Cooper-Bennun [this message]
2021-03-05 22:29   ` [PATCH 3/3] can: m_can: fix RX path: use rx-offload to ensure skbs are sent from softirq context Marc Kleine-Budde
2021-03-08  9:11     ` Torin Cooper-Bennun
2021-03-08  9:16       ` Marc Kleine-Budde
2021-03-08 10:31         ` Torin Cooper-Bennun

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=20210305172015.1506525-4-torin@maxiluxsystems.com \
    --to=torin@maxiluxsystems.com \
    --cc=linux-can@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=pankj.sharma@samsung.com \
    /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