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
next prev 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