Commit 06d53b03 authored by David S. Miller's avatar David S. Miller

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next

-queue

Tony Nguyen says:

====================
i40e: Simplify VSI and VEB handling

Ivan Vecera says:

The series simplifies handling of VSIs and VEBs by introducing for-each
iterating macros, 'find' helper functions. Also removes the VEB
recursion because the VEBs cannot have sub-VEBs according datasheet and
fixes the support for floating VEBs.

The series content:
Patch 1 - Uses existing helper function for find FDIR VSI instead of loop
Patch 2 - Adds and uses macros to iterate VSI and VEB arrays
Patch 3 - Adds 2 helper functions to find VSIs and VEBs by their SEID
Patch 4 - Fixes broken support for floating VEBs
Patch 5 - Removes VEB recursion and simplifies VEB handling
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d0bcc15c f09cbb6c
...@@ -686,6 +686,54 @@ struct i40e_pf { ...@@ -686,6 +686,54 @@ struct i40e_pf {
struct list_head ddp_old_prof; struct list_head ddp_old_prof;
}; };
/**
* __i40e_pf_next_vsi - get next valid VSI
* @pf: pointer to the PF struct
* @idx: pointer to start position number
*
* Find and return next non-NULL VSI pointer in pf->vsi array and
* updates idx position. Returns NULL if no VSI is found.
**/
static __always_inline struct i40e_vsi *
__i40e_pf_next_vsi(struct i40e_pf *pf, int *idx)
{
while (*idx < pf->num_alloc_vsi) {
if (pf->vsi[*idx])
return pf->vsi[*idx];
(*idx)++;
}
return NULL;
}
#define i40e_pf_for_each_vsi(_pf, _i, _vsi) \
for (_i = 0, _vsi = __i40e_pf_next_vsi(_pf, &_i); \
_vsi; \
_i++, _vsi = __i40e_pf_next_vsi(_pf, &_i))
/**
* __i40e_pf_next_veb - get next valid VEB
* @pf: pointer to the PF struct
* @idx: pointer to start position number
*
* Find and return next non-NULL VEB pointer in pf->veb array and
* updates idx position. Returns NULL if no VEB is found.
**/
static __always_inline struct i40e_veb *
__i40e_pf_next_veb(struct i40e_pf *pf, int *idx)
{
while (*idx < I40E_MAX_VEB) {
if (pf->veb[*idx])
return pf->veb[*idx];
(*idx)++;
}
return NULL;
}
#define i40e_pf_for_each_veb(_pf, _i, _veb) \
for (_i = 0, _veb = __i40e_pf_next_veb(_pf, &_i); \
_veb; \
_i++, _veb = __i40e_pf_next_veb(_pf, &_i))
/** /**
* i40e_mac_to_hkey - Convert a 6-byte MAC Address to a u64 hash key * i40e_mac_to_hkey - Convert a 6-byte MAC Address to a u64 hash key
* @macaddr: the MAC Address as the base key * @macaddr: the MAC Address as the base key
...@@ -735,7 +783,6 @@ struct i40e_new_mac_filter { ...@@ -735,7 +783,6 @@ struct i40e_new_mac_filter {
struct i40e_veb { struct i40e_veb {
struct i40e_pf *pf; struct i40e_pf *pf;
u16 idx; u16 idx;
u16 veb_idx; /* index of VEB parent */
u16 seid; u16 seid;
u16 uplink_seid; u16 uplink_seid;
u16 stats_idx; /* index of VEB parent */ u16 stats_idx; /* index of VEB parent */
...@@ -1120,14 +1167,12 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id); ...@@ -1120,14 +1167,12 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id);
static inline struct i40e_vsi * static inline struct i40e_vsi *
i40e_find_vsi_by_type(struct i40e_pf *pf, u16 type) i40e_find_vsi_by_type(struct i40e_pf *pf, u16 type)
{ {
struct i40e_vsi *vsi;
int i; int i;
for (i = 0; i < pf->num_alloc_vsi; i++) { i40e_pf_for_each_vsi(pf, i, vsi)
struct i40e_vsi *vsi = pf->vsi[i]; if (vsi->type == type)
if (vsi && vsi->type == type)
return vsi; return vsi;
}
return NULL; return NULL;
} }
...@@ -1309,4 +1354,40 @@ static inline struct i40e_pf *i40e_hw_to_pf(struct i40e_hw *hw) ...@@ -1309,4 +1354,40 @@ static inline struct i40e_pf *i40e_hw_to_pf(struct i40e_hw *hw)
struct device *i40e_hw_to_dev(struct i40e_hw *hw); struct device *i40e_hw_to_dev(struct i40e_hw *hw);
/**
* i40e_pf_get_vsi_by_seid - find VSI by SEID
* @pf: pointer to a PF
* @seid: SEID of the VSI
**/
static inline struct i40e_vsi *
i40e_pf_get_vsi_by_seid(struct i40e_pf *pf, u16 seid)
{
struct i40e_vsi *vsi;
int i;
i40e_pf_for_each_vsi(pf, i, vsi)
if (vsi->seid == seid)
return vsi;
return NULL;
}
/**
* i40e_pf_get_veb_by_seid - find VEB by SEID
* @pf: pointer to a PF
* @seid: SEID of the VSI
**/
static inline struct i40e_veb *
i40e_pf_get_veb_by_seid(struct i40e_pf *pf, u16 seid)
{
struct i40e_veb *veb;
int i;
i40e_pf_for_each_veb(pf, i, veb)
if (veb->seid == seid)
return veb;
return NULL;
}
#endif /* _I40E_H_ */ #endif /* _I40E_H_ */
...@@ -947,16 +947,16 @@ static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi, ...@@ -947,16 +947,16 @@ static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
static void i40e_dcbnl_del_app(struct i40e_pf *pf, static void i40e_dcbnl_del_app(struct i40e_pf *pf,
struct i40e_dcb_app_priority_table *app) struct i40e_dcb_app_priority_table *app)
{ {
struct i40e_vsi *vsi;
int v, err; int v, err;
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi)
if (pf->vsi[v] && pf->vsi[v]->netdev) { if (vsi->netdev) {
err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app); err = i40e_dcbnl_vsi_del_app(vsi, app);
dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n", dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",
pf->vsi[v]->seid, err, app->selector, vsi->seid, err, app->selector,
app->protocolid, app->priority); app->protocolid, app->priority);
} }
}
} }
/** /**
......
...@@ -24,31 +24,13 @@ enum ring_type { ...@@ -24,31 +24,13 @@ enum ring_type {
**/ **/
static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid)
{ {
int i; if (seid < 0) {
if (seid < 0)
dev_info(&pf->pdev->dev, "%d: bad seid\n", seid); dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
else
for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i] && (pf->vsi[i]->seid == seid))
return pf->vsi[i];
return NULL; return NULL;
} }
/**
* i40e_dbg_find_veb - searches for the veb with the given seid
* @pf: the PF structure to search for the veb
* @seid: seid of the veb it is searching for
**/
static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
{
int i;
for (i = 0; i < I40E_MAX_VEB; i++) return i40e_pf_get_vsi_by_seid(pf, seid);
if (pf->veb[i] && pf->veb[i]->seid == seid)
return pf->veb[i];
return NULL;
} }
/************************************************************** /**************************************************************
...@@ -653,12 +635,11 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n, ...@@ -653,12 +635,11 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
**/ **/
static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf) static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int i; int i;
for (i = 0; i < pf->num_alloc_vsi; i++) i40e_pf_for_each_vsi(pf, i, vsi)
if (pf->vsi[i]) dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n", i, vsi->seid);
dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n",
i, pf->vsi[i]->seid);
} }
/** /**
...@@ -696,15 +677,14 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid) ...@@ -696,15 +677,14 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid)
{ {
struct i40e_veb *veb; struct i40e_veb *veb;
veb = i40e_dbg_find_veb(pf, seid); veb = i40e_pf_get_veb_by_seid(pf, seid);
if (!veb) { if (!veb) {
dev_info(&pf->pdev->dev, "can't find veb %d\n", seid); dev_info(&pf->pdev->dev, "can't find veb %d\n", seid);
return; return;
} }
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"veb idx=%d,%d stats_ic=%d seid=%d uplink=%d mode=%s\n", "veb idx=%d stats_ic=%d seid=%d uplink=%d mode=%s\n",
veb->idx, veb->veb_idx, veb->stats_idx, veb->seid, veb->idx, veb->stats_idx, veb->seid, veb->uplink_seid,
veb->uplink_seid,
veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); veb->bridge_mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB");
i40e_dbg_dump_eth_stats(pf, &veb->stats); i40e_dbg_dump_eth_stats(pf, &veb->stats);
} }
...@@ -718,11 +698,8 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf) ...@@ -718,11 +698,8 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
struct i40e_veb *veb; struct i40e_veb *veb;
int i; int i;
for (i = 0; i < I40E_MAX_VEB; i++) { i40e_pf_for_each_veb(pf, i, veb)
veb = pf->veb[i];
if (veb)
i40e_dbg_dump_veb_seid(pf, veb->seid); i40e_dbg_dump_veb_seid(pf, veb->seid);
}
} }
/** /**
...@@ -851,10 +828,14 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -851,10 +828,14 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
} else if (strncmp(cmd_buf, "add relay", 9) == 0) { } else if (strncmp(cmd_buf, "add relay", 9) == 0) {
struct i40e_veb *veb; struct i40e_veb *veb;
int uplink_seid, i; u8 enabled_tc = 0x1;
int uplink_seid;
cnt = sscanf(&cmd_buf[9], "%i %i", &uplink_seid, &vsi_seid); cnt = sscanf(&cmd_buf[9], "%i %i", &uplink_seid, &vsi_seid);
if (cnt != 2) { if (cnt == 0) {
uplink_seid = 0;
vsi_seid = 0;
} else if (cnt != 2) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"add relay: bad command string, cnt=%d\n", "add relay: bad command string, cnt=%d\n",
cnt); cnt);
...@@ -866,33 +847,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -866,33 +847,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
goto command_write_done; goto command_write_done;
} }
vsi = i40e_dbg_find_vsi(pf, vsi_seid); if (uplink_seid != 0 && uplink_seid != pf->mac_seid) {
dev_info(&pf->pdev->dev,
"add relay: relay uplink %d not found\n",
uplink_seid);
goto command_write_done;
} else if (uplink_seid) {
vsi = i40e_pf_get_vsi_by_seid(pf, vsi_seid);
if (!vsi) { if (!vsi) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"add relay: VSI %d not found\n", vsi_seid); "add relay: VSI %d not found\n",
vsi_seid);
goto command_write_done; goto command_write_done;
} }
enabled_tc = vsi->tc_config.enabled_tc;
for (i = 0; i < I40E_MAX_VEB; i++) } else if (vsi_seid) {
if (pf->veb[i] && pf->veb[i]->seid == uplink_seid)
break;
if (i >= I40E_MAX_VEB && uplink_seid != 0 &&
uplink_seid != pf->mac_seid) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"add relay: relay uplink %d not found\n", "add relay: VSI must be 0 for floating relay\n");
uplink_seid);
goto command_write_done; goto command_write_done;
} }
veb = i40e_veb_setup(pf, 0, uplink_seid, vsi_seid, veb = i40e_veb_setup(pf, 0, uplink_seid, vsi_seid, enabled_tc);
vsi->tc_config.enabled_tc);
if (veb) if (veb)
dev_info(&pf->pdev->dev, "added relay %d\n", veb->seid); dev_info(&pf->pdev->dev, "added relay %d\n", veb->seid);
else else
dev_info(&pf->pdev->dev, "add relay failed\n"); dev_info(&pf->pdev->dev, "add relay failed\n");
} else if (strncmp(cmd_buf, "del relay", 9) == 0) { } else if (strncmp(cmd_buf, "del relay", 9) == 0) {
struct i40e_veb *veb;
int i; int i;
cnt = sscanf(&cmd_buf[9], "%i", &veb_seid); cnt = sscanf(&cmd_buf[9], "%i", &veb_seid);
if (cnt != 1) { if (cnt != 1) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
...@@ -906,9 +890,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -906,9 +890,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
} }
/* find the veb */ /* find the veb */
for (i = 0; i < I40E_MAX_VEB; i++) i40e_pf_for_each_veb(pf, i, veb)
if (pf->veb[i] && pf->veb[i]->seid == veb_seid) if (veb->seid == veb_seid)
break; break;
if (i >= I40E_MAX_VEB) { if (i >= I40E_MAX_VEB) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"del relay: relay %d not found\n", veb_seid); "del relay: relay %d not found\n", veb_seid);
...@@ -916,7 +901,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -916,7 +901,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
} }
dev_info(&pf->pdev->dev, "deleting relay %d\n", veb_seid); dev_info(&pf->pdev->dev, "deleting relay %d\n", veb_seid);
i40e_veb_release(pf->veb[i]); i40e_veb_release(veb);
} else if (strncmp(cmd_buf, "add pvid", 8) == 0) { } else if (strncmp(cmd_buf, "add pvid", 8) == 0) {
unsigned int v; unsigned int v;
int ret; int ret;
...@@ -1251,8 +1236,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -1251,8 +1236,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
if (cnt == 0) { if (cnt == 0) {
int i; int i;
for (i = 0; i < pf->num_alloc_vsi; i++) i40e_pf_for_each_vsi(pf, i, vsi)
i40e_vsi_reset_stats(pf->vsi[i]); i40e_vsi_reset_stats(vsi);
dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n"); dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n");
} else if (cnt == 1) { } else if (cnt == 1) {
vsi = i40e_dbg_find_vsi(pf, vsi_seid); vsi = i40e_dbg_find_vsi(pf, vsi_seid);
......
...@@ -310,11 +310,12 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id) ...@@ -310,11 +310,12 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
**/ **/
struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id) struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)
{ {
struct i40e_vsi *vsi;
int i; int i;
for (i = 0; i < pf->num_alloc_vsi; i++) i40e_pf_for_each_vsi(pf, i, vsi)
if (pf->vsi[i] && (pf->vsi[i]->id == id)) if (vsi->id == id)
return pf->vsi[i]; return vsi;
return NULL; return NULL;
} }
...@@ -552,24 +553,19 @@ void i40e_vsi_reset_stats(struct i40e_vsi *vsi) ...@@ -552,24 +553,19 @@ void i40e_vsi_reset_stats(struct i40e_vsi *vsi)
**/ **/
void i40e_pf_reset_stats(struct i40e_pf *pf) void i40e_pf_reset_stats(struct i40e_pf *pf)
{ {
struct i40e_veb *veb;
int i; int i;
memset(&pf->stats, 0, sizeof(pf->stats)); memset(&pf->stats, 0, sizeof(pf->stats));
memset(&pf->stats_offsets, 0, sizeof(pf->stats_offsets)); memset(&pf->stats_offsets, 0, sizeof(pf->stats_offsets));
pf->stat_offsets_loaded = false; pf->stat_offsets_loaded = false;
for (i = 0; i < I40E_MAX_VEB; i++) { i40e_pf_for_each_veb(pf, i, veb) {
if (pf->veb[i]) { memset(&veb->stats, 0, sizeof(veb->stats));
memset(&pf->veb[i]->stats, 0, memset(&veb->stats_offsets, 0, sizeof(veb->stats_offsets));
sizeof(pf->veb[i]->stats)); memset(&veb->tc_stats, 0, sizeof(veb->tc_stats));
memset(&pf->veb[i]->stats_offsets, 0, memset(&veb->tc_stats_offsets, 0, sizeof(veb->tc_stats_offsets));
sizeof(pf->veb[i]->stats_offsets)); veb->stat_offsets_loaded = false;
memset(&pf->veb[i]->tc_stats, 0,
sizeof(pf->veb[i]->tc_stats));
memset(&pf->veb[i]->tc_stats_offsets, 0,
sizeof(pf->veb[i]->tc_stats_offsets));
pf->veb[i]->stat_offsets_loaded = false;
}
} }
pf->hw_csum_rx_error = 0; pf->hw_csum_rx_error = 0;
} }
...@@ -2879,6 +2875,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -2879,6 +2875,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
**/ **/
static void i40e_sync_filters_subtask(struct i40e_pf *pf) static void i40e_sync_filters_subtask(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int v; int v;
if (!pf) if (!pf)
...@@ -2890,11 +2887,10 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf) ...@@ -2890,11 +2887,10 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
return; return;
} }
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi) {
if (pf->vsi[v] && if ((vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) &&
(pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED) && !test_bit(__I40E_VSI_RELEASING, vsi->state)) {
!test_bit(__I40E_VSI_RELEASING, pf->vsi[v]->state)) { int ret = i40e_sync_vsi_filters(vsi);
int ret = i40e_sync_vsi_filters(pf->vsi[v]);
if (ret) { if (ret) {
/* come back and try again later */ /* come back and try again later */
...@@ -5166,6 +5162,7 @@ static void i40e_reset_interrupt_capability(struct i40e_pf *pf) ...@@ -5166,6 +5162,7 @@ static void i40e_reset_interrupt_capability(struct i40e_pf *pf)
**/ **/
static void i40e_clear_interrupt_scheme(struct i40e_pf *pf) static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int i; int i;
if (test_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) if (test_bit(__I40E_MISC_IRQ_REQUESTED, pf->state))
...@@ -5175,9 +5172,10 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf) ...@@ -5175,9 +5172,10 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
I40E_IWARP_IRQ_PILE_ID); I40E_IWARP_IRQ_PILE_ID);
i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1); i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1);
for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i]) i40e_pf_for_each_vsi(pf, i, vsi)
i40e_vsi_free_q_vectors(pf->vsi[i]); i40e_vsi_free_q_vectors(vsi);
i40e_reset_interrupt_capability(pf); i40e_reset_interrupt_capability(pf);
} }
...@@ -5274,12 +5272,11 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi) ...@@ -5274,12 +5272,11 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi)
**/ **/
static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf) static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int v; int v;
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi)
if (pf->vsi[v]) i40e_quiesce_vsi(vsi);
i40e_quiesce_vsi(pf->vsi[v]);
}
} }
/** /**
...@@ -5288,12 +5285,11 @@ static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf) ...@@ -5288,12 +5285,11 @@ static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf)
**/ **/
static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf) static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int v; int v;
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi)
if (pf->vsi[v]) i40e_unquiesce_vsi(vsi);
i40e_unquiesce_vsi(pf->vsi[v]);
}
} }
/** /**
...@@ -5354,15 +5350,14 @@ int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi) ...@@ -5354,15 +5350,14 @@ int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi)
**/ **/
static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf) static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int v, ret = 0; int v, ret = 0;
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi) {
if (pf->vsi[v]) { ret = i40e_vsi_wait_queues_disabled(vsi);
ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
if (ret) if (ret)
break; break;
} }
}
return ret; return ret;
} }
...@@ -6778,32 +6773,29 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) ...@@ -6778,32 +6773,29 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc)
**/ **/
static void i40e_dcb_reconfigure(struct i40e_pf *pf) static void i40e_dcb_reconfigure(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
struct i40e_veb *veb;
u8 tc_map = 0; u8 tc_map = 0;
int ret; int ret;
u8 v; int v;
/* Enable the TCs available on PF to all VEBs */ /* Enable the TCs available on PF to all VEBs */
tc_map = i40e_pf_get_tc_map(pf); tc_map = i40e_pf_get_tc_map(pf);
if (tc_map == I40E_DEFAULT_TRAFFIC_CLASS) if (tc_map == I40E_DEFAULT_TRAFFIC_CLASS)
return; return;
for (v = 0; v < I40E_MAX_VEB; v++) { i40e_pf_for_each_veb(pf, v, veb) {
if (!pf->veb[v]) ret = i40e_veb_config_tc(veb, tc_map);
continue;
ret = i40e_veb_config_tc(pf->veb[v], tc_map);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"Failed configuring TC for VEB seid=%d\n", "Failed configuring TC for VEB seid=%d\n",
pf->veb[v]->seid); veb->seid);
/* Will try to configure as many components */ /* Will try to configure as many components */
} }
} }
/* Update each VSI */ /* Update each VSI */
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi) {
if (!pf->vsi[v])
continue;
/* - Enable all TCs for the LAN VSI /* - Enable all TCs for the LAN VSI
* - For all others keep them at TC0 for now * - For all others keep them at TC0 for now
*/ */
...@@ -6812,17 +6804,17 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf) ...@@ -6812,17 +6804,17 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
else else
tc_map = I40E_DEFAULT_TRAFFIC_CLASS; tc_map = I40E_DEFAULT_TRAFFIC_CLASS;
ret = i40e_vsi_config_tc(pf->vsi[v], tc_map); ret = i40e_vsi_config_tc(vsi, tc_map);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"Failed configuring TC for VSI seid=%d\n", "Failed configuring TC for VSI seid=%d\n",
pf->vsi[v]->seid); vsi->seid);
/* Will try to configure as many components */ /* Will try to configure as many components */
} else { } else {
/* Re-configure VSI vectors based on updated TC map */ /* Re-configure VSI vectors based on updated TC map */
i40e_vsi_map_rings_to_vectors(pf->vsi[v]); i40e_vsi_map_rings_to_vectors(vsi);
if (pf->vsi[v]->netdev) if (vsi->netdev)
i40e_dcbnl_set_all(pf->vsi[v]); i40e_dcbnl_set_all(vsi);
} }
} }
} }
...@@ -9257,7 +9249,9 @@ int i40e_close(struct net_device *netdev) ...@@ -9257,7 +9249,9 @@ int i40e_close(struct net_device *netdev)
**/ **/
void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired) void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired)
{ {
struct i40e_vsi *vsi;
u32 val; u32 val;
int i;
/* do the biggest reset indicated */ /* do the biggest reset indicated */
if (reset_flags & BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED)) { if (reset_flags & BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED)) {
...@@ -9313,29 +9307,20 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired) ...@@ -9313,29 +9307,20 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired)
"FW LLDP is enabled\n"); "FW LLDP is enabled\n");
} else if (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) { } else if (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) {
int v;
/* Find the VSI(s) that requested a re-init */ /* Find the VSI(s) that requested a re-init */
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev, "VSI reinit requested\n");
"VSI reinit requested\n");
for (v = 0; v < pf->num_alloc_vsi; v++) {
struct i40e_vsi *vsi = pf->vsi[v];
if (vsi != NULL && i40e_pf_for_each_vsi(pf, i, vsi) {
test_and_clear_bit(__I40E_VSI_REINIT_REQUESTED, if (test_and_clear_bit(__I40E_VSI_REINIT_REQUESTED,
vsi->state)) vsi->state))
i40e_vsi_reinit_locked(pf->vsi[v]); i40e_vsi_reinit_locked(vsi);
} }
} else if (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) { } else if (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) {
int v;
/* Find the VSI(s) that needs to be brought down */ /* Find the VSI(s) that needs to be brought down */
dev_info(&pf->pdev->dev, "VSI down requested\n"); dev_info(&pf->pdev->dev, "VSI down requested\n");
for (v = 0; v < pf->num_alloc_vsi; v++) {
struct i40e_vsi *vsi = pf->vsi[v];
if (vsi != NULL && i40e_pf_for_each_vsi(pf, i, vsi) {
test_and_clear_bit(__I40E_VSI_DOWN_REQUESTED, if (test_and_clear_bit(__I40E_VSI_DOWN_REQUESTED,
vsi->state)) { vsi->state)) {
set_bit(__I40E_VSI_DOWN, vsi->state); set_bit(__I40E_VSI_DOWN, vsi->state);
i40e_down(vsi); i40e_down(vsi);
...@@ -9888,6 +9873,7 @@ static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up) ...@@ -9888,6 +9873,7 @@ static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up)
**/ **/
static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up)
{ {
struct i40e_vsi *vsi;
struct i40e_pf *pf; struct i40e_pf *pf;
int i; int i;
...@@ -9895,15 +9881,10 @@ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up) ...@@ -9895,15 +9881,10 @@ static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up)
return; return;
pf = veb->pf; pf = veb->pf;
/* depth first... */ /* Send link event to contained VSIs */
for (i = 0; i < I40E_MAX_VEB; i++) i40e_pf_for_each_vsi(pf, i, vsi)
if (pf->veb[i] && (pf->veb[i]->uplink_seid == veb->seid)) if (vsi->uplink_seid == veb->seid)
i40e_veb_link_event(pf->veb[i], link_up); i40e_vsi_link_event(vsi, link_up);
/* ... now the local VSIs */
for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i] && (pf->vsi[i]->uplink_seid == veb->seid))
i40e_vsi_link_event(pf->vsi[i], link_up);
} }
/** /**
...@@ -9995,6 +9976,8 @@ static void i40e_link_event(struct i40e_pf *pf) ...@@ -9995,6 +9976,8 @@ static void i40e_link_event(struct i40e_pf *pf)
**/ **/
static void i40e_watchdog_subtask(struct i40e_pf *pf) static void i40e_watchdog_subtask(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
struct i40e_veb *veb;
int i; int i;
/* if interface is down do nothing */ /* if interface is down do nothing */
...@@ -10015,15 +9998,14 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) ...@@ -10015,15 +9998,14 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
/* Update the stats for active netdevs so the network stack /* Update the stats for active netdevs so the network stack
* can look at updated numbers whenever it cares to * can look at updated numbers whenever it cares to
*/ */
for (i = 0; i < pf->num_alloc_vsi; i++) i40e_pf_for_each_vsi(pf, i, vsi)
if (pf->vsi[i] && pf->vsi[i]->netdev) if (vsi->netdev)
i40e_update_stats(pf->vsi[i]); i40e_update_stats(vsi);
if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) { if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) {
/* Update the stats for the active switching components */ /* Update the stats for the active switching components */
for (i = 0; i < I40E_MAX_VEB; i++) i40e_pf_for_each_veb(pf, i, veb)
if (pf->veb[i]) i40e_update_veb_stats(veb);
i40e_update_veb_stats(pf->veb[i]);
} }
i40e_ptp_rx_hang(pf); i40e_ptp_rx_hang(pf);
...@@ -10368,89 +10350,84 @@ static void i40e_config_bridge_mode(struct i40e_veb *veb) ...@@ -10368,89 +10350,84 @@ static void i40e_config_bridge_mode(struct i40e_veb *veb)
} }
/** /**
* i40e_reconstitute_veb - rebuild the VEB and anything connected to it * i40e_reconstitute_veb - rebuild the VEB and VSIs connected to it
* @veb: pointer to the VEB instance * @veb: pointer to the VEB instance
* *
* This is a recursive function that first builds the attached VSIs then * This is a function that builds the attached VSIs. We track the connections
* recurses in to build the next layer of VEB. We track the connections * through our own index numbers because the seid's from the HW could change
* through our own index numbers because the seid's from the HW could * across the reset.
* change across the reset.
**/ **/
static int i40e_reconstitute_veb(struct i40e_veb *veb) static int i40e_reconstitute_veb(struct i40e_veb *veb)
{ {
struct i40e_vsi *ctl_vsi = NULL; struct i40e_vsi *ctl_vsi = NULL;
struct i40e_pf *pf = veb->pf; struct i40e_pf *pf = veb->pf;
int v, veb_idx; struct i40e_vsi *vsi;
int ret; int v, ret;
/* build VSI that owns this VEB, temporarily attached to base VEB */ /* As we do not maintain PV (port virtualizer) switch element then
for (v = 0; v < pf->num_alloc_vsi && !ctl_vsi; v++) { * there can be only one non-floating VEB that have uplink to MAC SEID
if (pf->vsi[v] && * and its control VSI is the main one.
pf->vsi[v]->veb_idx == veb->idx && */
pf->vsi[v]->flags & I40E_VSI_FLAG_VEB_OWNER) { if (WARN_ON(veb->uplink_seid && veb->uplink_seid != pf->mac_seid)) {
ctl_vsi = pf->vsi[v]; dev_err(&pf->pdev->dev,
break; "Invalid uplink SEID for VEB %d\n", veb->idx);
} return -ENOENT;
} }
if (!ctl_vsi) {
dev_info(&pf->pdev->dev, if (veb->uplink_seid == pf->mac_seid) {
"missing owner VSI for veb_idx %d\n", veb->idx); /* Check that the LAN VSI has VEB owning flag set */
ret = -ENOENT; ctl_vsi = pf->vsi[pf->lan_vsi];
goto end_reconstitute;
if (WARN_ON(ctl_vsi->veb_idx != veb->idx ||
!(ctl_vsi->flags & I40E_VSI_FLAG_VEB_OWNER))) {
dev_err(&pf->pdev->dev,
"Invalid control VSI for VEB %d\n", veb->idx);
return -ENOENT;
} }
if (ctl_vsi != pf->vsi[pf->lan_vsi])
ctl_vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid; /* Add the control VSI to switch */
ret = i40e_add_vsi(ctl_vsi); ret = i40e_add_vsi(ctl_vsi);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_err(&pf->pdev->dev,
"rebuild of veb_idx %d owner VSI failed: %d\n", "Rebuild of owner VSI for VEB %d failed: %d\n",
veb->idx, ret); veb->idx, ret);
goto end_reconstitute; return ret;
} }
i40e_vsi_reset_stats(ctl_vsi); i40e_vsi_reset_stats(ctl_vsi);
}
/* create the VEB in the switch and move the VSI onto the VEB */ /* create the VEB in the switch and move the VSI onto the VEB */
ret = i40e_add_veb(veb, ctl_vsi); ret = i40e_add_veb(veb, ctl_vsi);
if (ret) if (ret)
goto end_reconstitute; return ret;
if (veb->uplink_seid) {
if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags))
veb->bridge_mode = BRIDGE_MODE_VEB; veb->bridge_mode = BRIDGE_MODE_VEB;
else else
veb->bridge_mode = BRIDGE_MODE_VEPA; veb->bridge_mode = BRIDGE_MODE_VEPA;
i40e_config_bridge_mode(veb); i40e_config_bridge_mode(veb);
}
/* create the remaining VSIs attached to this VEB */ /* create the remaining VSIs attached to this VEB */
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi) {
if (!pf->vsi[v] || pf->vsi[v] == ctl_vsi) if (vsi == ctl_vsi)
continue; continue;
if (pf->vsi[v]->veb_idx == veb->idx) { if (vsi->veb_idx == veb->idx) {
struct i40e_vsi *vsi = pf->vsi[v];
vsi->uplink_seid = veb->seid; vsi->uplink_seid = veb->seid;
ret = i40e_add_vsi(vsi); ret = i40e_add_vsi(vsi);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"rebuild of vsi_idx %d failed: %d\n", "rebuild of vsi_idx %d failed: %d\n",
v, ret); v, ret);
goto end_reconstitute; return ret;
} }
i40e_vsi_reset_stats(vsi); i40e_vsi_reset_stats(vsi);
} }
} }
/* create any VEBs attached to this VEB - RECURSION */
for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) {
if (pf->veb[veb_idx] && pf->veb[veb_idx]->veb_idx == veb->idx) {
pf->veb[veb_idx]->uplink_seid = veb->seid;
ret = i40e_reconstitute_veb(pf->veb[veb_idx]);
if (ret)
break;
}
}
end_reconstitute:
return ret; return ret;
} }
...@@ -10718,6 +10695,7 @@ static void i40e_clean_xps_state(struct i40e_vsi *vsi) ...@@ -10718,6 +10695,7 @@ static void i40e_clean_xps_state(struct i40e_vsi *vsi)
static void i40e_prep_for_reset(struct i40e_pf *pf) static void i40e_prep_for_reset(struct i40e_pf *pf)
{ {
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
struct i40e_vsi *vsi;
int ret = 0; int ret = 0;
u32 v; u32 v;
...@@ -10732,11 +10710,9 @@ static void i40e_prep_for_reset(struct i40e_pf *pf) ...@@ -10732,11 +10710,9 @@ static void i40e_prep_for_reset(struct i40e_pf *pf)
/* quiesce the VSIs and their queues that are not already DOWN */ /* quiesce the VSIs and their queues that are not already DOWN */
i40e_pf_quiesce_all_vsi(pf); i40e_pf_quiesce_all_vsi(pf);
for (v = 0; v < pf->num_alloc_vsi; v++) { i40e_pf_for_each_vsi(pf, v, vsi) {
if (pf->vsi[v]) { i40e_clean_xps_state(vsi);
i40e_clean_xps_state(pf->vsi[v]); vsi->seid = 0;
pf->vsi[v]->seid = 0;
}
} }
i40e_shutdown_adminq(&pf->hw); i40e_shutdown_adminq(&pf->hw);
...@@ -10850,6 +10826,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) ...@@ -10850,6 +10826,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf); const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf);
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
struct i40e_veb *veb;
int ret; int ret;
u32 val; u32 val;
int v; int v;
...@@ -10991,15 +10968,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) ...@@ -10991,15 +10968,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
*/ */
if (vsi->uplink_seid != pf->mac_seid) { if (vsi->uplink_seid != pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n"); dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
/* find the one VEB connected to the MAC, and find orphans */
for (v = 0; v < I40E_MAX_VEB; v++) {
if (!pf->veb[v])
continue;
if (pf->veb[v]->uplink_seid == pf->mac_seid ||
pf->veb[v]->uplink_seid == 0) {
ret = i40e_reconstitute_veb(pf->veb[v]);
/* Rebuild VEBs */
i40e_pf_for_each_veb(pf, v, veb) {
ret = i40e_reconstitute_veb(veb);
if (!ret) if (!ret)
continue; continue;
...@@ -11009,20 +10981,19 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) ...@@ -11009,20 +10981,19 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
* If orphan failed, we'll report the error * If orphan failed, we'll report the error
* but try to keep going. * but try to keep going.
*/ */
if (pf->veb[v]->uplink_seid == pf->mac_seid) { if (veb->uplink_seid == pf->mac_seid) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"rebuild of switch failed: %d, will try to set up simple PF connection\n", "rebuild of switch failed: %d, will try to set up simple PF connection\n",
ret); ret);
vsi->uplink_seid = pf->mac_seid; vsi->uplink_seid = pf->mac_seid;
break; break;
} else if (pf->veb[v]->uplink_seid == 0) { } else if (veb->uplink_seid == 0) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"rebuild of orphan VEB failed: %d\n", "rebuild of orphan VEB failed: %d\n",
ret); ret);
} }
} }
} }
}
if (vsi->uplink_seid == pf->mac_seid) { if (vsi->uplink_seid == pf->mac_seid) {
dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n"); dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n");
...@@ -12098,6 +12069,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf) ...@@ -12098,6 +12069,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
*/ */
static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
{ {
struct i40e_vsi *vsi;
int err, i; int err, i;
/* We cleared the MSI and MSI-X flags when disabling the old interrupt /* We cleared the MSI and MSI-X flags when disabling the old interrupt
...@@ -12114,13 +12086,12 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf) ...@@ -12114,13 +12086,12 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
/* Now that we've re-acquired IRQs, we need to remap the vectors and /* Now that we've re-acquired IRQs, we need to remap the vectors and
* rings together again. * rings together again.
*/ */
for (i = 0; i < pf->num_alloc_vsi; i++) { i40e_pf_for_each_vsi(pf, i, vsi) {
if (pf->vsi[i]) { err = i40e_vsi_alloc_q_vectors(vsi);
err = i40e_vsi_alloc_q_vectors(pf->vsi[i]);
if (err) if (err)
goto err_unwind; goto err_unwind;
i40e_vsi_map_rings_to_vectors(pf->vsi[i]);
} i40e_vsi_map_rings_to_vectors(vsi);
} }
err = i40e_setup_misc_vector(pf); err = i40e_setup_misc_vector(pf);
...@@ -13122,19 +13093,16 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, ...@@ -13122,19 +13093,16 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_netdev_priv *np = netdev_priv(dev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct i40e_veb *veb = NULL;
struct nlattr *attr, *br_spec; struct nlattr *attr, *br_spec;
int i, rem; struct i40e_veb *veb;
int rem;
/* Only for PF VSI for now */ /* Only for PF VSI for now */
if (vsi->seid != pf->vsi[pf->lan_vsi]->seid) if (vsi->seid != pf->vsi[pf->lan_vsi]->seid)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* Find the HW bridge for PF VSI */ /* Find the HW bridge for PF VSI */
for (i = 0; i < I40E_MAX_VEB && !veb; i++) { veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid);
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
veb = pf->veb[i];
}
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
if (!br_spec) if (!br_spec)
...@@ -13199,19 +13167,14 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, ...@@ -13199,19 +13167,14 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_netdev_priv *np = netdev_priv(dev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct i40e_veb *veb = NULL; struct i40e_veb *veb;
int i;
/* Only for PF VSI for now */ /* Only for PF VSI for now */
if (vsi->seid != pf->vsi[pf->lan_vsi]->seid) if (vsi->seid != pf->vsi[pf->lan_vsi]->seid)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* Find the HW bridge for the PF VSI */ /* Find the HW bridge for the PF VSI */
for (i = 0; i < I40E_MAX_VEB && !veb; i++) { veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid);
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
veb = pf->veb[i];
}
if (!veb) if (!veb)
return 0; return 0;
...@@ -14145,7 +14108,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi) ...@@ -14145,7 +14108,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
struct hlist_node *h; struct hlist_node *h;
struct i40e_veb *veb = NULL; struct i40e_veb *veb;
struct i40e_pf *pf; struct i40e_pf *pf;
u16 uplink_seid; u16 uplink_seid;
int i, n, bkt; int i, n, bkt;
...@@ -14209,29 +14172,28 @@ int i40e_vsi_release(struct i40e_vsi *vsi) ...@@ -14209,29 +14172,28 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
/* If this was the last thing on the VEB, except for the /* If this was the last thing on the VEB, except for the
* controlling VSI, remove the VEB, which puts the controlling * controlling VSI, remove the VEB, which puts the controlling
* VSI onto the next level down in the switch. * VSI onto the uplink port.
* *
* Well, okay, there's one more exception here: don't remove * Well, okay, there's one more exception here: don't remove
* the orphan VEBs yet. We'll wait for an explicit remove request * the floating VEBs yet. We'll wait for an explicit remove request
* from up the network stack. * from up the network stack.
*/ */
for (n = 0, i = 0; i < pf->num_alloc_vsi; i++) { veb = i40e_pf_get_veb_by_seid(pf, uplink_seid);
if (pf->vsi[i] && if (veb && veb->uplink_seid) {
pf->vsi[i]->uplink_seid == uplink_seid && n = 0;
(pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) {
n++; /* count the VSIs */ /* Count non-controlling VSIs present on the VEB */
} i40e_pf_for_each_vsi(pf, i, vsi)
} if (vsi->uplink_seid == uplink_seid &&
for (i = 0; i < I40E_MAX_VEB; i++) { (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
if (!pf->veb[i]) n++;
continue;
if (pf->veb[i]->uplink_seid == uplink_seid) /* If there is no VSI except the control one then release
n++; /* count the VEBs */ * the VEB and put the control VSI onto VEB uplink.
if (pf->veb[i]->seid == uplink_seid) */
veb = pf->veb[i]; if (!n)
}
if (n == 0 && veb && veb->uplink_seid != 0)
i40e_veb_release(veb); i40e_veb_release(veb);
}
return 0; return 0;
} }
...@@ -14389,8 +14351,8 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, ...@@ -14389,8 +14351,8 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
struct i40e_vsi *vsi = NULL; struct i40e_vsi *vsi = NULL;
struct i40e_veb *veb = NULL; struct i40e_veb *veb = NULL;
u16 alloc_queue_pairs; u16 alloc_queue_pairs;
int ret, i;
int v_idx; int v_idx;
int ret;
/* The requested uplink_seid must be either /* The requested uplink_seid must be either
* - the PF's port seid * - the PF's port seid
...@@ -14405,21 +14367,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, ...@@ -14405,21 +14367,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
* *
* Find which uplink_seid we were given and create a new VEB if needed * Find which uplink_seid we were given and create a new VEB if needed
*/ */
for (i = 0; i < I40E_MAX_VEB; i++) { veb = i40e_pf_get_veb_by_seid(pf, uplink_seid);
if (pf->veb[i] && pf->veb[i]->seid == uplink_seid) {
veb = pf->veb[i];
break;
}
}
if (!veb && uplink_seid != pf->mac_seid) { if (!veb && uplink_seid != pf->mac_seid) {
vsi = i40e_pf_get_vsi_by_seid(pf, uplink_seid);
for (i = 0; i < pf->num_alloc_vsi; i++) {
if (pf->vsi[i] && pf->vsi[i]->seid == uplink_seid) {
vsi = pf->vsi[i];
break;
}
}
if (!vsi) { if (!vsi) {
dev_info(&pf->pdev->dev, "no such uplink_seid %d\n", dev_info(&pf->pdev->dev, "no such uplink_seid %d\n",
uplink_seid); uplink_seid);
...@@ -14448,10 +14398,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, ...@@ -14448,10 +14398,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
} }
i40e_config_bridge_mode(veb); i40e_config_bridge_mode(veb);
} }
for (i = 0; i < I40E_MAX_VEB && !veb; i++) { veb = i40e_pf_get_veb_by_seid(pf, vsi->uplink_seid);
if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
veb = pf->veb[i];
}
if (!veb) { if (!veb) {
dev_info(&pf->pdev->dev, "couldn't add VEB\n"); dev_info(&pf->pdev->dev, "couldn't add VEB\n");
return NULL; return NULL;
...@@ -14681,29 +14628,24 @@ static void i40e_switch_branch_release(struct i40e_veb *branch) ...@@ -14681,29 +14628,24 @@ static void i40e_switch_branch_release(struct i40e_veb *branch)
struct i40e_pf *pf = branch->pf; struct i40e_pf *pf = branch->pf;
u16 branch_seid = branch->seid; u16 branch_seid = branch->seid;
u16 veb_idx = branch->idx; u16 veb_idx = branch->idx;
struct i40e_vsi *vsi;
struct i40e_veb *veb;
int i; int i;
/* release any VEBs on this VEB - RECURSION */ /* release any VEBs on this VEB - RECURSION */
for (i = 0; i < I40E_MAX_VEB; i++) { i40e_pf_for_each_veb(pf, i, veb)
if (!pf->veb[i]) if (veb->uplink_seid == branch->seid)
continue; i40e_switch_branch_release(veb);
if (pf->veb[i]->uplink_seid == branch->seid)
i40e_switch_branch_release(pf->veb[i]);
}
/* Release the VSIs on this VEB, but not the owner VSI. /* Release the VSIs on this VEB, but not the owner VSI.
* *
* NOTE: Removing the last VSI on a VEB has the SIDE EFFECT of removing * NOTE: Removing the last VSI on a VEB has the SIDE EFFECT of removing
* the VEB itself, so don't use (*branch) after this loop. * the VEB itself, so don't use (*branch) after this loop.
*/ */
for (i = 0; i < pf->num_alloc_vsi; i++) { i40e_pf_for_each_vsi(pf, i, vsi)
if (!pf->vsi[i]) if (vsi->uplink_seid == branch_seid &&
continue; (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
if (pf->vsi[i]->uplink_seid == branch_seid && i40e_vsi_release(vsi);
(pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) {
i40e_vsi_release(pf->vsi[i]);
}
}
/* There's one corner case where the VEB might not have been /* There's one corner case where the VEB might not have been
* removed, so double check it here and remove it if needed. * removed, so double check it here and remove it if needed.
...@@ -14741,38 +14683,35 @@ static void i40e_veb_clear(struct i40e_veb *veb) ...@@ -14741,38 +14683,35 @@ static void i40e_veb_clear(struct i40e_veb *veb)
**/ **/
void i40e_veb_release(struct i40e_veb *veb) void i40e_veb_release(struct i40e_veb *veb)
{ {
struct i40e_vsi *vsi = NULL; struct i40e_vsi *vsi, *vsi_it;
struct i40e_pf *pf; struct i40e_pf *pf;
int i, n = 0; int i, n = 0;
pf = veb->pf; pf = veb->pf;
/* find the remaining VSI and check for extras */ /* find the remaining VSI and check for extras */
for (i = 0; i < pf->num_alloc_vsi; i++) { i40e_pf_for_each_vsi(pf, i, vsi_it)
if (pf->vsi[i] && pf->vsi[i]->uplink_seid == veb->seid) { if (vsi_it->uplink_seid == veb->seid) {
if (vsi_it->flags & I40E_VSI_FLAG_VEB_OWNER)
vsi = vsi_it;
n++; n++;
vsi = pf->vsi[i];
}
} }
if (n != 1) {
/* Floating VEB has to be empty and regular one must have
* single owner VSI.
*/
if ((veb->uplink_seid && n != 1) || (!veb->uplink_seid && n != 0)) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"can't remove VEB %d with %d VSIs left\n", "can't remove VEB %d with %d VSIs left\n",
veb->seid, n); veb->seid, n);
return; return;
} }
/* move the remaining VSI to uplink veb */ /* For regular VEB move the owner VSI to uplink port */
vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER;
if (veb->uplink_seid) { if (veb->uplink_seid) {
vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER;
vsi->uplink_seid = veb->uplink_seid; vsi->uplink_seid = veb->uplink_seid;
if (veb->uplink_seid == pf->mac_seid)
vsi->veb_idx = I40E_NO_VEB; vsi->veb_idx = I40E_NO_VEB;
else
vsi->veb_idx = veb->veb_idx;
} else {
/* floating VEB */
vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid;
vsi->veb_idx = pf->vsi[pf->lan_vsi]->veb_idx;
} }
i40e_aq_delete_element(&pf->hw, veb->seid, NULL); i40e_aq_delete_element(&pf->hw, veb->seid, NULL);
...@@ -14790,8 +14729,8 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) ...@@ -14790,8 +14729,8 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi)
bool enable_stats = !!test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags); bool enable_stats = !!test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags);
int ret; int ret;
ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid, ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi ? vsi->seid : 0,
veb->enabled_tc, false, veb->enabled_tc, vsi ? false : true,
&veb->seid, enable_stats, NULL); &veb->seid, enable_stats, NULL);
/* get a VEB from the hardware */ /* get a VEB from the hardware */
...@@ -14823,9 +14762,11 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) ...@@ -14823,9 +14762,11 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi)
return -ENOENT; return -ENOENT;
} }
if (vsi) {
vsi->uplink_seid = veb->seid; vsi->uplink_seid = veb->seid;
vsi->veb_idx = veb->idx; vsi->veb_idx = veb->idx;
vsi->flags |= I40E_VSI_FLAG_VEB_OWNER; vsi->flags |= I40E_VSI_FLAG_VEB_OWNER;
}
return 0; return 0;
} }
...@@ -14850,8 +14791,9 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, ...@@ -14850,8 +14791,9 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
u16 uplink_seid, u16 vsi_seid, u16 uplink_seid, u16 vsi_seid,
u8 enabled_tc) u8 enabled_tc)
{ {
struct i40e_veb *veb, *uplink_veb = NULL; struct i40e_vsi *vsi = NULL;
int vsi_idx, veb_idx; struct i40e_veb *veb;
int veb_idx;
int ret; int ret;
/* if one seid is 0, the other must be 0 to create a floating relay */ /* if one seid is 0, the other must be 0 to create a floating relay */
...@@ -14864,28 +14806,13 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, ...@@ -14864,28 +14806,13 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
} }
/* make sure there is such a vsi and uplink */ /* make sure there is such a vsi and uplink */
for (vsi_idx = 0; vsi_idx < pf->num_alloc_vsi; vsi_idx++) if (vsi_seid) {
if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid) vsi = i40e_pf_get_vsi_by_seid(pf, vsi_seid);
break; if (!vsi) {
if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) { dev_err(&pf->pdev->dev, "vsi seid %d not found\n",
dev_info(&pf->pdev->dev, "vsi seid %d not found\n",
vsi_seid); vsi_seid);
return NULL; return NULL;
} }
if (uplink_seid && uplink_seid != pf->mac_seid) {
for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) {
if (pf->veb[veb_idx] &&
pf->veb[veb_idx]->seid == uplink_seid) {
uplink_veb = pf->veb[veb_idx];
break;
}
}
if (!uplink_veb) {
dev_info(&pf->pdev->dev,
"uplink seid %d not found\n", uplink_seid);
return NULL;
}
} }
/* get veb sw struct */ /* get veb sw struct */
...@@ -14895,14 +14822,14 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, ...@@ -14895,14 +14822,14 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
veb = pf->veb[veb_idx]; veb = pf->veb[veb_idx];
veb->flags = flags; veb->flags = flags;
veb->uplink_seid = uplink_seid; veb->uplink_seid = uplink_seid;
veb->veb_idx = (uplink_veb ? uplink_veb->idx : I40E_NO_VEB);
veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1); veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1);
/* create the VEB in the switch */ /* create the VEB in the switch */
ret = i40e_add_veb(veb, pf->vsi[vsi_idx]); ret = i40e_add_veb(veb, vsi);
if (ret) if (ret)
goto err_veb; goto err_veb;
if (vsi_idx == pf->lan_vsi)
if (vsi && vsi->idx == pf->lan_vsi)
pf->lan_veb = veb->idx; pf->lan_veb = veb->idx;
return veb; return veb;
...@@ -14930,6 +14857,7 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, ...@@ -14930,6 +14857,7 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
u16 uplink_seid = le16_to_cpu(ele->uplink_seid); u16 uplink_seid = le16_to_cpu(ele->uplink_seid);
u8 element_type = ele->element_type; u8 element_type = ele->element_type;
u16 seid = le16_to_cpu(ele->seid); u16 seid = le16_to_cpu(ele->seid);
struct i40e_veb *veb;
if (printconfig) if (printconfig)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
...@@ -14948,13 +14876,10 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, ...@@ -14948,13 +14876,10 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
int v; int v;
/* find existing or else empty VEB */ /* find existing or else empty VEB */
for (v = 0; v < I40E_MAX_VEB; v++) { veb = i40e_pf_get_veb_by_seid(pf, seid);
if (pf->veb[v] && (pf->veb[v]->seid == seid)) { if (veb) {
pf->lan_veb = v; pf->lan_veb = veb->idx;
break; } else {
}
}
if (pf->lan_veb >= I40E_MAX_VEB) {
v = i40e_veb_mem_alloc(pf); v = i40e_veb_mem_alloc(pf);
if (v < 0) if (v < 0)
break; break;
...@@ -14967,7 +14892,6 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf, ...@@ -14967,7 +14892,6 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
pf->veb[pf->lan_veb]->seid = seid; pf->veb[pf->lan_veb]->seid = seid;
pf->veb[pf->lan_veb]->uplink_seid = pf->mac_seid; pf->veb[pf->lan_veb]->uplink_seid = pf->mac_seid;
pf->veb[pf->lan_veb]->pf = pf; pf->veb[pf->lan_veb]->pf = pf;
pf->veb[pf->lan_veb]->veb_idx = I40E_NO_VEB;
break; break;
case I40E_SWITCH_ELEMENT_TYPE_VSI: case I40E_SWITCH_ELEMENT_TYPE_VSI:
if (num_reported != 1) if (num_reported != 1)
...@@ -15630,6 +15554,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -15630,6 +15554,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_I40E_DCB #ifdef CONFIG_I40E_DCB
enum i40e_get_fw_lldp_status_resp lldp_status; enum i40e_get_fw_lldp_status_resp lldp_status;
#endif /* CONFIG_I40E_DCB */ #endif /* CONFIG_I40E_DCB */
struct i40e_vsi *vsi;
struct i40e_pf *pf; struct i40e_pf *pf;
struct i40e_hw *hw; struct i40e_hw *hw;
u16 wol_nvm_bits; u16 wol_nvm_bits;
...@@ -15640,7 +15565,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -15640,7 +15565,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif /* CONFIG_I40E_DCB */ #endif /* CONFIG_I40E_DCB */
int err; int err;
u32 val; u32 val;
u32 i;
err = pci_enable_device_mem(pdev); err = pci_enable_device_mem(pdev);
if (err) if (err)
...@@ -15990,12 +15914,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -15990,12 +15914,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list); INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list);
/* if FDIR VSI was set up, start it now */ /* if FDIR VSI was set up, start it now */
for (i = 0; i < pf->num_alloc_vsi; i++) { vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR);
if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { if (vsi)
i40e_vsi_open(pf->vsi[i]); i40e_vsi_open(vsi);
break;
}
}
/* The driver only wants link up/down and module qualification /* The driver only wants link up/down and module qualification
* reports from firmware. Note the negative logic. * reports from firmware. Note the negative logic.
...@@ -16241,6 +16162,8 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -16241,6 +16162,8 @@ static void i40e_remove(struct pci_dev *pdev)
{ {
struct i40e_pf *pf = pci_get_drvdata(pdev); struct i40e_pf *pf = pci_get_drvdata(pdev);
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
struct i40e_vsi *vsi;
struct i40e_veb *veb;
int ret_code; int ret_code;
int i; int i;
...@@ -16298,22 +16221,17 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -16298,22 +16221,17 @@ static void i40e_remove(struct pci_dev *pdev)
/* If there is a switch structure or any orphans, remove them. /* If there is a switch structure or any orphans, remove them.
* This will leave only the PF's VSI remaining. * This will leave only the PF's VSI remaining.
*/ */
for (i = 0; i < I40E_MAX_VEB; i++) { i40e_pf_for_each_veb(pf, i, veb)
if (!pf->veb[i]) if (veb->uplink_seid == pf->mac_seid ||
continue; veb->uplink_seid == 0)
i40e_switch_branch_release(veb);
if (pf->veb[i]->uplink_seid == pf->mac_seid ||
pf->veb[i]->uplink_seid == 0)
i40e_switch_branch_release(pf->veb[i]);
}
/* Now we can shutdown the PF's VSIs, just before we kill /* Now we can shutdown the PF's VSIs, just before we kill
* adminq and hmc. * adminq and hmc.
*/ */
for (i = pf->num_alloc_vsi; i--;) i40e_pf_for_each_vsi(pf, i, vsi) {
if (pf->vsi[i]) { i40e_vsi_close(vsi);
i40e_vsi_close(pf->vsi[i]); i40e_vsi_release(vsi);
i40e_vsi_release(pf->vsi[i]);
pf->vsi[i] = NULL; pf->vsi[i] = NULL;
} }
...@@ -16352,18 +16270,17 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -16352,18 +16270,17 @@ static void i40e_remove(struct pci_dev *pdev)
/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */ /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
rtnl_lock(); rtnl_lock();
i40e_clear_interrupt_scheme(pf); i40e_clear_interrupt_scheme(pf);
for (i = 0; i < pf->num_alloc_vsi; i++) { i40e_pf_for_each_vsi(pf, i, vsi) {
if (pf->vsi[i]) {
if (!test_bit(__I40E_RECOVERY_MODE, pf->state)) if (!test_bit(__I40E_RECOVERY_MODE, pf->state))
i40e_vsi_clear_rings(pf->vsi[i]); i40e_vsi_clear_rings(vsi);
i40e_vsi_clear(pf->vsi[i]);
i40e_vsi_clear(vsi);
pf->vsi[i] = NULL; pf->vsi[i] = NULL;
} }
}
rtnl_unlock(); rtnl_unlock();
for (i = 0; i < I40E_MAX_VEB; i++) { i40e_pf_for_each_veb(pf, i, veb) {
kfree(pf->veb[i]); kfree(veb);
pf->veb[i] = NULL; pf->veb[i] = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment