Commit 821c7733 authored by Jakub Kicinski's avatar Jakub Kicinski

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.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 6c0d09d9 81765eea
...@@ -1344,14 +1344,19 @@ gsi_event_trans(struct gsi *gsi, struct gsi_event *event) ...@@ -1344,14 +1344,19 @@ gsi_event_trans(struct gsi *gsi, struct gsi_event *event)
} }
/** /**
* gsi_evt_ring_rx_update() - Record lengths of received data * gsi_evt_ring_update() - Update transaction state from hardware
* @evt_ring: Event ring associated with channel that received packets * @gsi: GSI pointer
* @evt_ring_id: Event ring ID
* @index: Event index in ring reported by hardware * @index: Event index in ring reported by hardware
* *
* Events for RX channels contain the actual number of bytes received into * Events for RX channels contain the actual number of bytes received into
* the buffer. Every event has a transaction associated with it, and here * the buffer. Every event has a transaction associated with it, and here
* we update transactions to record their actual received lengths. * 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 * 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 * 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 * 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) ...@@ -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. * 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_ring *ring = &evt_ring->ring;
struct gsi_trans_info *trans_info;
struct gsi_event *event_done; struct gsi_event *event_done;
struct gsi_event *event; struct gsi_event *event;
struct gsi_trans *trans;
u32 event_avail; u32 event_avail;
u32 old_index; u32 old_index;
trans_info = &channel->trans_info; /* Starting with the oldest un-processed event, determine which
* transaction (and which channel) is associated with the event.
/* We'll start with the oldest un-processed event. RX channels * For RX channels, update each completed transaction with the
* replenish receive buffers in single-TRE transactions, so we * number of bytes that were actually received. For TX channels
* can just map that event to its transaction. Transactions * associated with a network device, report to the network stack
* associated with completion events are consecutive. * the number of transfers and bytes this completion represents.
*/ */
old_index = ring->index; old_index = ring->index;
event = gsi_ring_virt(ring, old_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, /* Compute the number of events to process before we wrap,
* and determine when we'll be done processing events. * 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) ...@@ -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_avail = ring->count - old_index % ring->count;
event_done = gsi_ring_virt(ring, index); event_done = gsi_ring_virt(ring, index);
do { do {
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); 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 */ /* Move on to the next event and transaction */
if (--event_avail) if (--event_avail)
event++; event++;
else else
event = gsi_ring_virt(ring, 0); event = gsi_ring_virt(ring, 0);
trans = gsi_trans_pool_next(&trans_info->pool, trans);
} while (event != event_done); } 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 */ /* 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) ...@@ -1499,15 +1512,7 @@ static struct gsi_trans *gsi_channel_update(struct gsi_channel *channel)
* the number of transactions and bytes this completion represents * the number of transactions and bytes this completion represents
* up the network stack. * up the network stack.
*/ */
if (channel->toward_ipa) gsi_evt_ring_update(gsi, evt_ring_id, index);
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);
return gsi_channel_trans_complete(channel); return gsi_channel_trans_complete(channel);
} }
......
...@@ -16,9 +16,6 @@ struct gsi_channel; ...@@ -16,9 +16,6 @@ struct gsi_channel;
#define GSI_RING_ELEMENT_SIZE 16 /* bytes; must be a power of 2 */ #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 * gsi_trans_move_complete() - Mark a GSI transaction completed
* @trans: Transaction to commit * @trans: Transaction to commit
......
...@@ -214,26 +214,14 @@ void *gsi_trans_pool_alloc_dma(struct gsi_trans_pool *pool, dma_addr_t *addr) ...@@ -214,26 +214,14 @@ void *gsi_trans_pool_alloc_dma(struct gsi_trans_pool *pool, dma_addr_t *addr)
return pool->base + offset; return pool->base + offset;
} }
/* Return the pool element that immediately follows the one given. /* Map a TRE ring entry index to the transaction it is associated with */
* This only works done if elements are allocated one at a time. static void gsi_trans_map(struct gsi_trans *trans, u32 index)
*/
void *gsi_trans_pool_next(struct gsi_trans_pool *pool, void *element)
{ {
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);
element += pool->size;
return element < end ? element : pool->base; /* The completion event will indicate the last TRE used */
} index += trans->used_count - 1;
/* 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 */ /* Note: index *must* be used modulo the ring count here */
channel->trans_info.map[index % channel->tre_ring.count] = trans; 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) ...@@ -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); gsi_trans_tre_fill(dest_tre, addr, len, last_tre, bei, opcode);
dest_tre++; dest_tre++;
} }
/* Associate the TRE with the transaction */
gsi_trans_map(trans, tre_ring->index);
tre_ring->index += trans->used_count; tre_ring->index += trans->used_count;
trans->len = byte_count; trans->len = byte_count;
if (channel->toward_ipa) if (channel->toward_ipa)
gsi_trans_tx_committed(trans); 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); gsi_trans_move_pending(trans);
/* Ring doorbell if requested, or if all TREs are allocated */ /* Ring doorbell if requested, or if all TREs are allocated */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment