Skip to content

Commit df2790b

Browse files
sreedeviintelgregkh
authored andcommitted
idpf: Fix RSS LUT NULL pointer crash on early ethtool operations
[ Upstream commit 83f38f2 ] The RSS LUT is not initialized until the interface comes up, causing the following NULL pointer crash when ethtool operations like rxhash on/off are performed before the interface is brought up for the first time. Move RSS LUT initialization from ndo_open to vport creation to ensure LUT is always available. This enables RSS configuration via ethtool before bringing the interface up. Simplify LUT management by maintaining all changes in the driver's soft copy and programming zeros to the indirection table when rxhash is disabled. Defer HW programming until the interface comes up if it is down during rxhash and LUT configuration changes. Steps to reproduce: ** Load idpf driver; interfaces will be created modprobe idpf ** Before bringing the interfaces up, turn rxhash off ethtool -K eth2 rxhash off [89408.371875] BUG: kernel NULL pointer dereference, address: 0000000000000000 [89408.371908] #PF: supervisor read access in kernel mode [89408.371924] #PF: error_code(0x0000) - not-present page [89408.371940] PGD 0 P4D 0 [89408.371953] Oops: Oops: 0000 [#1] SMP NOPTI <snip> [89408.372052] RIP: 0010:memcpy_orig+0x16/0x130 [89408.372310] Call Trace: [89408.372317] <TASK> [89408.372326] ? idpf_set_features+0xfc/0x180 [idpf] [89408.372363] __netdev_update_features+0x295/0xde0 [89408.372384] ethnl_set_features+0x15e/0x460 [89408.372406] genl_family_rcv_msg_doit+0x11f/0x180 [89408.372429] genl_rcv_msg+0x1ad/0x2b0 [89408.372446] ? __pfx_ethnl_set_features+0x10/0x10 [89408.372465] ? __pfx_genl_rcv_msg+0x10/0x10 [89408.372482] netlink_rcv_skb+0x58/0x100 [89408.372502] genl_rcv+0x2c/0x50 [89408.372516] netlink_unicast+0x289/0x3e0 [89408.372533] netlink_sendmsg+0x215/0x440 [89408.372551] __sys_sendto+0x234/0x240 [89408.372571] __x64_sys_sendto+0x28/0x30 [89408.372585] x64_sys_call+0x1909/0x1da0 [89408.372604] do_syscall_64+0x7a/0xfa0 [89408.373140] ? clear_bhb_loop+0x60/0xb0 [89408.373647] entry_SYSCALL_64_after_hwframe+0x76/0x7e [89408.378887] </TASK> <snip> Fixes: a251eee ("idpf: add SRIOV support and other ndo_ops") Signed-off-by: Sreedevi Joshi <sreedevi.joshi@intel.com> Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com> Reviewed-by: Emil Tantilov <emil.s.tantilov@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de> Reviewed-by: Simon Horman <horms@kernel.org> Tested-by: Samuel Salin <Samuel.salin@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> (cherry picked from commit 83f38f2) [Harshit: While this is a clean cherry-pick I had to change a line of code where test_bit(IDPF_VPORT_UP,..) is used because 6.12.y branch doesn't have commit: 8dd72eb ("idpf: convert vport state to bitmap")] Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 9ad3d08 commit df2790b

5 files changed

Lines changed: 66 additions & 79 deletions

File tree

