Skip to content

Commit 37d318d

Browse files
aloktionJeff Kirsher
authored andcommitted
i40e: Remove scheduling while atomic possibility
In some occasions task held spinlock (mac_filter_hash_lock), while being rescheduled due to admin queue mutex_lock. The struct i40e_spinlock asq_spinlock, which later expands to struct mutex spinlock. Moved i40e_aq_set_vsi_multicast_promiscuous(), i40e_aq_set_vsi_unicast_promiscuous(), i40e_aq_set_vsi_mc_promisc_on_vlan(), and i40e_aq_set_vsi_uc_promisc_on_vlan() outside of atomic context. Without this patch there is a race condition, which might result in scheduling while in atomic context. The race condition is between the thread, which holds mac_filter_hash_lock, while trying to acquire an admin queue mutex and a thread, which already has said admin queue mutex. The thread, which holds spinlock, fails to acquire the mutex, which causes this thread to sleep. Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
1 parent 3dbdd6c commit 37d318d

File tree

1 file changed

+137
-97
lines changed

1 file changed

+137
-97
lines changed

drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c

Lines changed: 137 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,39 +1106,81 @@ static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
11061106
return -EIO;
11071107
}
11081108

1109-
static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi);
1109+
/**
1110+
* i40e_getnum_vf_vsi_vlan_filters
1111+
* @vsi: pointer to the vsi
1112+
*
1113+
* called to get the number of VLANs offloaded on this VF
1114+
**/
1115+
static int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
1116+
{
1117+
struct i40e_mac_filter *f;
1118+
int num_vlans = 0, bkt;
1119+
1120+
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
1121+
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
1122+
num_vlans++;
1123+
}
1124+
1125+
return num_vlans;
1126+
}
11101127

11111128
/**
1112-
* i40e_config_vf_promiscuous_mode
1113-
* @vf: pointer to the VF info
1114-
* @vsi_id: VSI id
1115-
* @allmulti: set MAC L2 layer multicast promiscuous enable/disable
1116-
* @alluni: set MAC L2 layer unicast promiscuous enable/disable
1129+
* i40e_get_vlan_list_sync
1130+
* @vsi: pointer to the VSI
1131+
* @num_vlans: number of VLANs in mac_filter_hash, returned to caller
1132+
* @vlan_list: list of VLANs present in mac_filter_hash, returned to caller.
1133+
* This array is allocated here, but has to be freed in caller.
11171134
*
1118-
* Called from the VF to configure the promiscuous mode of
1119-
* VF vsis and from the VF reset path to reset promiscuous mode.
1135+
* Called to get number of VLANs and VLAN list present in mac_filter_hash.
11201136
**/
1121-
static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
1122-
u16 vsi_id,
1123-
bool allmulti,
1124-
bool alluni)
1137+
static void i40e_get_vlan_list_sync(struct i40e_vsi *vsi, int *num_vlans,
1138+
s16 **vlan_list)
11251139
{
1126-
struct i40e_pf *pf = vf->pf;
1127-
struct i40e_hw *hw = &pf->hw;
11281140
struct i40e_mac_filter *f;
1129-
i40e_status aq_ret = 0;
1130-
struct i40e_vsi *vsi;
1141+
int i = 0;
11311142
int bkt;
11321143

1133-
vsi = i40e_find_vsi_from_id(pf, vsi_id);
1134-
if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
1135-
return I40E_ERR_PARAM;
1144+
spin_lock_bh(&vsi->mac_filter_hash_lock);
1145+
*num_vlans = i40e_getnum_vf_vsi_vlan_filters(vsi);
1146+
*vlan_list = kcalloc(*num_vlans, sizeof(**vlan_list), GFP_ATOMIC);
1147+
if (!(*vlan_list))
1148+
goto err;
11361149

1137-
if (vf->port_vlan_id) {
1138-
aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
1139-
allmulti,
1140-
vf->port_vlan_id,
1141-
NULL);
1150+
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
1151+
if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
1152+
continue;
1153+
(*vlan_list)[i++] = f->vlan;
1154+
}
1155+
err:
1156+
spin_unlock_bh(&vsi->mac_filter_hash_lock);
1157+
}
1158+
1159+
/**
1160+
* i40e_set_vsi_promisc
1161+
* @vf: pointer to the VF struct
1162+
* @seid: VSI number
1163+
* @multi_enable: set MAC L2 layer multicast promiscuous enable/disable
1164+
* for a given VLAN
1165+
* @unicast_enable: set MAC L2 layer unicast promiscuous enable/disable
1166+
* for a given VLAN
1167+
* @vl: List of VLANs - apply filter for given VLANs
1168+
* @num_vlans: Number of elements in @vl
1169+
**/
1170+
static i40e_status
1171+
i40e_set_vsi_promisc(struct i40e_vf *vf, u16 seid, bool multi_enable,
1172+
bool unicast_enable, s16 *vl, int num_vlans)
1173+
{
1174+
struct i40e_pf *pf = vf->pf;
1175+
struct i40e_hw *hw = &pf->hw;
1176+
i40e_status aq_ret;
1177+
int i;
1178+
1179+
/* No VLAN to set promisc on, set on VSI */
1180+
if (!num_vlans || !vl) {
1181+
aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, seid,
1182+
multi_enable,
1183+
NULL);
11421184
if (aq_ret) {
11431185
int aq_err = pf->hw.aq.asq_last_status;
11441186

@@ -1147,13 +1189,14 @@ static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
11471189
vf->vf_id,
11481190
i40e_stat_str(&pf->hw, aq_ret),
11491191
i40e_aq_str(&pf->hw, aq_err));
1192+
11501193
return aq_ret;
11511194
}
11521195

