netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, linux-can@vger.kernel.org,
	kernel@pengutronix.de,
	Torin Cooper-Bennun <torin@maxiluxsystems.com>,
	Marc Kleine-Budde <mkl@pengutronix.de>
Subject: [net-next 20/39] can: m_can: fix periph RX path: use rx-offload to ensure skbs are sent from softirq context
Date: Tue, 30 Mar 2021 13:45:40 +0200	[thread overview]
Message-ID: <20210330114559.1114855-21-mkl@pengutronix.de> (raw)
In-Reply-To: <20210330114559.1114855-1-mkl@pengutronix.de>

From: Torin Cooper-Bennun <torin@maxiluxsystems.com>

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

Link: https://lore.kernel.org/r/20210308102427.63916-4-torin@maxiluxsystems.com
Signed-off-by: Torin Cooper-Bennun <torin@maxiluxsystems.com>
[mkl: m_can_class_register(): update error handling]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/m_can/m_can.c | 121 +++++++++++++++++++++++++++++-----
 drivers/net/can/m_can/m_can.h |   2 +
 2 files changed, 107 insertions(+), 16 deletions(-)

diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 7df81e38b043..890ed826a355 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -457,6 +457,21 @@ static void m_can_clean(struct net_device *net)
 	}
 }
 
+/* For peripherals, pass skb to rx-offload, which will push skb from
+ * napi. For non-peripherals, RX is done in napi already, so push
+ * directly. timestamp is used to ensure good skb ordering in
+ * rx-offload and is ignored for non-peripherals.
+*/
+static void m_can_receive_skb(struct m_can_classdev *cdev,
+			      struct sk_buff *skb,
+			      u32 timestamp)
+{
+	if (cdev->is_peripheral)
+		can_rx_offload_queue_sorted(&cdev->offload, skb, timestamp);
+	else
+		netif_receive_skb(skb);
+}
+
 static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
 {
 	struct net_device_stats *stats = &dev->stats;
@@ -464,6 +479,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
 	struct canfd_frame *cf;
 	struct sk_buff *skb;
 	u32 id, fgi, dlc;
+	u32 timestamp = 0;
 	int i;
 
 	/* calculate the fifo get index for where to read data */
@@ -512,7 +528,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 = FIELD_GET(RX_BUF_RXTS_MASK, dlc);
+
+	m_can_receive_skb(cdev, skb, timestamp);
 }
 
 static int m_can_do_rx_poll(struct net_device *dev, int quota)
@@ -543,9 +561,11 @@ 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;
+	u32 timestamp = 0;
 
 	netdev_err(dev, "msg lost in rxf0\n");
 
@@ -559,7 +579,10 @@ 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);
+	if (cdev->is_peripheral)
+		timestamp = m_can_get_timestamp(cdev);
+
+	m_can_receive_skb(cdev, skb, timestamp);
 
 	return 1;
 }
@@ -571,6 +594,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
 	struct net_device_stats *stats = &dev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
+	u32 timestamp = 0;
 
 	cdev->can.can_stats.bus_error++;
 	stats->rx_errors++;
@@ -616,7 +640,11 @@ static int m_can_handle_lec_err(struct net_device *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->len;
-	netif_receive_skb(skb);
+
+	if (cdev->is_peripheral)
+		timestamp = m_can_get_timestamp(cdev);
+
+	m_can_receive_skb(cdev, skb, timestamp);
 
 	return 1;
 }
@@ -674,6 +702,7 @@ static int m_can_handle_state_change(struct net_device *dev,
 	struct sk_buff *skb;
 	struct can_berr_counter bec;
 	unsigned int ecr;
+	u32 timestamp = 0;
 
 	switch (new_state) {
 	case CAN_STATE_ERROR_WARNING:
@@ -735,7 +764,11 @@ static int m_can_handle_state_change(struct net_device *dev,
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->len;
-	netif_receive_skb(skb);
+
+	if (cdev->is_peripheral)
+		timestamp = m_can_get_timestamp(cdev);
+
+	m_can_receive_skb(cdev, skb, timestamp);
 
 	return 1;
 }
@@ -800,6 +833,7 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
 	struct m_can_classdev *cdev = netdev_priv(dev);
 	struct can_frame *cf;
 	struct sk_buff *skb;
+	u32 timestamp = 0;
 
 	/* propagate the error condition to the CAN stack */
 	skb = alloc_can_err_skb(dev, &cf);
@@ -821,7 +855,11 @@ 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);
+
+	if (cdev->is_peripheral)
+		timestamp = m_can_get_timestamp(cdev);
+
+	m_can_receive_skb(cdev, skb, timestamp);
 
 	return 1;
 }