drivers/net/ethernet/intel/idpf/idpf.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,12 @@ enum idpf_user_flags {
361361
* @rss_key: RSS hash key
362362
* @rss_lut_size: Size of RSS lookup table
363363
* @rss_lut: RSS lookup table
364-
* @cached_lut: Used to restore previously init RSS lut
365364
*/
366365
struct idpf_rss_data {
367366
u16 rss_key_size;
368367
u8 *rss_key;
369368
u16 rss_lut_size;
370369
u32 *rss_lut;
371-
u32 *cached_lut;
372370
};
373371

374372
/**

drivers/net/ethernet/intel/idpf/idpf_lib.c

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ static void idpf_vport_rel(struct idpf_vport *vport)
999999
u16 idx = vport->idx;
10001000

10011001
vport_config = adapter->vport_config[vport->idx];
1002-
idpf_deinit_rss(vport);
1002+
idpf_deinit_rss_lut(vport);
10031003
rss_data = &vport_config->user_config.rss_data;
10041004
kfree(rss_data->rss_key);
10051005
rss_data->rss_key = NULL;
@@ -1148,6 +1148,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
11481148
u16 idx = adapter->next_vport;
11491149
struct idpf_vport *vport;
11501150
u16 num_max_q;
1151+
int err;
11511152

11521153
if (idx == IDPF_NO_FREE_SLOT)
11531154
return NULL;
@@ -1198,10 +1199,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
11981199

11991200
idpf_vport_init(vport, max_q);
12001201

1201-
/* This alloc is done separate from the LUT because it's not strictly
1202-
* dependent on how many queues we have. If we change number of queues
1203-
* and soft reset we'll need a new LUT but the key can remain the same
1204-
* for as long as the vport exists.
1202+
/* LUT and key are both initialized here. Key is not strictly dependent
1203+
* on how many queues we have. If we change number of queues and soft
1204+
* reset is initiated, LUT will be freed and a new LUT will be allocated
1205+
* as per the updated number of queues during vport bringup. However,
1206+
* the key remains the same for as long as the vport exists.
12051207
*/
12061208
rss_data = &adapter->vport_config[idx]->user_config.rss_data;
12071209
rss_data->rss_key = kzalloc(rss_data->rss_key_size, GFP_KERNEL);
@@ -1211,6 +1213,11 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
12111213
/* Initialize default rss key */
12121214
netdev_rss_key_fill((void *)rss_data->rss_key, rss_data->rss_key_size);
12131215

1216+
/* Initialize default rss LUT */
1217+
err = idpf_init_rss_lut(vport);
1218+
if (err)
1219+
goto free_rss_key;
1220+
12141221
/* fill vport slot in the adapter struct */
12151222
adapter->vports[idx] = vport;
12161223
adapter->vport_ids[idx] = idpf_get_vport_id(vport);
@@ -1221,6 +1228,8 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
12211228

12221229
return vport;
12231230

1231+
free_rss_key:
1232+
kfree(rss_data->rss_key);
12241233
free_vector_idxs:
12251234
kfree(vport->q_vector_idxs);
12261235
free_vport:
@@ -1397,6 +1406,7 @@ static int idpf_vport_open(struct idpf_vport *vport)
13971406
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
13981407
struct idpf_adapter *adapter = vport->adapter;
13991408
struct idpf_vport_config *vport_config;
1409+
struct idpf_rss_data *rss_data;
14001410
int err;
14011411

14021412
if (np->state != __IDPF_VPORT_DOWN)
@@ -1479,12 +1489,21 @@ static int idpf_vport_open(struct idpf_vport *vport)
14791489
idpf_restore_features(vport);
14801490

14811491
vport_config = adapter->vport_config[vport->idx];
1482-
if (vport_config->user_config.rss_data.rss_lut)
1483-
err = idpf_config_rss(vport);
1484-
else
1485-
err = idpf_init_rss(vport);
1492+
rss_data = &vport_config->user_config.rss_data;
1493+
1494+
if (!rss_data->rss_lut) {
1495+
err = idpf_init_rss_lut(vport);
1496+
if (err) {
1497+
dev_err(&adapter->pdev->dev,
1498+
"Failed to initialize RSS LUT for vport %u: %d\n",
1499+
vport->vport_id, err);
1500+
goto disable_vport;
1501+
}
1502+
}
1503+
1504+
err = idpf_config_rss(vport);
14861505
if (err) {
1487-
dev_err(&adapter->pdev->dev, "Failed to initialize RSS for vport %u: %d\n",
1506+
dev_err(&adapter->pdev->dev, "Failed to configure RSS for vport %u: %d\n",
14881507
vport->vport_id, err);
14891508
goto disable_vport;
14901509
}
@@ -1493,13 +1512,11 @@ static int idpf_vport_open(struct idpf_vport *vport)
14931512
if (err) {
14941513
dev_err(&adapter->pdev->dev, "Failed to complete interface up for vport %u: %d\n",
14951514
vport->vport_id, err);
1496-
goto deinit_rss;
1515+
goto disable_vport;
14971516
}
14981517

14991518
return 0;
15001519

1501-
deinit_rss:
1502-
idpf_deinit_rss(vport);
15031520
disable_vport:
15041521
idpf_send_disable_vport_msg(vport);
15051522
disable_queues:
@@ -1936,7 +1953,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
19361953
idpf_vport_stop(vport);
19371954
}
19381955

1939-
idpf_deinit_rss(vport);
1956+
idpf_deinit_rss_lut(vport);
19401957
/* We're passing in vport here because we need its wait_queue
19411958
* to send a message and it should be getting all the vport
19421959
* config data out of the adapter but we need to be careful not
@@ -2102,40 +2119,6 @@ static void idpf_set_rx_mode(struct net_device *netdev)
21022119
dev_err(dev, "Failed to set promiscuous mode: %d\n", err);
21032120
}
21042121

2105-
/**
2106-
* idpf_vport_manage_rss_lut - disable/enable RSS
2107-
* @vport: the vport being changed
2108-
*
2109-
* In the event of disable request for RSS, this function will zero out RSS
2110-
* LUT, while in the event of enable request for RSS, it will reconfigure RSS
2111-
* LUT with the default LUT configuration.
2112-
*/
2113-
static int idpf_vport_manage_rss_lut(struct idpf_vport *vport)
2114-
{
2115-
bool ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH);
2116-
struct idpf_rss_data *rss_data;
2117-
u16 idx = vport->idx;
2118-
int lut_size;
2119-
2120-
rss_data = &vport->adapter->vport_config[idx]->user_config.rss_data;
2121-
lut_size = rss_data->rss_lut_size * sizeof(u32);
2122-
2123-
if (ena) {
2124-
/* This will contain the default or user configured LUT */
2125-
memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size);
2126-
} else {
2127-
/* Save a copy of the current LUT to be restored later if
2128-
* requested.
2129-
*/
2130-
memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size);
2131-
2132-
/* Zero out the current LUT to disable */
2133-
memset(rss_data->rss_lut, 0, lut_size);
2134-
}
2135-
2136-
return idpf_config_rss(vport);
2137-
}
2138-
21392122
/**
21402123
* idpf_set_features - set the netdev feature flags
21412124
* @netdev: ptr to the netdev being adjusted
@@ -2161,10 +2144,19 @@ static int idpf_set_features(struct net_device *netdev,
21612144
}
21622145

21632146
if (changed & NETIF_F_RXHASH) {
2147+
struct idpf_netdev_priv *np = netdev_priv(netdev);
2148+
21642149
netdev->features ^= NETIF_F_RXHASH;
2165-
err = idpf_vport_manage_rss_lut(vport);
2166-
if (err)
2167-
goto unlock_mutex;
2150+
2151+
/* If the interface is not up when changing the rxhash, update
2152+
* to the HW is skipped. The updated LUT will be committed to
2153+
* the HW when the interface is brought up.
2154+
*/
2155+
if (np->state == __IDPF_VPORT_UP) {
2156+
err = idpf_config_rss(vport);
2157+
if (err)
2158+
goto unlock_mutex;
2159+
}
21682160
}
21692161

