Skip to content

Commit 8700aff

Browse files
ecree-solarflaredavem330
authored andcommitted
sfc: fix channel allocation with brute force
It was possible for channel allocation logic to get confused between what it had and what it wanted, and end up trying to use the same channel for both PTP and regular TX. This led to a kernel panic: BUG: unable to handle page fault for address: 0000000000047635 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page PGD 0 P4D 0 Oops: 0002 [#1] SMP PTI CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 5.4.0-rc3-ehc14+ #900 Hardware name: Dell Inc. PowerEdge R710/0M233H, BIOS 6.4.0 07/23/2013 RIP: 0010:native_queued_spin_lock_slowpath+0x188/0x1e0 Code: f3 90 48 8b 32 48 85 f6 74 f6 eb e8 c1 ee 12 83 e0 03 83 ee 01 48 c1 e0 05 48 63 f6 48 05 c0 98 02 00 48 03 04 f5 a0 c6 ed 81 <48> 89 10 8b 42 08 85 c0 75 09 f3 90 8b 42 08 85 c0 74 f7 48 8b 32 RSP: 0018:ffffc90000003d28 EFLAGS: 00010006 RAX: 0000000000047635 RBX: 0000000000000246 RCX: 0000000000040000 RDX: ffff888627a298c0 RSI: 0000000000003ffe RDI: ffff88861f6b8dd4 RBP: ffff8886225c6e00 R08: 0000000000040000 R09: 0000000000000000 R10: 0000000616f080c6 R11: 00000000000000c0 R12: ffff88861f6b8dd4 R13: ffffc90000003dc8 R14: ffff88861942bf00 R15: ffff8886150f2000 FS: 0000000000000000(0000) GS:ffff888627a00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000047635 CR3: 000000000200a000 CR4: 00000000000006f0 Call Trace: <IRQ> _raw_spin_lock_irqsave+0x22/0x30 skb_queue_tail+0x1b/0x50 sock_queue_err_skb+0x9d/0xf0 __skb_complete_tx_timestamp+0x9d/0xc0 efx_dequeue_buffer+0x126/0x180 [sfc] efx_xmit_done+0x73/0x1c0 [sfc] efx_ef10_ev_process+0x56a/0xfe0 [sfc] ? tick_sched_do_timer+0x60/0x60 ? timerqueue_add+0x5d/0x70 ? enqueue_hrtimer+0x39/0x90 efx_poll+0x111/0x380 [sfc] ? rcu_accelerate_cbs+0x50/0x160 net_rx_action+0x14a/0x400 __do_softirq+0xdd/0x2d0 irq_exit+0xa0/0xb0 do_IRQ+0x53/0xe0 common_interrupt+0xf/0xf </IRQ> In the long run we intend to rewrite the channel allocation code, but for 'net' fix this by allocating extra_channels, and giving them TX queues, even if we do not in fact need them (e.g. on NICs without MAC TX timestamping), and thereby using simpler logic to assign the channels once they're allocated. Fixes: 3990a8f ("sfc: allocate channels for XDP tx queues") Signed-off-by: Edward Cree <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 258a980 commit 8700aff

File tree

2 files changed

+19
-22
lines changed

2 files changed

+19
-22
lines changed

drivers/net/ethernet/sfc/efx.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,12 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
14721472
n_xdp_tx = num_possible_cpus();
14731473
n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, EFX_TXQ_TYPES);
14741474

