Merge branch 'net-ipa-more-multi-channel-event-ring-work'

Alex Elder says:

====================
net: ipa: more multi-channel event ring work

This series makes a little more progress toward supporting multiple
channels with a single event ring.  The first removes the assumption
that consecutive events are associated with the same RX channel.

The second derives the channel associated with an event from the
event itself, and the next does a small cleanup enabled by that.

The fourth causes updates to occur for every event processed (rather
once).  And the final patch does a little more rework to make TX
completion have more in common with RX completion.
====================

Link: https://lore.kernel.org/r/20220615165929.5924-1-elder@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2022-06-16 20:44:07 -07:00
commit 821c7733d2
3 changed files with 40 additions and 50 deletions

View File

@ -1344,14 +1344,19 @@ gsi_event_trans(struct gsi *gsi, struct gsi_event *event)
}
/**
* gsi_evt_ring_rx_update() - Record lengths of received data
* @evt_ring: Event ring associated with channel that received packets
* @index: Event index in ring reported by hardware
* gsi_evt_ring_update() - Update transaction state from hardware
* @gsi: GSI pointer
* @evt_ring_id: Event ring ID
* @index: Event index in ring reported by hardware
*
* Events for RX channels contain the actual number of bytes received into
* the buffer. Every event has a transaction associated with it, and here
* we update transactions to record their actual received lengths.
*
* When an event for a TX channel arrives we use information in the
* transaction to report the number of requests and bytes have been
* transferred.
*
* This function is called whenever we learn that the GSI hardware has filled
* new events since the last time we checked. The ring's index field tells
* the first entry in need of processing. The index provided is the
@ -1362,29 +1367,24 @@ gsi_event_trans(struct gsi *gsi, struct gsi_event *event)
*
* Note that @index always refers to an element *within* the event ring.
*/
static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)
static void gsi_evt_ring_update(struct gsi *gsi, u32 evt_ring_id, u32 index)
{
struct gsi_channel *channel = evt_ring->channel;
struct gsi_evt_ring *evt_ring = &gsi->evt_ring[evt_ring_id];
struct gsi_ring *ring = &evt_ring->ring;
struct gsi_trans_info *trans_info;
struct gsi_event *event_done;
struct gsi_event *event;
struct gsi_trans *trans;
u32 event_avail;
u32 old_index;
trans_info = &channel->trans_info;
/* We'll start with the oldest un-processed event. RX channels
* replenish receive buffers in single-TRE transactions, so we
* can just map that event to its transaction. Transactions
* associated with completion events are consecutive.
/* Starting with the oldest un-processed event, determine which
* transaction (and which channel) is associated with the event.
* For RX channels, update each completed transaction with the
* number of bytes that were actually received. For TX channels
* associated with a network device, report to the network stack
* the number of transfers and bytes this completion represents.
*/
old_index = ring->index;
event = gsi_ring_virt(ring, old_index);
trans = gsi_event_trans(channel->gsi, event);
if (!trans)
return;
/* Compute the number of events to process before we wrap,
* and determine when we'll be done processing events.
@ -1392,15 +1392,28 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)
event_avail = ring->count - old_index % ring->count;
event_done = gsi_ring_virt(ring, index);
do {
trans->len = __le16_to_cpu(event->len);
struct gsi_trans *trans;
trans = gsi_event_trans(gsi, event);
if (!trans)
return;
if (trans->direction == DMA_FROM_DEVICE)
trans->len = __le16_to_cpu(event->len);
else
gsi_trans_tx_completed(trans);
gsi_trans_move_complete(trans);
/* Move on to the next event and transaction */
if (--event_avail)
event++;
else
event = gsi_ring_virt(ring, 0);
trans = gsi_trans_pool_next(&trans_info->pool, trans);
} while (event != event_done);
/* Tell the hardware we've handled these events */
gsi_evt_ring_doorbell(gsi, evt_ring_id, index);
}
/* Initialize a ring, including allocating DMA memory for its entries */
@ -1499,15 +1512,7 @@ static struct gsi_trans *gsi_channel_update(struct gsi_channel *channel)
* the number of transactions and bytes this completion represents
* up the network stack.
*/
if (channel->toward_ipa)
gsi_trans_tx_completed(trans);
else
gsi_evt_ring_rx_update(evt_ring, index);
gsi_trans_move_complete(trans);
/* Tell the hardware we've handled these events */
gsi_evt_ring_doorbell(gsi, evt_ring_id, index);
gsi_evt_ring_update(gsi, evt_ring_id, index);
return gsi_channel_trans_complete(channel);
}

View File

@ -16,9 +16,6 @@ struct gsi_channel;
#define GSI_RING_ELEMENT_SIZE 16 /* bytes; must be a power of 2 */
/* Return the entry that follows one provided in a transaction pool */
void *gsi_trans_pool_next(struct gsi_trans_pool *pool, void *element);
/**
* gsi_trans_move_complete() - Mark a GSI transaction completed
* @trans: Transaction to commit

View File

@ -214,26 +214,14 @@ void *gsi_trans_pool_alloc_dma(struct gsi_trans_pool *pool, dma_addr_t *addr)
return pool->base + offset;
}
/* Return the pool element that immediately follows the one given.
* This only works done if elements are allocated one at a time.
*/
void *gsi_trans_pool_next(struct gsi_trans_pool *pool, void *element)
/* Map a TRE ring entry index to the transaction it is associated with */
static void gsi_trans_map(struct gsi_trans *trans, u32 index)
{
void *end = pool->base + pool->count * pool->size;
struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
WARN_ON(element < pool->base);
WARN_ON(element >= end);
WARN_ON(pool->max_alloc != 1);
/* The completion event will indicate the last TRE used */
index += trans->used_count - 1;
element += pool->size;
return element < end ? element : pool->base;
}
/* Map a given ring entry index to the transaction associated with it */
static void gsi_channel_trans_map(struct gsi_channel *channel, u32 index,
struct gsi_trans *trans)
{
/* Note: index *must* be used modulo the ring count here */
channel->trans_info.map[index % channel->tre_ring.count] = trans;
}
@ -584,15 +572,15 @@ static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
gsi_trans_tre_fill(dest_tre, addr, len, last_tre, bei, opcode);
dest_tre++;
}
/* Associate the TRE with the transaction */
gsi_trans_map(trans, tre_ring->index);
tre_ring->index += trans->used_count;
trans->len = byte_count;
if (channel->toward_ipa)
gsi_trans_tx_committed(trans);
/* Associate the last TRE with the transaction */
gsi_channel_trans_map(channel, tre_ring->index - 1, trans);
gsi_trans_move_pending(trans);
/* Ring doorbell if requested, or if all TREs are allocated */