21702162
if (changed & NETIF_F_GRO_HW) {

drivers/net/ethernet/intel/idpf/idpf_txrx.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4068,57 +4068,47 @@ static void idpf_fill_dflt_rss_lut(struct idpf_vport *vport)
40684068

40694069
rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
40704070

4071-
for (i = 0; i < rss_data->rss_lut_size; i++) {
4071+
for (i = 0; i < rss_data->rss_lut_size; i++)
40724072
rss_data->rss_lut[i] = i % num_active_rxq;
4073-
rss_data->cached_lut[i] = rss_data->rss_lut[i];
4074-
}
40754073
}
40764074

40774075
/**
4078-
* idpf_init_rss - Allocate and initialize RSS resources
4076+
* idpf_init_rss_lut - Allocate and initialize RSS LUT
40794077
* @vport: virtual port
40804078
*
4081-
* Return 0 on success, negative on failure
4079+
* Return: 0 on success, negative on failure
40824080
*/
4083-
int idpf_init_rss(struct idpf_vport *vport)
4081+
int idpf_init_rss_lut(struct idpf_vport *vport)
40844082
{
40854083
struct idpf_adapter *adapter = vport->adapter;
40864084
struct idpf_rss_data *rss_data;
4087-
u32 lut_size;
40884085

40894086
rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
4087+
if (!rss_data->rss_lut) {
4088+
u32 lut_size;
40904089

4091-
lut_size = rss_data->rss_lut_size * sizeof(u32);
4092-
rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL);
4093-
if (!rss_data->rss_lut)
4094-
return -ENOMEM;
4095-
4096-
rss_data->cached_lut = kzalloc(lut_size, GFP_KERNEL);
4097-
if (!rss_data->cached_lut) {
4098-
kfree(rss_data->rss_lut);
4099-
rss_data->rss_lut = NULL;
4100-
4101-
return -ENOMEM;
4090+
lut_size = rss_data->rss_lut_size * sizeof(u32);
4091+
rss_data->rss_lut = kzalloc(lut_size, GFP_KERNEL);
4092+
if (!rss_data->rss_lut)
4093+
return -ENOMEM;
41024094
}
41034095

41044096
/* Fill the default RSS lut values */
41054097
idpf_fill_dflt_rss_lut(vport);
41064098

4107-
return idpf_config_rss(vport);
4099+
return 0;
41084100
}
41094101

