Commit e7b76db3 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-ipa-napi-poll-updates'

Alex Elder says:

====================
net: ipa: NAPI poll updates

While reviewing the IPA NAPI polling code in detail I found two
problems.  This series fixes those, and implements a few other
improvements to this part of the code.

The first two patches are minor bug fixes that avoid extra passes
through the poll function.  The third simplifies code inside the
polling loop a bit.

The last two update how interrupts are disabled; previously it was
possible for another I/O completion condition to be recorded before
NAPI got scheduled.
====================

Link: https://lore.kernel.org/r/20210121114821.26495-1-elder@linaro.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 59a49d96 7bd9785f
......@@ -272,7 +272,7 @@ static void gsi_irq_ch_ctrl_disable(struct gsi *gsi)
iowrite32(0, gsi->virt + GSI_CNTXT_SRC_CH_IRQ_MSK_OFFSET);
}
static void gsi_irq_ieob_enable(struct gsi *gsi, u32 evt_ring_id)
static void gsi_irq_ieob_enable_one(struct gsi *gsi, u32 evt_ring_id)
{
bool enable_ieob = !gsi->ieob_enabled_bitmap;
u32 val;
......@@ -286,11 +286,11 @@ static void gsi_irq_ieob_enable(struct gsi *gsi, u32 evt_ring_id)
gsi_irq_type_enable(gsi, GSI_IEOB);
}
static void gsi_irq_ieob_disable(struct gsi *gsi, u32 evt_ring_id)
static void gsi_irq_ieob_disable(struct gsi *gsi, u32 event_mask)
{
u32 val;
gsi->ieob_enabled_bitmap &= ~BIT(evt_ring_id);
gsi->ieob_enabled_bitmap &= ~event_mask;
/* Disable the interrupt type if this was the last enabled channel */
if (!gsi->ieob_enabled_bitmap)
......@@ -300,6 +300,11 @@ static void gsi_irq_ieob_disable(struct gsi *gsi, u32 evt_ring_id)
iowrite32(val, gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET);
}
static void gsi_irq_ieob_disable_one(struct gsi *gsi, u32 evt_ring_id)
{
gsi_irq_ieob_disable(gsi, BIT(evt_ring_id));
}
/* Enable all GSI_interrupt types */
static void gsi_irq_enable(struct gsi *gsi)
{
......@@ -766,13 +771,13 @@ static void gsi_channel_freeze(struct gsi_channel *channel)
napi_disable(&channel->napi);
gsi_irq_ieob_disable(channel->gsi, channel->evt_ring_id);
gsi_irq_ieob_disable_one(channel->gsi, channel->evt_ring_id);
}
/* Allow transactions to be used on the channel again. */
static void gsi_channel_thaw(struct gsi_channel *channel)
{
gsi_irq_ieob_enable(channel->gsi, channel->evt_ring_id);
gsi_irq_ieob_enable_one(channel->gsi, channel->evt_ring_id);
napi_enable(&channel->napi);
}
......@@ -1200,6 +1205,7 @@ static void gsi_isr_ieob(struct gsi *gsi)
u32 event_mask;
event_mask = ioread32(gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_OFFSET);
gsi_irq_ieob_disable(gsi, event_mask);
iowrite32(event_mask, gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_CLR_OFFSET);
while (event_mask) {
......@@ -1207,7 +1213,6 @@ static void gsi_isr_ieob(struct gsi *gsi)
event_mask ^= BIT(evt_ring_id);
gsi_irq_ieob_disable(gsi, evt_ring_id);
napi_schedule(&gsi->evt_ring[evt_ring_id].channel->napi);
}
}
......@@ -1452,7 +1457,7 @@ void gsi_channel_doorbell(struct gsi_channel *channel)
}
/* Consult hardware, move any newly completed transactions to completed list */
static void gsi_channel_update(struct gsi_channel *channel)
static struct gsi_trans *gsi_channel_update(struct gsi_channel *channel)
{
u32 evt_ring_id = channel->evt_ring_id;
struct gsi *gsi = channel->gsi;
......@@ -1471,7 +1476,7 @@ static void gsi_channel_update(struct gsi_channel *channel)
offset = GSI_EV_CH_E_CNTXT_4_OFFSET(evt_ring_id);
index = gsi_ring_index(ring, ioread32(gsi->virt + offset));
if (index == ring->index % ring->count)
return;
return NULL;
/* Get the transaction for the latest completed event. Take a
* reference to keep it from completing before we give the events
......@@ -1496,6 +1501,8 @@ static void gsi_channel_update(struct gsi_channel *channel)
gsi_evt_ring_doorbell(channel->gsi, channel->evt_ring_id, index);
gsi_trans_free(trans);
return gsi_channel_trans_complete(channel);
}
/**
......@@ -1516,11 +1523,8 @@ static struct gsi_trans *gsi_channel_poll_one(struct gsi_channel *channel)
/* Get the first transaction from the completed list */
trans = gsi_channel_trans_complete(channel);
if (!trans) {
/* List is empty; see if there's more to do */
gsi_channel_update(channel);
trans = gsi_channel_trans_complete(channel);
}
if (!trans) /* List is empty; see if there's more to do */
trans = gsi_channel_update(channel);
if (trans)
gsi_trans_move_polled(trans);
......@@ -1543,23 +1547,20 @@ static struct gsi_trans *gsi_channel_poll_one(struct gsi_channel *channel)
static int gsi_channel_poll(struct napi_struct *napi, int budget)
{
struct gsi_channel *channel;
int count = 0;
int count;
channel = container_of(napi, struct gsi_channel, napi);
while (count < budget) {
for (count = 0; count < budget; count++) {
struct gsi_trans *trans;
count++;
trans = gsi_channel_poll_one(channel);
if (!trans)
break;
gsi_trans_complete(trans);
}
if (count < budget) {
napi_complete(&channel->napi);
gsi_irq_ieob_enable(channel->gsi, channel->evt_ring_id);
}
if (count < budget && napi_complete(napi))
gsi_irq_ieob_enable_one(channel->gsi, channel->evt_ring_id);
return count;
}
......
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