@@ -922,6 +960,29 @@ static int m_can_poll(struct napi_struct *napi, int quota)
 	return work_done;
 }
 
+/* Echo tx skb and update net stats. Peripherals use rx-offload for
+ * echo. timestamp is used for peripherals to ensure correct ordering
+ * by rx-offload, and is ignored for non-peripherals.
+*/
+static void m_can_tx_update_stats(struct m_can_classdev *cdev,
+				  unsigned int msg_mark,
+				  u32 timestamp)
+{
+	struct net_device *dev = cdev->net;
+	struct net_device_stats *stats = &dev->stats;
+
+	if (cdev->is_peripheral)
+		stats->tx_bytes +=
+			can_rx_offload_get_echo_skb(&cdev->offload,
+						    msg_mark,
+						    timestamp,
+						    NULL);
+	else
+		stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
+
+	stats->tx_packets++;
+}
+
 static void m_can_echo_tx_event(struct net_device *dev)
 {
 	u32 txe_count = 0;
@@ -931,7 +992,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);
@@ -941,21 +1001,23 @@ static void m_can_echo_tx_event(struct net_device *dev)
 
 	/* Get and process all sent elements */
 	for (i = 0; i < txe_count; i++) {
+		u32 txe, timestamp = 0;
+
 		/* retrieve get index */
 		fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) >>
 			TXEFS_EFGI_SHIFT;
 
-		/* get message marker */
-		msg_mark = (m_can_txe_fifo_read(cdev, fgi, 4) &
-			    TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
+		/* get message marker, timestamp */
+		txe = m_can_txe_fifo_read(cdev, fgi, 4);
+		msg_mark = (txe & TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
+		timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
 
 		/* ack txe element */
 		m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK &
 						(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, timestamp);
 	}
 }
 
@@ -963,7 +1025,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))
@@ -996,8 +1057,12 @@ 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++;
+			u32 timestamp = 0;
+
+			if (cdev->is_peripheral)
+				timestamp = m_can_get_timestamp(cdev);
+			m_can_tx_update_stats(cdev, 0, timestamp);
+
 			can_led_event(dev, CAN_LED_EVENT_TX);
 			netif_wake_queue(dev);
 		}
@@ -1458,6 +1523,9 @@ static int m_can_close(struct net_device *dev)
 		cdev->tx_wq = NULL;
 	}
 
+	if (cdev->is_peripheral)
+		can_rx_offload_disable(&cdev->offload);
+
 	close_candev(dev);
 	can_led_event(dev, CAN_LED_EVENT_STOP);
 
@@ -1656,6 +1724,9 @@ static int m_can_open(struct net_device *dev)
 		goto exit_disable_clks;
 	}
 
+	if (cdev->is_peripheral)
+		can_rx_offload_enable(&cdev->offload);
+
 	/* register interrupt handler */
 	if (cdev->is_peripheral) {
 		cdev->tx_skb = NULL;
@@ -1697,6 +1768,8 @@ static int m_can_open(struct net_device *dev)
 	if (cdev->is_peripheral)
 		destroy_workqueue(cdev->tx_wq);
 out_wq_fail:
+	if (cdev->is_peripheral)
+		can_rx_offload_disable(&cdev->offload);
 	close_candev(dev);
 exit_disable_clks:
 	m_can_clk_stop(cdev);
@@ -1845,15 +1918,22 @@ int m_can_class_register(struct m_can_classdev *cdev)
 			return ret;
 	}
 