1153-
aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
1154-
alluni,
1155-
vf->port_vlan_id,
1156-
NULL);
1196+
aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, seid,
1197+
unicast_enable,
1198+
NULL, true);
1199+
11571200
if (aq_ret) {
11581201
int aq_err = pf->hw.aq.asq_last_status;
11591202

@@ -1163,68 +1206,84 @@ static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
11631206
i40e_stat_str(&pf->hw, aq_ret),
11641207
i40e_aq_str(&pf->hw, aq_err));
11651208
}
1209+
11661210
return aq_ret;
1167-
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
1168-
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
1169-
if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
1170-
continue;
1171-
aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
1172-
vsi->seid,
1173-
allmulti,
1174-
f->vlan,
1175-
NULL);
1176-
if (aq_ret) {
1177-
int aq_err = pf->hw.aq.asq_last_status;
1211+
}
11781212

1179-
dev_err(&pf->pdev->dev,
1180-
"Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
1181-
f->vlan,
1182-
i40e_stat_str(&pf->hw, aq_ret),
1183-
i40e_aq_str(&pf->hw, aq_err));
1184-
}
1213+
for (i = 0; i < num_vlans; i++) {
1214+
aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, seid,
1215+
multi_enable,
1216+
vl[i], NULL);
1217+
if (aq_ret) {
1218+
int aq_err = pf->hw.aq.asq_last_status;
1219+
1220+
dev_err(&pf->pdev->dev,
1221+
"VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
1222+
vf->vf_id,
1223+
i40e_stat_str(&pf->hw, aq_ret),
1224+
i40e_aq_str(&pf->hw, aq_err));
1225+
}
11851226

