From: Loic Poulain <loic.poulain@linaro.org>
To: kuba@kernel.org, davem@davemloft.net
Cc: willemdebruijn.kernel@gmail.com, netdev@vger.kernel.org,
stranche@codeaurora.org, subashab@codeaurora.org,
Loic Poulain <loic.poulain@linaro.org>
Subject: [PATCH net-next v5 1/2] net: mhi-net: Add re-aggregation of fragmented packets
Date: Thu, 4 Feb 2021 09:40:00 +0100 [thread overview]
Message-ID: <1612428002-12333-1-git-send-email-loic.poulain@linaro.org> (raw)
When device side MTU is larger than host side MTU, the packets
(typically rmnet packets) are split over multiple MHI transfers.
In that case, fragments must be re-aggregated to recover the packet
before forwarding to upper layer.
A fragmented packet result in -EOVERFLOW MHI transaction status for
each of its fragments, except the final one. Such transfer was
previously considered as error and fragments were simply dropped.
This change adds re-aggregation mechanism using skb chaining, via
skb frag_list.
A warning (once) is printed since this behavior usually comes from
a misconfiguration of the device (e.g. modem MTU).
Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
---
v2: use zero-copy skb chaining instead of skb_copy_expand.
v3: Fix nit in commit msg + remove misleading inline comment for frag_list
v4: no change
v5: reword/fix commit subject
drivers/net/mhi_net.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 64 insertions(+), 10 deletions(-)
diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c
index 4f512531..8800991 100644
--- a/drivers/net/mhi_net.c
+++ b/drivers/net/mhi_net.c
@@ -32,6 +32,8 @@ struct mhi_net_stats {
struct mhi_net_dev {
struct mhi_device *mdev;
struct net_device *ndev;
+ struct sk_buff *skbagg_head;
+ struct sk_buff *skbagg_tail;
struct delayed_work rx_refill;
struct mhi_net_stats stats;
u32 rx_queue_sz;
@@ -132,6 +134,32 @@ static void mhi_net_setup(struct net_device *ndev)
ndev->tx_queue_len = 1000;
}
+static struct sk_buff *mhi_net_skb_agg(struct mhi_net_dev *mhi_netdev,
+ struct sk_buff *skb)
+{
+ struct sk_buff *head = mhi_netdev->skbagg_head;
+ struct sk_buff *tail = mhi_netdev->skbagg_tail;
+
+ /* This is non-paged skb chaining using frag_list */
+ if (!head) {
+ mhi_netdev->skbagg_head = skb;
+ return skb;
+ }
+
+ if (!skb_shinfo(head)->frag_list)
+ skb_shinfo(head)->frag_list = skb;
+ else
+ tail->next = skb;
+
+ head->len += skb->len;
+ head->data_len += skb->len;
+ head->truesize += skb->truesize;
+
+ mhi_netdev->skbagg_tail = skb;
+
+ return mhi_netdev->skbagg_head;
+}
+
static void mhi_net_dl_callback(struct mhi_device *mhi_dev,
struct mhi_result *mhi_res)
{
@@ -142,19 +170,42 @@ static void mhi_net_dl_callback(struct mhi_device *mhi_dev,
free_desc_count = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
if (unlikely(mhi_res->transaction_status)) {
- dev_kfree_skb_any(skb);
-
- /* MHI layer stopping/resetting the DL channel */
- if (mhi_res->transaction_status == -ENOTCONN)
+ switch (mhi_res->transaction_status) {
+ case -EOVERFLOW:
+ /* Packet can not fit in one MHI buffer and has been
+ * split over multiple MHI transfers, do re-aggregation.
+ * That usually means the device side MTU is larger than
+ * the host side MTU/MRU. Since this is not optimal,
+ * print a warning (once).
+ */
+ netdev_warn_once(mhi_netdev->ndev,
+ "Fragmented packets received, fix MTU?\n");
+ skb_put(skb, mhi_res->bytes_xferd);
+ mhi_net_skb_agg(mhi_netdev, skb);
+ break;
+ case -ENOTCONN:
+ /* MHI layer stopping/resetting the DL channel */
+ dev_kfree_skb_any(skb);
return;
-
- u64_stats_update_begin(&mhi_netdev->stats.rx_syncp);
- u64_stats_inc(&mhi_netdev->stats.rx_errors);
- u64_stats_update_end(&mhi_netdev->stats.rx_syncp);
+ default:
+ /* Unknown error, simply drop */
+ dev_kfree_skb_any(skb);
+ u64_stats_update_begin(&mhi_netdev->stats.rx_syncp);
+ u64_stats_inc(&mhi_netdev->stats.rx_errors);
+ u64_stats_update_end(&mhi_netdev->stats.rx_syncp);
+ }
} else {
+ skb_put(skb, mhi_res->bytes_xferd);
+
+ if (mhi_netdev->skbagg_head) {
+ /* Aggregate the final fragment */
+ skb = mhi_net_skb_agg(mhi_netdev, skb);
+ mhi_netdev->skbagg_head = NULL;
+ }
+
u64_stats_update_begin(&mhi_netdev->stats.rx_syncp);
u64_stats_inc(&mhi_netdev->stats.rx_packets);
- u64_stats_add(&mhi_netdev->stats.rx_bytes, mhi_res->bytes_xferd);
+ u64_stats_add(&mhi_netdev->stats.rx_bytes, skb->len);
u64_stats_update_end(&mhi_netdev->stats.rx_syncp);
switch (skb->data[0] & 0xf0) {
@@ -169,7 +220,6 @@ static void mhi_net_dl_callback(struct mhi_device *mhi_dev,
break;
}
- skb_put(skb, mhi_res->bytes_xferd);
netif_rx(skb);
}
@@ -267,6 +317,7 @@ static int mhi_net_probe(struct mhi_device *mhi_dev,
dev_set_drvdata(dev, mhi_netdev);
mhi_netdev->ndev = ndev;
mhi_netdev->mdev = mhi_dev;
+ mhi_netdev->skbagg_head = NULL;
SET_NETDEV_DEV(ndev, &mhi_dev->dev);
SET_NETDEV_DEVTYPE(ndev, &wwan_type);
@@ -301,6 +352,9 @@ static void mhi_net_remove(struct mhi_device *mhi_dev)
mhi_unprepare_from_transfer(mhi_netdev->mdev);
+ if (mhi_netdev->skbagg_head)
+ kfree_skb(mhi_netdev->skbagg_head);
+
free_netdev(mhi_netdev->ndev);
}
--
2.7.4
next reply other threads:[~2021-02-04 8:33 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-04 8:40 Loic Poulain [this message]
2021-02-04 8:40 ` [PATCH net-next v5 2/2] net: qualcomm: rmnet: Fix rx_handler for non-linear skbs Loic Poulain
2021-02-04 19:17 ` [PATCH net-next v5 1/2] net: mhi-net: Add re-aggregation of fragmented packets Jesse Brandeburg
2021-02-06 19:31 ` Jakub Kicinski
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=1612428002-12333-1-git-send-email-loic.poulain@linaro.org \
--to=loic.poulain@linaro.org \
--cc=davem@davemloft.net \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=stranche@codeaurora.org \
--cc=subashab@codeaurora.org \
--cc=willemdebruijn.kernel@gmail.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).