net: ipa: prevent concurrent replenish
authorAlex Elder <elder@linaro.org>
Wed, 12 Jan 2022 13:30:12 +0000 (07:30 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 5 Feb 2022 11:37:55 +0000 (12:37 +0100)
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.

Fixes: 84f9bd12d46db ("soc: qcom: ipa: IPA endpoints")
Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ipa/ipa_endpoint.c
drivers/net/ipa/ipa_endpoint.h

index 5f83be6754b6c4f1d44c083891faa41199d7979b..621648ce750b7efd60c328152d27cef3f90c0f5c 100644 (file)
@@ -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_add_return(count + 1, &endpoint->replenish_backlog);
 
@@ -1470,6 +1481,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);
index ffae393500d4f025b6b77c93d680ca55d2046326..823c4a1296587c225f65239e624fe1911b707a52 100644 (file)
@@ -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) */
 };