1186-
aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
1187-
vsi->seid,
1188-
alluni,
1189-
f->vlan,
1190-
NULL);
1191-
if (aq_ret) {
1192-
int aq_err = pf->hw.aq.asq_last_status;
1227+
aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, seid,
1228+
unicast_enable,
1229+
vl[i], NULL);
1230+
if (aq_ret) {
1231+
int aq_err = pf->hw.aq.asq_last_status;
11931232

1194-
dev_err(&pf->pdev->dev,
1195-
"Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
1196-
f->vlan,
1197-
i40e_stat_str(&pf->hw, aq_ret),
1198-
i40e_aq_str(&pf->hw, aq_err));
1199-
}
1233+
dev_err(&pf->pdev->dev,
1234+
"VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
1235+
vf->vf_id,
1236+
i40e_stat_str(&pf->hw, aq_ret),
1237+
i40e_aq_str(&pf->hw, aq_err));
12001238
}
1201-
return aq_ret;
12021239
}
1203-
aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti,
1204-
NULL);
1205-
if (aq_ret) {
1206-
int aq_err = pf->hw.aq.asq_last_status;
1240+
return aq_ret;
1241+
}
12071242

1208-
dev_err(&pf->pdev->dev,
1209-
"VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
1210-
vf->vf_id,
1211-
i40e_stat_str(&pf->hw, aq_ret),
1212-
i40e_aq_str(&pf->hw, aq_err));
1243+
/**
1244+
* i40e_config_vf_promiscuous_mode
1245+
* @vf: pointer to the VF info
1246+
* @vsi_id: VSI id
1247+
* @allmulti: set MAC L2 layer multicast promiscuous enable/disable
1248+
* @alluni: set MAC L2 layer unicast promiscuous enable/disable
1249+
*
1250+
* Called from the VF to configure the promiscuous mode of
1251+
* VF vsis and from the VF reset path to reset promiscuous mode.
1252+
**/
1253+
static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
1254+
u16 vsi_id,
1255+
bool allmulti,
1256+
bool alluni)
1257+
{
1258+
i40e_status aq_ret = I40E_SUCCESS;
1259+
struct i40e_pf *pf = vf->pf;
1260+
struct i40e_vsi *vsi;
1261+
int num_vlans;
1262+
s16 *vl;
1263+
1264+
vsi = i40e_find_vsi_from_id(pf, vsi_id);
1265+
if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
1266+
return I40E_ERR_PARAM;
1267+
1268+
if (vf->port_vlan_id) {
1269+
aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti,
1270+
alluni, &vf->port_vlan_id, 1);
12131271
return aq_ret;
1214-
}
1272+
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
1273+
i40e_get_vlan_list_sync(vsi, &num_vlans, &vl);
12151274

1216-
aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, alluni,
1217-
NULL, true);
1218-
if (aq_ret) {
1219-
int aq_err = pf->hw.aq.asq_last_status;
1275+
if (!vl)
1276+
return I40E_ERR_NO_MEMORY;
12201277

1221-
dev_err(&pf->pdev->dev,
1222-
"VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
1223-
vf->vf_id,
1224-
i40e_stat_str(&pf->hw, aq_ret),
1225-
i40e_aq_str(&pf->hw, aq_err));
1278+
aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti, alluni,
1279+
vl, num_vlans);
1280+
kfree(vl);
1281+
return aq_ret;
12261282
}
12271283

1284+
/* no VLANs to set on, set on VSI */
1285+
aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti, alluni,
1286+
NULL, 0);
12281287
return aq_ret;
12291288
}
12301289

@@ -1972,25 +2031,6 @@ static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
19722031
i40e_reset_vf(vf, false);
19732032
}
19742033

1975-
/**
1976-
* i40e_getnum_vf_vsi_vlan_filters
1977-
* @vsi: pointer to the vsi
1978-
*
1979-
* called to get the number of VLANs offloaded on this VF
1980-
**/
1981-
static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
1982-
{
1983-
struct i40e_mac_filter *f;
1984-
int num_vlans = 0, bkt;
1985-
1986-
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
1987-
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
1988-
num_vlans++;
1989-
}
1990-
1991-
return num_vlans;
1992-
}
1993-
19942034
/**
19952035
* i40e_vc_config_promiscuous_mode_msg
19962036
* @vf: pointer to the VF info

0 commit comments

Comments
 (0)