1475+
vec_count = pci_msix_vec_count(efx->pci_dev);
1476+
if (vec_count < 0)
1477+
return vec_count;
1478+
1479+
max_channels = min_t(unsigned int, vec_count, max_channels);
1480+
14751481
/* Check resources.
14761482
* We need a channel per event queue, plus a VI per tx queue.
14771483
* This may be more pessimistic than it needs to be.
@@ -1493,11 +1499,6 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
14931499
n_xdp_tx, n_xdp_ev);
14941500
}
14951501

1496-
n_channels = min(n_channels, max_channels);
1497-
1498-
vec_count = pci_msix_vec_count(efx->pci_dev);
1499-
if (vec_count < 0)
1500-
return vec_count;
15011502
if (vec_count < n_channels) {
15021503
netif_err(efx, drv, efx->net_dev,
15031504
"WARNING: Insufficient MSI-X vectors available (%d < %u).\n",
@@ -1507,11 +1508,9 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
15071508
n_channels = vec_count;
15081509
}
15091510

1510-
efx->n_channels = n_channels;
1511+
n_channels = min(n_channels, max_channels);
15111512

1512-
/* Do not create the PTP TX queue(s) if PTP uses the MC directly. */
1513-
if (extra_channels && !efx_ptp_use_mac_tx_timestamps(efx))
1514-
n_channels--;
1513+
efx->n_channels = n_channels;
15151514

15161515
/* Ignore XDP tx channels when creating rx channels. */
15171516
n_channels -= efx->n_xdp_channels;
@@ -1531,11 +1530,10 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
15311530
efx->n_rx_channels = n_channels;
15321531
}
15331532

1534-
if (efx->n_xdp_channels)
1535-
efx->xdp_channel_offset = efx->tx_channel_offset +
1536-
efx->n_tx_channels;
1537-
else
1538-
efx->xdp_channel_offset = efx->n_channels;
1533+
efx->n_rx_channels = min(efx->n_rx_channels, parallelism);
1534+
efx->n_tx_channels = min(efx->n_tx_channels, parallelism);
1535+
1536+
efx->xdp_channel_offset = n_channels;
15391537

15401538
netif_dbg(efx, drv, efx->net_dev,
15411539
"Allocating %u RX channels\n",
@@ -1550,6 +1548,7 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
15501548
static int efx_probe_interrupts(struct efx_nic *efx)
15511549
{
15521550
unsigned int extra_channels = 0;
1551+
unsigned int rss_spread;
15531552
unsigned int i, j;
15541553
int rc;
15551554

@@ -1631,8 +1630,7 @@ static int efx_probe_interrupts(struct efx_nic *efx)
16311630
for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
16321631
if (!efx->extra_channel_type[i])
16331632
continue;
1634-
if (efx->interrupt_mode != EFX_INT_MODE_MSIX ||
1635-
efx->n_channels <= extra_channels) {
1633+
if (j <= efx->tx_channel_offset + efx->n_tx_channels) {
16361634
efx->extra_channel_type[i]->handle_no_channel(efx);
16371635
} else {
16381636
--j;
@@ -1643,16 +1641,17 @@ static int efx_probe_interrupts(struct efx_nic *efx)
16431641
}
16441642
}
16451643

1644+
rss_spread = efx->n_rx_channels;
16461645
/* RSS might be usable on VFs even if it is disabled on the PF */
16471646
#ifdef CONFIG_SFC_SRIOV
16481647
if (efx->type->sriov_wanted) {
1649-
efx->rss_spread = ((efx->n_rx_channels > 1 ||
1648+
efx->rss_spread = ((rss_spread > 1 ||
16501649
!efx->type->sriov_wanted(efx)) ?
1651-
efx->n_rx_channels : efx_vf_size(efx));
1650+
rss_spread : efx_vf_size(efx));
16521651
return 0;
16531652
}
16541653
#endif
1655-
efx->rss_spread = efx->n_rx_channels;
1654+
efx->rss_spread = rss_spread;
16561655

16571656
return 0;
16581657
}

drivers/net/ethernet/sfc/net_driver.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,9 +1533,7 @@ static inline bool efx_channel_is_xdp_tx(struct efx_channel *channel)
15331533

15341534
static inline bool efx_channel_has_tx_queues(struct efx_channel *channel)
15351535
{
1536-
return efx_channel_is_xdp_tx(channel) ||
1537-
(channel->type && channel->type->want_txqs &&
1538-
channel->type->want_txqs(channel));
1536+
return true;
15391537
}
15401538

15411539
static inline struct efx_tx_queue *

0 commit comments

Comments
 (0)