summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ipa/gsi.c28
-rw-r--r--drivers/net/ipa/gsi_private.h14
-rw-r--r--drivers/net/ipa/gsi_trans.c22
3 files changed, 28 insertions, 36 deletions
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
index 9e307eebd33f..0ea98fa5dee5 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
@@ -710,7 +710,6 @@ static void gsi_evt_ring_program(struct gsi *gsi, u32 evt_ring_id)
static struct gsi_trans *gsi_channel_trans_last(struct gsi_channel *channel)
{
struct gsi_trans_info *trans_info = &channel->trans_info;
- const struct list_head *list;
struct gsi_trans *trans;
spin_lock_bh(&trans_info->spinlock);
@@ -719,29 +718,30 @@ static struct gsi_trans *gsi_channel_trans_last(struct gsi_channel *channel)
* before we disabled transmits, so check for that.
*/
if (channel->toward_ipa) {
- list = &trans_info->alloc;
- if (!list_empty(list))
+ trans = list_last_entry_or_null(&trans_info->alloc,
+ struct gsi_trans, links);
+ if (trans)
goto done;
- list = &trans_info->committed;
- if (!list_empty(list))
+ trans = list_last_entry_or_null(&trans_info->committed,
+ struct gsi_trans, links);
+ if (trans)
goto done;
- list = &trans_info->pending;
- if (!list_empty(list))
+ trans = list_last_entry_or_null(&trans_info->pending,
+ struct gsi_trans, links);
+ if (trans)
goto done;
}
/* Otherwise (TX or RX) we want to wait for anything that
* has completed, or has been polled but not released yet.
*/
- list = &trans_info->complete;
- if (!list_empty(list))
+ trans = list_last_entry_or_null(&trans_info->complete,
+ struct gsi_trans, links);
+ if (trans)
goto done;
- list = &trans_info->polled;
- if (list_empty(list))
- list = NULL;
+ trans = list_last_entry_or_null(&trans_info->polled,
+ struct gsi_trans, links);
done:
- trans = list ? list_last_entry(list, struct gsi_trans, links) : NULL;
-
/* Caller will wait for this, so take a reference */
if (trans)
refcount_inc(&trans->refcount);
diff --git a/drivers/net/ipa/gsi_private.h b/drivers/net/ipa/gsi_private.h
index 0b2516fa21b5..51bbc7a40dc2 100644
--- a/drivers/net/ipa/gsi_private.h
+++ b/drivers/net/ipa/gsi_private.h
@@ -17,6 +17,20 @@ struct gsi_channel;
#define GSI_RING_ELEMENT_SIZE 16 /* bytes; must be a power of 2 */
/**
+ * list_last_entry_or_null - get the last element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ */
+#define list_last_entry_or_null(ptr, type, member) ({ \
+ struct list_head *head__ = (ptr); \
+ struct list_head *pos__ = READ_ONCE(head__->prev); \
+ pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
+})
+
+/**
* gsi_trans_move_complete() - Mark a GSI transaction completed
* @trans: Transaction to commit
*/
diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c
index 4eef1480c200..b4a6f2b56356 100644
--- a/drivers/net/ipa/gsi_trans.c
+++ b/drivers/net/ipa/gsi_trans.c
@@ -309,23 +309,15 @@ void gsi_trans_move_polled(struct gsi_trans *trans)
{
struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
struct gsi_trans_info *trans_info = &channel->trans_info;
- u16 trans_index;
spin_lock_bh(&trans_info->spinlock);
list_move_tail(&trans->links, &trans_info->polled);
- trans = list_first_entry(&trans_info->polled,
- struct gsi_trans, links);
-
spin_unlock_bh(&trans_info->spinlock);
/* This completed transaction is now polled */
trans_info->completed_id++;
-
- WARN_ON(trans_info->polled_id == trans_info->completed_id);
- trans_index = trans_info->polled_id % channel->tre_count;
- WARN_ON(trans != &trans_info->trans[trans_index]);
}
/* Reserve some number of TREs on a channel. Returns true if successful */
@@ -413,11 +405,8 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,
/* Free a previously-allocated transaction */
void gsi_trans_free(struct gsi_trans *trans)
{
- struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
refcount_t *refcount = &trans->refcount;
struct gsi_trans_info *trans_info;
- struct gsi_trans *polled;
- u16 trans_index;
bool last;
/* We must hold the lock to release the last reference */
@@ -433,9 +422,6 @@ void gsi_trans_free(struct gsi_trans *trans)
if (last)
list_del(&trans->links);
- polled = list_first_entry_or_null(&trans_info->polled,
- struct gsi_trans, links);
-
spin_unlock_bh(&trans_info->spinlock);
if (!last)
@@ -456,14 +442,6 @@ void gsi_trans_free(struct gsi_trans *trans)
/* This transaction is now free */
trans_info->polled_id++;
- if (polled) {
- trans_index = trans_info->polled_id % channel->tre_count;
- WARN_ON(polled != &trans_info->trans[trans_index]);
- } else {
- WARN_ON(trans_info->polled_id !=
- trans_info->completed_id);
- }
-
/* Releasing the reserved TREs implicitly frees the sgl[] and
* (if present) info[] arrays, plus the transaction itself.
*/