WSL2-Linux-Kernel/drivers/net/ipa
Alex Elder 064c9c32b1 net: ipa: lock when freeing transaction
Transactions sit on one of several lists, depending on their state
(allocated, pending, complete, or polled).  A spinlock protects
against concurrent access when transactions are moved between these
lists.

Transactions are also reference counted.  A newly-allocated
transaction has an initial count of 1; a transaction is released in
gsi_trans_free() only if its decremented reference count reaches 0.
Releasing a transaction includes removing it from the polled (or if
unused, allocated) list, so the spinlock is acquired when we release
a transaction.

The reference count is used to allow a caller to synchronously wait
for a committed transaction to complete.  In this case, the waiter
takes an extra reference to the transaction *before* committing it
(so it won't be freed), and releases its reference (calls
gsi_trans_free()) when it is done with it.

Similarly, gsi_channel_update() takes an extra reference to ensure a
transaction isn't released before the function is done operating on
it.  Until the transaction is moved to the completed list (by this
function) it won't be freed, so this reference is taken "safely."

But in the quiesce path, we want to wait for the "last" transaction,
which we find in the completed or polled list.  Transactions on
these lists can be freed at any time, so we (try to) prevent that
by taking the reference while holding the spinlock.

Currently gsi_trans_free() decrements a transaction's reference
count unconditionally, acquiring the lock to remove the transaction
from its list *only* when the count reaches 0.  This does not
protect the quiesce path, which depends on the lock to ensure its
extra reference prevents release of the transaction.

Fix this by only dropping the last reference to a transaction
in gsi_trans_free() while holding the spinlock.

Fixes: 9dd441e4ed ("soc: qcom: ipa: GSI transactions")
Reported-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Alex Elder <elder@linaro.org>
Link: https://lore.kernel.org/r/20201114182017.28270-1-elder@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-11-16 17:32:22 -08:00
..
Kconfig
Makefile
gsi.c net: ipa: fix two mild warnings 2020-09-28 18:34:56 -07:00
gsi.h net: ipa: do not enable GSI interrupt for wakeup 2020-09-18 17:47:07 -07:00
gsi_private.h
gsi_reg.h net: ipa: share field mask values for GSI general interrupt 2020-09-28 18:34:56 -07:00
gsi_trans.c net: ipa: lock when freeing transaction 2020-11-16 17:32:22 -08:00
gsi_trans.h
ipa.h net: ipa: repurpose CLOCK_HELD flag 2020-09-18 17:47:07 -07:00
ipa_clock.c net: ipa: manage endpoints separate from clock 2020-09-18 17:47:07 -07:00
ipa_clock.h
ipa_cmd.c
ipa_cmd.h
ipa_data-sc7180.c
ipa_data-sdm845.c
ipa_data.h
ipa_endpoint.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net 2020-10-15 12:43:21 -07:00
ipa_endpoint.h
ipa_gsi.c
ipa_gsi.h
ipa_interrupt.c net: ipa: enable wakeup on IPA interrupt 2020-09-18 17:47:07 -07:00
ipa_interrupt.h
ipa_main.c net: ipa: rename a phandle variable 2020-09-28 18:34:56 -07:00
ipa_mem.c
ipa_mem.h
ipa_modem.c
ipa_modem.h
ipa_qmi.c
ipa_qmi.h
ipa_qmi_msg.c
ipa_qmi_msg.h
ipa_reg.c
ipa_reg.h net: ipa: fix two comments 2020-09-28 18:34:56 -07:00
ipa_smp2p.c
ipa_smp2p.h
ipa_table.c net: ipa: fix u32_replace_bits by u32p_xxx version 2020-09-11 17:28:48 -07:00
ipa_table.h
ipa_uc.c net: ipa: fix two comments 2020-09-28 18:34:56 -07:00
ipa_uc.h
ipa_version.h