Attached are two patches that take the place of one IPA fix that was requested for back-port. The original did not apply cleanly, so one prerequisite was back-ported, followed by the "real" fix. They are built upon Linux v5.10.95.
I wasn't sure how I was supposed to indicate this was a manual back-port. I added the upstream commit ID in each patch but it needs to be edited. And I added a "References" tag indicating the e-mail to which this small series responds.
Please let me know if there's something else/more I should do.
Thanks.
-Alex
Alex Elder (2): net: ipa: use a bitmap for endpoint replenish_enabled net: ipa: prevent concurrent replenish
drivers/net/ipa/ipa_endpoint.c | 20 ++++++++++++++++---- drivers/net/ipa/ipa_endpoint.h | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-)
XXX commit c1aaa01dbf4cef95af3e04a5a43986c290e06ea3 upstream.
Define a new replenish_flags bitmap to contain Boolean flags associated with an endpoint's replenishing state. Replace the replenish_enabled field with a flag in that bitmap. This is to prepare for the next patch, which adds another flag.
References: https://lore.kernel.org/stable/1643031462146216@kroah.com Signed-off-by: Alex Elder elder@linaro.org Signed-off-by: David S. Miller davem@davemloft.net --- drivers/net/ipa/ipa_endpoint.c | 8 ++++---- drivers/net/ipa/ipa_endpoint.h | 13 ++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index a37aae00e128f..80380f5966142 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -901,7 +901,7 @@ static void ipa_endpoint_replenish(struct ipa_endpoint *endpoint, u32 count) struct gsi *gsi; u32 backlog;
- if (!endpoint->replenish_enabled) { + if (!test_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags)) { if (count) atomic_add(count, &endpoint->replenish_saved); return; @@ -941,7 +941,7 @@ static void ipa_endpoint_replenish_enable(struct ipa_endpoint *endpoint) u32 max_backlog; u32 saved;
- endpoint->replenish_enabled = true; + set_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); while ((saved = atomic_xchg(&endpoint->replenish_saved, 0))) atomic_add(saved, &endpoint->replenish_backlog);
@@ -955,7 +955,7 @@ static void ipa_endpoint_replenish_disable(struct ipa_endpoint *endpoint) { u32 backlog;
- endpoint->replenish_enabled = false; + clear_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); while ((backlog = atomic_xchg(&endpoint->replenish_backlog, 0))) atomic_add(backlog, &endpoint->replenish_saved); } @@ -1472,7 +1472,7 @@ static void ipa_endpoint_setup_one(struct ipa_endpoint *endpoint) /* RX transactions require a single TRE, so the maximum * backlog is the same as the maximum outstanding TREs. */ - endpoint->replenish_enabled = false; + clear_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); atomic_set(&endpoint->replenish_saved, gsi_channel_tre_max(gsi, endpoint->channel_id)); atomic_set(&endpoint->replenish_backlog, 0); diff --git a/drivers/net/ipa/ipa_endpoint.h b/drivers/net/ipa/ipa_endpoint.h index 58a245de488e8..ffae393500d4f 100644 --- a/drivers/net/ipa/ipa_endpoint.h +++ b/drivers/net/ipa/ipa_endpoint.h @@ -39,6 +39,17 @@ enum ipa_endpoint_name {
#define IPA_ENDPOINT_MAX 32 /* Max supported by driver */
+/** + * enum ipa_replenish_flag: RX buffer replenish flags + * + * @IPA_REPLENISH_ENABLED: Whether receive buffer replenishing is enabled + * @IPA_REPLENISH_COUNT: Number of defined replenish flags + */ +enum ipa_replenish_flag { + IPA_REPLENISH_ENABLED, + IPA_REPLENISH_COUNT, /* Number of flags (must be last) */ +}; + /** * struct ipa_endpoint - IPA endpoint information * @channel_id: EP's GSI channel @@ -60,7 +71,7 @@ struct ipa_endpoint { struct net_device *netdev;
/* Receive buffer replenishing for RX endpoints */ - bool replenish_enabled; + DECLARE_BITMAP(replenish_flags, IPA_REPLENISH_COUNT); u32 replenish_ready; atomic_t replenish_saved; atomic_t replenish_backlog;
XXX commit 998c0bd2b3715244da7639cc4e6a2062cb79c3f4 upstream.
We have seen cases where an endpoint RX completion interrupt arrives while replenishing for the endpoint is underway. This causes another instance of replenishing to begin as part of completing the receive transaction. If this occurs it can lead to transaction corruption.
Use a new flag to ensure only one replenish instance for an endpoint executes at a time.
References: https://lore.kernel.org/stable/1643031462146216@kroah.com Fixes: 84f9bd12d46db ("soc: qcom: ipa: IPA endpoints") Signed-off-by: Alex Elder elder@linaro.org Signed-off-by: David S. Miller davem@davemloft.net --- drivers/net/ipa/ipa_endpoint.c | 12 ++++++++++++ drivers/net/ipa/ipa_endpoint.h | 2 ++ 2 files changed, 14 insertions(+)
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 80380f5966142..2e1e558275b1c 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -907,16 +907,27 @@ static void ipa_endpoint_replenish(struct ipa_endpoint *endpoint, u32 count) return; }
+ /* If already active, just update the backlog */ + if (test_and_set_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags)) { + if (count) + atomic_add(count, &endpoint->replenish_backlog); + return; + }
while (atomic_dec_not_zero(&endpoint->replenish_backlog)) if (ipa_endpoint_replenish_one(endpoint)) goto try_again_later; + + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); + if (count) atomic_add(count, &endpoint->replenish_backlog);
return;
try_again_later: + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); + /* The last one didn't succeed, so fix the backlog */ backlog = atomic_inc_return(&endpoint->replenish_backlog);
@@ -1473,6 +1484,7 @@ static void ipa_endpoint_setup_one(struct ipa_endpoint *endpoint) * backlog is the same as the maximum outstanding TREs. */ clear_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); atomic_set(&endpoint->replenish_saved, gsi_channel_tre_max(gsi, endpoint->channel_id)); atomic_set(&endpoint->replenish_backlog, 0); diff --git a/drivers/net/ipa/ipa_endpoint.h b/drivers/net/ipa/ipa_endpoint.h index ffae393500d4f..823c4a1296587 100644 --- a/drivers/net/ipa/ipa_endpoint.h +++ b/drivers/net/ipa/ipa_endpoint.h @@ -43,10 +43,12 @@ enum ipa_endpoint_name { * enum ipa_replenish_flag: RX buffer replenish flags * * @IPA_REPLENISH_ENABLED: Whether receive buffer replenishing is enabled + * @IPA_REPLENISH_ACTIVE: Whether replenishing is underway * @IPA_REPLENISH_COUNT: Number of defined replenish flags */ enum ipa_replenish_flag { IPA_REPLENISH_ENABLED, + IPA_REPLENISH_ACTIVE, IPA_REPLENISH_COUNT, /* Number of flags (must be last) */ };
On Mon, Jan 31, 2022 at 07:16:56PM -0600, Alex Elder wrote:
Attached are two patches that take the place of one IPA fix that was requested for back-port. The original did not apply cleanly, so one prerequisite was back-ported, followed by the "real" fix. They are built upon Linux v5.10.95.
I wasn't sure how I was supposed to indicate this was a manual back-port. I added the upstream commit ID in each patch but it needs to be edited. And I added a "References" tag indicating the e-mail to which this small series responds.
Please let me know if there's something else/more I should do.
Thanks.
-Alex
Alex Elder (2): net: ipa: use a bitmap for endpoint replenish_enabled net: ipa: prevent concurrent replenish
drivers/net/ipa/ipa_endpoint.c | 20 ++++++++++++++++---- drivers/net/ipa/ipa_endpoint.h | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-)
-- 2.32.0
All now queued up, thanks!
linux-stable-mirror@lists.linaro.org