mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
Merge branch 'avoid-compiler-and-iq-oq-reordering'
Vimlesh Kumar says: ==================== avoid compiler and IQ/OQ reordering Utilize READ_ONCE and WRITE_ONCE APIs to prevent compiler optimization and reordering. Ensure IO queue OUT/IN_CNT registers are flushed. Relocate IQ/OQ IN/OUT_CNTS updates to occur before NAPI completion, and replace napi_complete with napi_complete_done. ==================== Link: https://patch.msgid.link/20260227091402.1773833-1-vimleshk@marvell.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
699f3b2e51
4 changed files with 105 additions and 48 deletions
|
|
@ -553,6 +553,36 @@ static void octep_clean_irqs(struct octep_device *oct)
|
|||
octep_free_ioq_vectors(oct);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*/
|
||||
static void octep_update_pkt(struct octep_iq *iq, struct octep_oq *oq)
|
||||
{
|
||||
u32 pkts_pend = READ_ONCE(oq->pkts_pending);
|
||||
u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
|
||||
u32 pkts_processed = READ_ONCE(iq->pkts_processed);
|
||||
u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
|
||||
|
||||
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
|
||||
if (pkts_processed) {
|
||||
writel(pkts_processed, iq->inst_cnt_reg);
|
||||
readl(iq->inst_cnt_reg);
|
||||
WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
|
||||
WRITE_ONCE(iq->pkts_processed, 0);
|
||||
}
|
||||
if (last_pkt_count - pkts_pend) {
|
||||
writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
|
||||
readl(oq->pkts_sent_reg);
|
||||
WRITE_ONCE(oq->last_pkt_count, pkts_pend);
|
||||
}
|
||||
|
||||
/* Flush the previous wrties before writing to RESEND bit */
|
||||
smp_wmb();
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
|
||||
*
|
||||
|
|
@ -561,21 +591,6 @@ static void octep_clean_irqs(struct octep_device *oct)
|
|||
*/
|
||||
static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
|
||||
{
|
||||
u32 pkts_pend = oq->pkts_pending;
|
||||
|
||||
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
|
||||
if (iq->pkts_processed) {
|
||||
writel(iq->pkts_processed, iq->inst_cnt_reg);
|
||||
iq->pkt_in_done -= iq->pkts_processed;
|
||||
iq->pkts_processed = 0;
|
||||
}
|
||||
if (oq->last_pkt_count - pkts_pend) {
|
||||
writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
|
||||
oq->last_pkt_count = pkts_pend;
|
||||
}
|
||||
|
||||
/* Flush the previous wrties before writing to RESEND bit */
|
||||
wmb();
|
||||
writeq(1UL << OCTEP_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
|
||||
writeq(1UL << OCTEP_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
|
||||
}
|
||||
|
|
@ -601,7 +616,8 @@ static int octep_napi_poll(struct napi_struct *napi, int budget)
|
|||
if (tx_pending || rx_done >= budget)
|
||||
return budget;
|
||||
|
||||
napi_complete(napi);
|
||||
octep_update_pkt(ioq_vector->iq, ioq_vector->oq);
|
||||
napi_complete_done(napi, rx_done);
|
||||
octep_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
|
||||
return rx_done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,10 +324,16 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
|
|||
struct octep_oq *oq)
|
||||
{
|
||||
u32 pkt_count, new_pkts;
|
||||
u32 last_pkt_count, pkts_pending;
|
||||
|
||||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts = pkt_count - oq->last_pkt_count;
|
||||
last_pkt_count = READ_ONCE(oq->last_pkt_count);
|
||||
new_pkts = pkt_count - last_pkt_count;
|
||||
|
||||
if (pkt_count < last_pkt_count) {
|
||||
dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
|
||||
oq->q_no, pkt_count, last_pkt_count);
|
||||
}
|
||||
/* Clear the hardware packets counter register if the rx queue is
|
||||
* being processed continuously with-in a single interrupt and
|
||||
* reached half its max value.
|
||||
|
|
@ -338,8 +344,9 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
|
|||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts += pkt_count;
|
||||
}
|
||||
oq->last_pkt_count = pkt_count;
|
||||
oq->pkts_pending += new_pkts;
|
||||
WRITE_ONCE(oq->last_pkt_count, pkt_count);
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
|
||||
return new_pkts;
|
||||
}
|
||||
|
||||
|
|
@ -414,7 +421,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
|||
u16 rx_ol_flags;
|
||||
u32 read_idx;
|
||||
|
||||
read_idx = oq->host_read_idx;
|
||||
read_idx = READ_ONCE(oq->host_read_idx);
|
||||
rx_bytes = 0;
|
||||
desc_used = 0;
|
||||
for (pkt = 0; pkt < pkts_to_process; pkt++) {
|
||||
|
|
@ -499,7 +506,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
|
|||
napi_gro_receive(oq->napi, skb);
|
||||
}
|
||||
|
||||
oq->host_read_idx = read_idx;
|
||||
WRITE_ONCE(oq->host_read_idx, read_idx);
|
||||
oq->refill_count += desc_used;
|
||||
oq->stats->packets += pkt;
|
||||
oq->stats->bytes += rx_bytes;
|
||||
|
|
@ -522,22 +529,26 @@ int octep_oq_process_rx(struct octep_oq *oq, int budget)
|
|||
{
|
||||
u32 pkts_available, pkts_processed, total_pkts_processed;
|
||||
struct octep_device *oct = oq->octep_dev;
|
||||
u32 pkts_pending;
|
||||
|
||||
pkts_available = 0;
|
||||
pkts_processed = 0;
|
||||
total_pkts_processed = 0;
|
||||
while (total_pkts_processed < budget) {
|
||||
/* update pending count only when current one exhausted */
|
||||
if (oq->pkts_pending == 0)
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
if (pkts_pending == 0)
|
||||
octep_oq_check_hw_for_pkts(oct, oq);
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
pkts_available = min(budget - total_pkts_processed,
|
||||
oq->pkts_pending);
|
||||
pkts_pending);
|
||||
if (!pkts_available)
|
||||
break;
|
||||
|
||||
pkts_processed = __octep_oq_process_rx(oct, oq,
|
||||
pkts_available);
|
||||
oq->pkts_pending -= pkts_processed;
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
|
||||
total_pkts_processed += pkts_processed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -285,29 +285,46 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
|
|||
octep_vf_free_ioq_vectors(oct);
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*/
|
||||
|
||||
static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
|
||||
{
|
||||
u32 pkts_pend = READ_ONCE(oq->pkts_pending);
|
||||
u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
|
||||
u32 pkts_processed = READ_ONCE(iq->pkts_processed);
|
||||
u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
|
||||
|
||||
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
|
||||
if (pkts_processed) {
|
||||
writel(pkts_processed, iq->inst_cnt_reg);
|
||||
readl(iq->inst_cnt_reg);
|
||||
WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
|
||||
WRITE_ONCE(iq->pkts_processed, 0);
|
||||
}
|
||||
if (last_pkt_count - pkts_pend) {
|
||||
writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
|
||||
readl(oq->pkts_sent_reg);
|
||||
WRITE_ONCE(oq->last_pkt_count, pkts_pend);
|
||||
}
|
||||
|
||||
/* Flush the previous wrties before writing to RESEND bit */
|
||||
smp_wmb();
|
||||
}
|
||||
|
||||
/**
|
||||
* octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
|
||||
*
|
||||
* @iq: Octeon Tx queue data structure.
|
||||
* @oq: Octeon Rx queue data structure.
|
||||
*/
|
||||
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
|
||||
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq,
|
||||
struct octep_vf_oq *oq)
|
||||
{
|
||||
u32 pkts_pend = oq->pkts_pending;
|
||||
|
||||
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
|
||||
if (iq->pkts_processed) {
|
||||
writel(iq->pkts_processed, iq->inst_cnt_reg);
|
||||
iq->pkt_in_done -= iq->pkts_processed;
|
||||
iq->pkts_processed = 0;
|
||||
}
|
||||
if (oq->last_pkt_count - pkts_pend) {
|
||||
writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
|
||||
oq->last_pkt_count = pkts_pend;
|
||||
}
|
||||
|
||||
/* Flush the previous wrties before writing to RESEND bit */
|
||||
smp_wmb();
|
||||
writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
|
||||
writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
|
||||
}
|
||||
|
|
@ -333,6 +350,7 @@ static int octep_vf_napi_poll(struct napi_struct *napi, int budget)
|
|||
if (tx_pending || rx_done >= budget)
|
||||
return budget;
|
||||
|
||||
octep_vf_update_pkt(ioq_vector->iq, ioq_vector->oq);
|
||||
if (likely(napi_complete_done(napi, rx_done)))
|
||||
octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
|
||||
|
||||
|
|
|
|||
|
|
@ -325,9 +325,16 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
|
|||
struct octep_vf_oq *oq)
|
||||
{
|
||||
u32 pkt_count, new_pkts;
|
||||
u32 last_pkt_count, pkts_pending;
|
||||
|
||||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts = pkt_count - oq->last_pkt_count;
|
||||
last_pkt_count = READ_ONCE(oq->last_pkt_count);
|
||||
new_pkts = pkt_count - last_pkt_count;
|
||||
|
||||
if (pkt_count < last_pkt_count) {
|
||||
dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
|
||||
oq->q_no, pkt_count, last_pkt_count);
|
||||
}
|
||||
|
||||
/* Clear the hardware packets counter register if the rx queue is
|
||||
* being processed continuously with-in a single interrupt and
|
||||
|
|
@ -339,8 +346,9 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
|
|||
pkt_count = readl(oq->pkts_sent_reg);
|
||||
new_pkts += pkt_count;
|
||||
}
|
||||
oq->last_pkt_count = pkt_count;
|
||||
oq->pkts_pending += new_pkts;
|
||||
WRITE_ONCE(oq->last_pkt_count, pkt_count);
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
|
||||
return new_pkts;
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +377,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
|
|||
struct sk_buff *skb;
|
||||
u32 read_idx;
|
||||
|
||||
read_idx = oq->host_read_idx;
|
||||
read_idx = READ_ONCE(oq->host_read_idx);
|
||||
rx_bytes = 0;
|
||||
desc_used = 0;
|
||||
for (pkt = 0; pkt < pkts_to_process; pkt++) {
|
||||
|
|
@ -463,7 +471,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
|
|||
napi_gro_receive(oq->napi, skb);
|
||||
}
|
||||
|
||||
oq->host_read_idx = read_idx;
|
||||
WRITE_ONCE(oq->host_read_idx, read_idx);
|
||||
oq->refill_count += desc_used;
|
||||
oq->stats->packets += pkt;
|
||||
oq->stats->bytes += rx_bytes;
|
||||
|
|
@ -486,22 +494,26 @@ int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
|
|||
{
|
||||
u32 pkts_available, pkts_processed, total_pkts_processed;
|
||||
struct octep_vf_device *oct = oq->octep_vf_dev;
|
||||
u32 pkts_pending;
|
||||
|
||||
pkts_available = 0;
|
||||
pkts_processed = 0;
|
||||
total_pkts_processed = 0;
|
||||
while (total_pkts_processed < budget) {
|
||||
/* update pending count only when current one exhausted */
|
||||
if (oq->pkts_pending == 0)
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
if (pkts_pending == 0)
|
||||
octep_vf_oq_check_hw_for_pkts(oct, oq);
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
pkts_available = min(budget - total_pkts_processed,
|
||||
oq->pkts_pending);
|
||||
pkts_pending);
|
||||
if (!pkts_available)
|
||||
break;
|
||||
|
||||
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
|
||||
pkts_available);
|
||||
oq->pkts_pending -= pkts_processed;
|
||||
pkts_pending = READ_ONCE(oq->pkts_pending);
|
||||
WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
|
||||
total_pkts_processed += pkts_processed;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue