Commit 998c0bd2 authored by Alex Elder's avatar Alex Elder Committed by David S. Miller
Browse files

net: ipa: prevent concurrent replenish



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: 84f9bd12 ("soc: qcom: ipa: IPA endpoints")
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c1aaa01d
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1088,15 +1088,27 @@ static void ipa_endpoint_replenish(struct ipa_endpoint *endpoint, bool add_one)
		return;
	}

	/* If already active, just update the backlog */
	if (test_and_set_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags)) {
		if (add_one)
			atomic_inc(&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 (add_one)
		atomic_inc(&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 */
	delta = add_one ? 2 : 1;
	backlog = atomic_add_return(delta, &endpoint->replenish_backlog);
@@ -1691,6 +1703,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);
+2 −0
Original line number Diff line number Diff line
@@ -44,10 +44,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) */
};