Merge branch 'eth-bnxt-fix-irq-notifier-bugs'

Jakub Kicinski says:

====================
eth: bnxt: fix IRQ notifier bugs

I was trying to make bnxt preserve IRQ mappings across reconfiguration.
While hacking on that I noticed 2 bugs in the notifiers that should
probably be fixed before development work.

First one is simple - TPH recofig makes aARFs not work. There can only
be one notifier per IRQ and TPH "steals" the callback from the rmap
updates. Fix by patches 1 and 2.

Second one is a deadlock between the affinity notifier and reconfig.
This one is a bit more involved (patch 3 and 4).

Unfortunately, I can't really verify the problem or test the fix.
I managed to get my hands on a system with an AMD Venice CPU which
is supposed to support TPH, but the ACPI is missing some bits to
actually advertise it. pcie_tph_get_cpu_st() returns -EINVAL.
====================

Link: https://patch.msgid.link/20260803193135.2030368-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-10 15:15:08 -07:00
2 changed files with 91 additions and 41 deletions

View File

@@ -11789,10 +11789,21 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
{
struct bnxt_irq *irq;
u16 tag;
int err;
irq = container_of(notify, struct bnxt_irq, affinity_notify);
#ifdef CONFIG_RFS_ACCEL
if (irq->bp->dev->rx_cpu_rmap && irq->ring_nr < irq->bp->rx_nr_rings) {
int err;
err = cpu_rmap_update(irq->bp->dev->rx_cpu_rmap, irq->ring_nr,
mask);
if (err)
netdev_warn(irq->bp->dev,
"aRFS rmap update failed: %d\n", err);
}
#endif
if (!irq->bp->tph_mode)
return;
@@ -11802,20 +11813,11 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
return;
if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
cpumask_first(irq->cpu_mask), &tag))
cpumask_first(mask), &tag))
return;
if (pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag))
return;
netdev_lock(irq->bp->dev);
if (netif_running(irq->bp->dev)) {
err = netdev_rx_queue_restart(irq->bp->dev, irq->ring_nr);
if (err)
netdev_err(irq->bp->dev,
"RX queue restart failed: err=%d\n", err);
}
netdev_unlock(irq->bp->dev);
WRITE_ONCE(irq->new_tag, tag);
bnxt_queue_sp_work(irq->bp, BNXT_TPH_UPDATE_SP_EVENT);
}
static void bnxt_irq_affinity_release(struct kref *ref)
@@ -11866,10 +11868,6 @@ static void bnxt_free_irq(struct bnxt *bp)
struct bnxt_irq *irq;
int i;
#ifdef CONFIG_RFS_ACCEL
free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
bp->dev->rx_cpu_rmap = NULL;
#endif
if (!bp->irq_tbl || !bp->bnapi)
return;
@@ -11878,27 +11876,35 @@ static void bnxt_free_irq(struct bnxt *bp)
irq = &bp->irq_tbl[map_idx];
if (irq->requested) {
bnxt_release_irq_notifier(irq);
if (irq->have_cpumask) {
irq_update_affinity_hint(irq->vector, NULL);
free_cpumask_var(irq->cpu_mask);
irq->have_cpumask = 0;
}
bnxt_release_irq_notifier(irq);
free_irq(irq->vector, bp->bnapi[i]);
}
irq->requested = 0;
irq->tag = 0;
irq->new_tag = 0;
}
/* Disable TPH support */
pcie_disable_tph(bp->pdev);
bp->tph_mode = 0;
#ifdef CONFIG_RFS_ACCEL
free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
bp->dev->rx_cpu_rmap = NULL;
#endif
}
static int bnxt_request_irq(struct bnxt *bp)
{
const int numa_node = dev_to_node(&bp->pdev->dev);
struct cpu_rmap *rmap = NULL;
int i, j, rc = 0;
unsigned long flags = 0;
@@ -11921,6 +11927,8 @@ static int bnxt_request_irq(struct bnxt *bp)
for (i = 0, j = 0; i < bp->cp_nr_rings; i++) {
int map_idx = bnxt_cp_num_to_irq_num(bp, i);
struct bnxt_irq *irq = &bp->irq_tbl[map_idx];
unsigned int cpu_num;
u16 tag;
if (IS_ENABLED(CONFIG_RFS_ACCEL) &&
rmap && bp->bnapi[i]->rx_ring) {
@@ -11939,32 +11947,31 @@ static int bnxt_request_irq(struct bnxt *bp)
netif_napi_set_irq_locked(&bp->bnapi[i]->napi, irq->vector);
irq->requested = 1;
if (zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL)) {
int numa_node = dev_to_node(&bp->pdev->dev);
u16 tag;
if (!zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL))
continue;
irq->have_cpumask = 1;
irq->msix_nr = map_idx;
irq->ring_nr = i;
cpumask_set_cpu(cpumask_local_spread(i, numa_node),
irq->cpu_mask);
rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
if (rc) {
netdev_warn(bp->dev,
"Update affinity hint failed, IRQ = %d\n",
irq->vector);
break;
}
irq->have_cpumask = 1;
irq->msix_nr = map_idx;
irq->ring_nr = i;
cpu_num = cpumask_local_spread(i, numa_node);
cpumask_set_cpu(cpu_num, irq->cpu_mask);
bnxt_register_irq_notifier(bp, irq);
/* Init ST table entry if we can get the mapping */
if (!pcie_tph_get_cpu_st(bp->pdev, TPH_MEM_TYPE_VM,
cpu_num, &tag)) {
pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag);
irq->tag = tag;
irq->new_tag = tag;
}
/* Init ST table entry */
if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
cpumask_first(irq->cpu_mask),
&tag))
continue;
bnxt_register_irq_notifier(bp, irq);
pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag);
rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
if (rc) {
netdev_warn(bp->dev,
"Update affinity hint failed, IRQ = %d\n",
irq->vector);
break;
}
}
return rc;
@@ -14468,6 +14475,43 @@ static void bnxt_rtnl_unlock_sp(struct bnxt *bp)
rtnl_unlock();
}
static void bnxt_tph_update(struct bnxt *bp)
{
struct net_device *dev = bp->dev;
int i;
bnxt_lock_sp(bp);
if (!test_bit(BNXT_STATE_OPEN, &bp->state))
goto unlock;
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_irq *irq;
int map_idx, err;
u16 tag;
map_idx = bnxt_cp_num_to_irq_num(bp, i);
irq = &bp->irq_tbl[map_idx];
tag = READ_ONCE(irq->new_tag);
if (irq->tag == tag)
continue;
if (pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag))
continue;
err = netdev_rx_queue_restart(dev, irq->ring_nr);
if (err) {
netdev_err(dev, "RX queue restart failed: err=%d\n",
err);
continue;
}
irq->tag = tag;
}
unlock:
bnxt_unlock_sp(bp);
}
/* Only called from bnxt_sp_task() */
static void bnxt_reset(struct bnxt *bp, bool silent)
{
@@ -14892,6 +14936,9 @@ static void bnxt_sp_task(struct work_struct *work)
bnxt_devlink_health_fw_report(bp);
}
if (test_and_clear_bit(BNXT_TPH_UPDATE_SP_EVENT, &bp->sp_event))
bnxt_tph_update(bp);
smp_mb__before_atomic();
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
}

View File

@@ -1268,6 +1268,8 @@ struct bnxt_irq {
struct bnxt *bp;
int msix_nr;
int ring_nr;
u16 tag;
u16 new_tag;
struct irq_affinity_notify affinity_notify;
};
@@ -2642,6 +2644,7 @@ struct bnxt {
#define BNXT_RING_COAL_NOW_SP_EVENT 17
#define BNXT_FW_RESET_NOTIFY_SP_EVENT 18
#define BNXT_FW_EXCEPTION_SP_EVENT 19
#define BNXT_TPH_UPDATE_SP_EVENT 20
#define BNXT_LINK_CFG_CHANGE_SP_EVENT 21
#define BNXT_THERMAL_THRESHOLD_SP_EVENT 22
#define BNXT_FW_ECHO_REQUEST_SP_EVENT 23