41104102
/**
4111-
* idpf_deinit_rss - Release RSS resources
4103+
* idpf_deinit_rss_lut - Release RSS LUT
41124104
* @vport: virtual port
41134105
*/
4114-
void idpf_deinit_rss(struct idpf_vport *vport)
4106+
void idpf_deinit_rss_lut(struct idpf_vport *vport)
41154107
{
41164108
struct idpf_adapter *adapter = vport->adapter;
41174109
struct idpf_rss_data *rss_data;
41184110

41194111
rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
4120-
kfree(rss_data->cached_lut);
4121-
rss_data->cached_lut = NULL;
41224112
kfree(rss_data->rss_lut);
41234113
rss_data->rss_lut = NULL;
41244114
}

drivers/net/ethernet/intel/idpf/idpf_txrx.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,8 +1018,8 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport);
10181018
int idpf_vport_intr_init(struct idpf_vport *vport);
10191019
void idpf_vport_intr_ena(struct idpf_vport *vport);
10201020
int idpf_config_rss(struct idpf_vport *vport);
1021-
int idpf_init_rss(struct idpf_vport *vport);
1022-
void idpf_deinit_rss(struct idpf_vport *vport);
1021+
int idpf_init_rss_lut(struct idpf_vport *vport);
1022+
void idpf_deinit_rss_lut(struct idpf_vport *vport);
10231023
int idpf_rx_bufs_init_all(struct idpf_vport *vport);
10241024
void idpf_rx_add_frag(struct idpf_rx_buf *rx_buf, struct sk_buff *skb,
10251025
unsigned int size);

drivers/net/ethernet/intel/idpf/idpf_virtchnl.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2341,6 +2341,10 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport)
23412341
* @vport: virtual port data structure
23422342
* @get: flag to set or get rss look up table
23432343
*
2344+
* When rxhash is disabled, RSS LUT will be configured with zeros. If rxhash
2345+
* is enabled, the LUT values stored in driver's soft copy will be used to setup
2346+
* the HW.
2347+
*
23442348
* Returns 0 on success, negative on failure.
23452349
*/
23462350
int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
@@ -2351,10 +2355,12 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
23512355
struct idpf_rss_data *rss_data;
23522356
int buf_size, lut_buf_size;
23532357
ssize_t reply_sz;
2358+
bool rxhash_ena;
23542359
int i;
23552360

23562361
rss_data =
23572362
&vport->adapter->vport_config[vport->idx]->user_config.rss_data;
2363+
rxhash_ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH);
23582364
buf_size = struct_size(rl, lut, rss_data->rss_lut_size);
23592365
rl = kzalloc(buf_size, GFP_KERNEL);
23602366
if (!rl)
@@ -2376,7 +2382,8 @@ int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get)
23762382
} else {
23772383
rl->lut_entries = cpu_to_le16(rss_data->rss_lut_size);
23782384
for (i = 0; i < rss_data->rss_lut_size; i++)
2379-
rl->lut[i] = cpu_to_le32(rss_data->rss_lut[i]);
2385+
rl->lut[i] = rxhash_ena ?
2386+
cpu_to_le32(rss_data->rss_lut[i]) : 0;
23802387

23812388
xn_params.vc_op = VIRTCHNL2_OP_SET_RSS_LUT;
23822389
}

0 commit comments

Comments
 (0)