+	if (cdev->is_peripheral) {
+		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;
+		goto rx_offload_del;
 
 	ret = register_m_can_dev(cdev->net);
 	if (ret) {
 		dev_err(cdev->dev, "registering %s failed (err=%d)\n",
 			cdev->net->name, ret);
-		goto clk_disable;
+		goto rx_offload_del;
 	}
 
 	devm_can_led_init(cdev->net);
@@ -1866,6 +1946,13 @@ int m_can_class_register(struct m_can_classdev *cdev)
 	/* Probe finished
 	 * Stop clocks. They will be reactivated once the M_CAN device is opened
 	 */
+	m_can_clk_stop(cdev);
+
+	return 0;
+
+rx_offload_del:
+	if (cdev->is_peripheral)
+		can_rx_offload_del(&cdev->offload);
 clk_disable:
 	m_can_clk_stop(cdev);
 
@@ -1875,6 +1962,8 @@ EXPORT_SYMBOL_GPL(m_can_class_register);
 
 void m_can_class_unregister(struct m_can_classdev *cdev)
 {
+	if (cdev->is_peripheral)
+		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.2



  parent reply	other threads:[~2021-03-30 11:47 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-30 11:45 pull-request: can-next 2021-03-30 Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 01/39] MAINTAINERS: remove Dan Murphy from m_can and tcan4x5x Marc Kleine-Budde
2021-03-30 20:10   ` patchwork-bot+netdevbpf
2021-03-30 11:45 ` [net-next 02/39] MAINTAINERS: Update MCAN MMIO device driver maintainer Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 03/39] can: dev: always create TX echo skb Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 04/39] can: dev: can_free_echo_skb(): don't crash the kernel if can_priv::echo_skb is accessed out of bounds Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 05/39] can: dev: can_free_echo_skb(): extend to return can frame length Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 06/39] can: add new CAN FD bittiming parameters: Transmitter Delay Compensation (TDC) Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 07/39] can: dev: reorder struct can_priv members for better packing Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 08/39] can: netlink: move '=' operators back to previous line (checkpatch fix) Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 09/39] can: bittiming: add calculation for CAN FD Transmitter Delay Compensation (TDC) Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 10/39] can: bittiming: add CAN_KBPS, CAN_MBPS and CAN_MHZ macros Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 11/39] can: grcan: add missing Kconfig dependency to HAS_IOMEM Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 12/39] can: xilinx_can: Simplify code by using dev_err_probe() Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 13/39] can: ucan: fix alignment constraints Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 14/39] can: peak_usb: pcan_usb_pro_encode_msg(): use macros for flags instead of plain integers Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 15/39] can: peak_usb: add support of ethtool set_phys_id() Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 16/39] can: peak_usb: add support of ONE_SHOT mode Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 17/39] can: m_can: m_can_class_allocate_dev(): remove impossible error return judgment Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 18/39] can: m_can: add infrastructure for internal timestamps Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 19/39] can: m_can: m_can_chip_config(): enable and configure " Marc Kleine-Budde
2021-03-30 11:45 ` Marc Kleine-Budde [this message]
2021-03-30 11:45 ` [net-next 21/39] can: tcan4x5x: remove duplicate include of regmap.h Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 22/39] can: mcp251xfd: add dev coredump support Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 23/39] can: mcp251xfd: simplify UINC handling Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 24/39] can: mcp251xfd: move netdevice.h to mcp251xfd.h Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 25/39] can: mcp251xfd: mcp251xfd_get_timestamp(): move " Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 26/39] can: mcp251xfd: add HW timestamp infrastructure Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 27/39] can: mcp251xfd: add HW timestamp to RX, TX and error CAN frames Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 28/39] can: c_can: convert block comments to network style comments Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 29/39] can: c_can: remove unnecessary blank lines and add suggested ones Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 30/39] can: c_can: fix indention Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 31/39] can: c_can: fix print formating string Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 32/39] can: c_can: replace double assignments by two single ones Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 33/39] can: c_can: fix remaining checkpatch warnings Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 34/39] can: c_can: remove unused code Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 35/39] can: c_can: fix indentation Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 36/39] can: c_can: add a comment about IF_RX interface's use Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 37/39] can: c_can: use 32-bit write to set arbitration register Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 38/39] can: c_can: prepare to up the message objects number Marc Kleine-Budde
2021-03-30 11:45 ` [net-next 39/39] can: c_can: add support to 64 message objects Marc Kleine-Budde
2021-03-30 20:10 ` pull-request: can-next 2021-03-30 patchwork-bot+netdevbpf

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=20210330114559.1114855-21-mkl@pengutronix.de \
    --to=mkl@pengutronix.de \
    --cc=davem@davemloft.net \
    --cc=kernel@pengutronix.de \
    --cc=kuba@kernel.org \
    --cc=linux-can@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=torin@maxiluxsystems.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;
as well as URLs for NNTP newsgroup(s).