Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
100GbE Intel Wired LAN Driver Updates 2019-05-04

This series contains updates to the ice driver only.

Jesse updated the driver to make more functions consistent in their use
of a local variable for vsi->back.  Updates the driver to use bit fields
when possible to avoid wasting lots of storage space to store single bit
values.  Optimized the driver to be more memory efficient by moving
structure members around that are not in are hot path.

Michal updates the driver to disable the VF if malicious device driver
(MDD) event is detected by the hardware.  Adds checks to validate the
messages coming from the VF driver.  Tightens up the sniffing of the
driver so that transmit traffic so that VF's cannot see what is on other
VSIs.

Tony fixed the driver so that receive stripping state won't change every
time transmit insertion is changed.  Cleanup the __always_unused
attribute, now that the variable is being used.  Fixed the function
which evaluates setting of features to ensure that can evaluate and set
multiple features in a single function call.

Akeem fixes the driver so that we do not attempt to remove a VLAN filter
that does not exist.  Adds support for adding a ethertype based filter
rule on VSI and describe it in a very long run-on sentence. :-)

Bruce cleans up static analysis warnings by removing a local variable
initialization that is not needed.

Brett makes the allocate/deallocate more consistent in all the driver
flows for VSI q_vectors.  In addition, makes setting/getting coalesce
settings more consistent throughout the driver.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-05-05 21:40:23 -07:00
commit 9073989afb
12 changed files with 339 additions and 179 deletions

View File

@ -83,6 +83,8 @@ extern const char ice_drv_ver[];
#define ICE_MAX_QS_PER_VF 256
#define ICE_MIN_QS_PER_VF 1
#define ICE_DFLT_QS_PER_VF 4
#define ICE_NONQ_VECS_VF 1
#define ICE_MAX_SCATTER_QS_PER_VF 16
#define ICE_MAX_BASE_QS_PER_VF 16
#define ICE_MAX_INTR_PER_VF 65
#define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1)
@ -253,6 +255,8 @@ struct ice_vsi {
s16 vf_id; /* VF ID for SR-IOV VSIs */
u16 ethtype; /* Ethernet protocol for pause frame */
/* RSS config */
u16 rss_table_size; /* HW RSS table size */
u16 rss_size; /* Allocated RSS queues */

View File

@ -1880,10 +1880,10 @@ void
ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
u16 link_speeds_bitmap)
{
u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN;
u64 pt_high;
u64 pt_low;
int index;
u16 speed;
/* We first check with low part of phy_type */
for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) {

View File

@ -79,6 +79,7 @@ struct ice_rq_event_info {
/* Control Queue information */
struct ice_ctl_q_info {
enum ice_ctl_q qtype;
enum ice_aq_err rq_last_status; /* last status on receive queue */
struct ice_ctl_q_ring rq; /* receive queue */
struct ice_ctl_q_ring sq; /* send queue */
u32 sq_cmd_timeout; /* send queue cmd write back timeout */
@ -86,10 +87,9 @@ struct ice_ctl_q_info {
u16 num_sq_entries; /* send queue depth */
u16 rq_buf_size; /* receive queue buffer size */
u16 sq_buf_size; /* send queue buffer size */
enum ice_aq_err sq_last_status; /* last status on send queue */
struct mutex sq_lock; /* Send queue lock */
struct mutex rq_lock; /* Receive queue lock */
enum ice_aq_err sq_last_status; /* last status on send queue */
enum ice_aq_err rq_last_status; /* last status on receive queue */
};
#endif /* _ICE_CONTROLQ_H_ */

View File

@ -1251,7 +1251,7 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
*/
static void
ice_get_settings_link_down(struct ethtool_link_ksettings *ks,
struct net_device __always_unused *netdev)
struct net_device *netdev)
{
/* link is down and the driver needs to fall back on
* supported PHY types to figure out what info to display
@ -2254,50 +2254,61 @@ ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type,
return 0;
}
/**
* ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings
* @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings
* @ec: coalesce settings to program the device with
* @q_num: update ITR/INTRL (coalesce) settings for this queue number/index
*
* Return 0 on success, and negative under the following conditions:
* 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed.
* 2. The q_num passed in is not a valid number/index for Tx and Rx rings.
*/
static int
ice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num)
{
if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER,
&vsi->rx_rings[q_num]->q_vector->rx))
return -EINVAL;
if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER,
&vsi->tx_rings[q_num]->q_vector->tx))
return -EINVAL;
} else if (q_num < vsi->num_rxq) {
if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER,
&vsi->rx_rings[q_num]->q_vector->rx))
return -EINVAL;
} else if (q_num < vsi->num_txq) {
if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER,
&vsi->tx_rings[q_num]->q_vector->tx))
return -EINVAL;
} else {
return -EINVAL;
}
return 0;
}
/**
* __ice_get_coalesce - get ITR/INTRL values for the device
* @netdev: pointer to the netdev associated with this query
* @ec: ethtool structure to fill with driver's coalesce settings
* @q_num: queue number to get the coalesce settings for
*
* If the caller passes in a negative q_num then we return coalesce settings
* based on queue number 0, else use the actual q_num passed in.
*/
static int
__ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec,
int q_num)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
int tx = -EINVAL, rx = -EINVAL;
struct ice_vsi *vsi = np->vsi;
if (q_num < 0) {
rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER,
&vsi->rx_rings[0]->q_vector->rx);
tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER,
&vsi->tx_rings[0]->q_vector->tx);
if (q_num < 0)
q_num = 0;
goto update_coalesced_frames;
}
if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER,
&vsi->rx_rings[q_num]->q_vector->rx);
tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER,
&vsi->tx_rings[q_num]->q_vector->tx);
} else if (q_num < vsi->num_rxq) {
rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER,
&vsi->rx_rings[q_num]->q_vector->rx);
} else if (q_num < vsi->num_txq) {
tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER,
&vsi->tx_rings[q_num]->q_vector->tx);
} else {
/* q_num is invalid for both Rx and Tx queues */
return -EINVAL;
}
update_coalesced_frames:
/* either q_num is invalid for both Rx and Tx queues or setting coalesce
* failed completely
*/
if (tx && rx)
if (ice_get_q_coalesce(vsi, ec, q_num))
return -EINVAL;
if (q_num < vsi->num_txq)
@ -2423,54 +2434,77 @@ ice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec,
return 0;
}
/**
* ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings
* @vsi: VSI associated to the queue that need updating
* @ec: coalesce settings to program the device with
* @q_num: update ITR/INTRL (coalesce) settings for this queue number/index
*
* Return 0 on success, and negative under the following conditions:
* 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed.
* 2. The q_num passed in is not a valid number/index for Tx and Rx rings.
*/
static int
ice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num)
{
if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec,
&vsi->rx_rings[q_num]->q_vector->rx,
vsi))
return -EINVAL;
if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec,
&vsi->tx_rings[q_num]->q_vector->tx,
vsi))
return -EINVAL;
} else if (q_num < vsi->num_rxq) {
if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec,
&vsi->rx_rings[q_num]->q_vector->rx,
vsi))
return -EINVAL;
} else if (q_num < vsi->num_txq) {
if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec,
&vsi->tx_rings[q_num]->q_vector->tx,
vsi))
return -EINVAL;
} else {
return -EINVAL;
}
return 0;
}
/**
* __ice_set_coalesce - set ITR/INTRL values for the device
* @netdev: pointer to the netdev associated with this query
* @ec: ethtool structure to fill with driver's coalesce settings
* @q_num: queue number to get the coalesce settings for
*
* If the caller passes in a negative q_num then we set the coalesce settings
* for all Tx/Rx queues, else use the actual q_num passed in.
*/
static int
__ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec,
int q_num)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
int rx = -EINVAL, tx = -EINVAL;
struct ice_vsi *vsi = np->vsi;
if (q_num < 0) {
int i;
ice_for_each_q_vector(vsi, i) {
struct ice_q_vector *q_vector = vsi->q_vectors[i];
if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec,
&q_vector->rx, vsi) ||
ice_set_rc_coalesce(ICE_TX_CONTAINER, ec,
&q_vector->tx, vsi))
if (ice_set_q_coalesce(vsi, ec, i))
return -EINVAL;
}
goto set_work_lmt;
}
if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec,
&vsi->rx_rings[q_num]->q_vector->rx,
vsi);
tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec,
&vsi->tx_rings[q_num]->q_vector->tx,
vsi);
} else if (q_num < vsi->num_rxq) {
rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec,
&vsi->rx_rings[q_num]->q_vector->rx,
vsi);
} else if (q_num < vsi->num_txq) {
tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec,
&vsi->tx_rings[q_num]->q_vector->tx,
vsi);
}
/* either q_num is invalid for both Rx and Tx queues or setting coalesce
* failed completely
*/
if (rx && tx)
if (ice_set_q_coalesce(vsi, ec, q_num))
return -EINVAL;
set_work_lmt:
if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
vsi->work_lmt = max(ec->tx_max_coalesced_frames_irq,
ec->rx_max_coalesced_frames_irq);

View File

@ -163,11 +163,15 @@
#define PFINT_OICR_ENA 0x0016C900
#define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4))
#define QINT_RQCTL_MSIX_INDX_S 0
#define QINT_RQCTL_MSIX_INDX_M ICE_M(0x7FF, 0)
#define QINT_RQCTL_ITR_INDX_S 11
#define QINT_RQCTL_ITR_INDX_M ICE_M(0x3, 11)
#define QINT_RQCTL_CAUSE_ENA_M BIT(30)
#define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4))
#define QINT_TQCTL_MSIX_INDX_S 0
#define QINT_TQCTL_MSIX_INDX_M ICE_M(0x7FF, 0)
#define QINT_TQCTL_ITR_INDX_S 11
#define QINT_TQCTL_ITR_INDX_M ICE_M(0x3, 11)
#define QINT_TQCTL_CAUSE_ENA_M BIT(30)
#define VPINT_ALLOC(_VF) (0x001D1000 + ((_VF) * 4))
#define VPINT_ALLOC_FIRST_S 0

View File

@ -232,12 +232,11 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena)
/**
* ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI
* @vsi: VSI pointer
* @alloc_qvectors: a bool to specify if q_vectors need to be allocated.
*
* On error: returns error code (negative)
* On success: returns 0
*/
static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors)
static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
@ -252,15 +251,11 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors)
if (!vsi->rx_rings)
goto err_rxrings;
if (alloc_qvectors) {
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(&pf->pdev->dev,
vsi->num_q_vectors,
sizeof(*vsi->q_vectors),
GFP_KERNEL);
if (!vsi->q_vectors)
goto err_vectors;
}
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
if (!vsi->q_vectors)
goto err_vectors;
return 0;
@ -301,7 +296,6 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi)
static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
{
struct ice_pf *pf = vsi->back;
struct ice_vf *vf = NULL;
if (vsi->type == ICE_VSI_VF)
@ -325,8 +319,7 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
vsi->num_q_vectors = pf->num_vf_msix - 1;
break;
default:
dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
vsi->type);
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
break;
}
@ -391,16 +384,15 @@ void ice_vsi_delete(struct ice_vsi *vsi)
}
/**
* ice_vsi_free_arrays - clean up VSI resources
* ice_vsi_free_arrays - De-allocate queue and vector pointer arrays for the VSI
* @vsi: pointer to VSI being cleared
* @free_qvectors: bool to specify if q_vectors should be deallocated
*/
static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors)
static void ice_vsi_free_arrays(struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
/* free the ring and vector containers */
if (free_qvectors && vsi->q_vectors) {
if (vsi->q_vectors) {
devm_kfree(&pf->pdev->dev, vsi->q_vectors);
vsi->q_vectors = NULL;
}
@ -448,7 +440,7 @@ int ice_vsi_clear(struct ice_vsi *vsi)
if (vsi->idx < pf->next_vsi)
pf->next_vsi = vsi->idx;
ice_vsi_free_arrays(vsi, true);
ice_vsi_free_arrays(vsi);
mutex_unlock(&pf->sw_mutex);
devm_kfree(&pf->pdev->dev, vsi);
@ -514,14 +506,14 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id)
switch (vsi->type) {
case ICE_VSI_PF:
if (ice_vsi_alloc_arrays(vsi, true))
if (ice_vsi_alloc_arrays(vsi))
goto err_rings;
/* Setup default MSIX irq handler for VSI */
vsi->irq_handler = ice_msix_clean_rings;
break;
case ICE_VSI_VF:
if (ice_vsi_alloc_arrays(vsi, true))
if (ice_vsi_alloc_arrays(vsi))
goto err_rings;
break;
default:
@ -573,7 +565,7 @@ static int __ice_vsi_get_qs_contig(struct ice_qs_cfg *qs_cfg)
/**
* __ice_vsi_get_qs_sc - Assign a scattered queues from PF to VSI
* @qs_cfg: gathered variables needed for PF->VSI queues assignment
* @qs_cfg: gathered variables needed for pf->vsi queues assignment
*
* Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap
*/
@ -917,6 +909,9 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
{
u8 lut_type, hash_type;
struct ice_pf *pf;
pf = vsi->back;
switch (vsi->type) {
case ICE_VSI_PF:
@ -930,8 +925,7 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
break;
default:
dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
vsi->type);
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
return;
}
@ -1018,10 +1012,11 @@ static int ice_vsi_init(struct ice_vsi *vsi)
static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
{
struct ice_q_vector *q_vector;
struct ice_pf *pf = vsi->back;
struct ice_ring *ring;
if (!vsi->q_vectors[v_idx]) {
dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n",
dev_dbg(&pf->pdev->dev, "Queue vector at index %d not found\n",
v_idx);
return;
}
@ -1036,7 +1031,7 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
if (vsi->netdev)
netif_napi_del(&q_vector->napi);
devm_kfree(&vsi->back->pdev->dev, q_vector);
devm_kfree(&pf->pdev->dev, q_vector);
vsi->q_vectors[v_idx] = NULL;
}
@ -1188,8 +1183,7 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
num_q_vectors, vsi->idx);
break;
default:
dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
vsi->type);
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
break;
}
@ -1198,7 +1192,7 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
"Failed to get tracking for %d HW vectors for VSI %d, err=%d\n",
num_q_vectors, vsi->vsi_num, vsi->hw_base_vector);
if (vsi->type != ICE_VSI_VF) {
ice_free_res(vsi->back->sw_irq_tracker,
ice_free_res(pf->sw_irq_tracker,
vsi->sw_base_vector, vsi->idx);
pf->num_avail_sw_msix += num_q_vectors;
}
@ -1409,13 +1403,13 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
vsi->rss_table_size);
if (status) {
dev_err(&vsi->back->pdev->dev,
dev_err(&pf->pdev->dev,
"set_rss_lut failed, error %d\n", status);
err = -EIO;
goto ice_vsi_cfg_rss_exit;
}
key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL);
key = devm_kzalloc(&pf->pdev->dev, sizeof(*key), GFP_KERNEL);
if (!key) {
err = -ENOMEM;
goto ice_vsi_cfg_rss_exit;
@ -1432,7 +1426,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key);
if (status) {
dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n",
dev_err(&pf->pdev->dev, "set_rss_key failed, error %d\n",
status);
err = -EIO;
}
@ -1616,7 +1610,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid)
list_add(&list->list_entry, &tmp_add_list);
status = ice_remove_vlan(&pf->hw, &tmp_add_list);
if (status) {
if (status == ICE_ERR_DOES_NOT_EXIST) {
dev_dbg(&pf->pdev->dev,
"Failed to remove VLAN %d on VSI %i, it does not exist, status: %d\n",
vid, vsi->vsi_num, status);
} else if (status) {
dev_err(&pf->pdev->dev,
"Error removing VLAN %d on vsi %i error: %d\n",
vid, vsi->vsi_num, status);
@ -1717,7 +1715,7 @@ ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, int offset)
i, num_q_grps, qg_buf,
buf_len, NULL);
if (status) {
dev_err(&vsi->back->pdev->dev,
dev_err(&pf->pdev->dev,
"Failed to set LAN Tx queue context, error: %d\n",
status);
err = -ENODEV;
@ -1875,33 +1873,37 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi)
* tracked for this PF.
*/
for (q = 0; q < q_vector->num_ring_tx; q++) {
int itr_idx = q_vector->tx.itr_idx;
int itr_idx = (q_vector->tx.itr_idx <<
QINT_TQCTL_ITR_INDX_S) &
QINT_TQCTL_ITR_INDX_M;
u32 val;
if (vsi->type == ICE_VSI_VF)
val = QINT_TQCTL_CAUSE_ENA_M |
(itr_idx << QINT_TQCTL_ITR_INDX_S) |
((i + 1) << QINT_TQCTL_MSIX_INDX_S);
val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
(((i + 1) << QINT_TQCTL_MSIX_INDX_S) &
QINT_TQCTL_MSIX_INDX_M);
else
val = QINT_TQCTL_CAUSE_ENA_M |
(itr_idx << QINT_TQCTL_ITR_INDX_S) |
(reg_idx << QINT_TQCTL_MSIX_INDX_S);
val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
((reg_idx << QINT_TQCTL_MSIX_INDX_S) &
QINT_TQCTL_MSIX_INDX_M);
wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
txq++;
}
for (q = 0; q < q_vector->num_ring_rx; q++) {
int itr_idx = q_vector->rx.itr_idx;
int itr_idx = (q_vector->rx.itr_idx <<
QINT_RQCTL_ITR_INDX_S) &
QINT_RQCTL_ITR_INDX_M;
u32 val;
if (vsi->type == ICE_VSI_VF)
val = QINT_RQCTL_CAUSE_ENA_M |
(itr_idx << QINT_RQCTL_ITR_INDX_S) |
((i + 1) << QINT_RQCTL_MSIX_INDX_S);
val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
(((i + 1) << QINT_RQCTL_MSIX_INDX_S) &
QINT_RQCTL_MSIX_INDX_M);
else
val = QINT_RQCTL_CAUSE_ENA_M |
(itr_idx << QINT_RQCTL_ITR_INDX_S) |
(reg_idx << QINT_RQCTL_MSIX_INDX_S);
val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
((reg_idx << QINT_RQCTL_MSIX_INDX_S) &
QINT_RQCTL_MSIX_INDX_M);
wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
rxq++;
}
@ -1932,6 +1934,10 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
*/
ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL;
/* Preserve existing VLAN strip setting */
ctxt->info.vlan_flags |= (vsi->info.vlan_flags &
ICE_AQ_VSI_VLAN_EMOD_M);
ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
status = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
@ -2148,12 +2154,14 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)
{
struct ice_vsi_ctx *ctxt;
struct device *dev;
struct ice_pf *pf;
int status;
if (!vsi)
return -EINVAL;
dev = &vsi->back->pdev->dev;
pf = vsi->back;
dev = &pf->pdev->dev;
ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL);
if (!ctxt)
return -ENOMEM;
@ -2177,11 +2185,11 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)
cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID |
ICE_AQ_VSI_PROP_SW_VALID);
status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL);
status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);
if (status) {
netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %d\n",
ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status,
vsi->back->hw.adminq.sq_last_status);
pf->hw.adminq.sq_last_status);
goto err_out;
}
@ -2242,6 +2250,46 @@ clear_reg_idx:
return -EINVAL;
}
/**
* ice_vsi_add_rem_eth_mac - Program VSI ethertype based filter with rule
* @vsi: the VSI being configured
* @add_rule: boolean value to add or remove ethertype filter rule
*/
static void
ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule)
{
struct ice_fltr_list_entry *list;
struct ice_pf *pf = vsi->back;
LIST_HEAD(tmp_add_list);
enum ice_status status;
list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);
if (!list)
return;
list->fltr_info.lkup_type = ICE_SW_LKUP_ETHERTYPE;
list->fltr_info.fltr_act = ICE_DROP_PACKET;
list->fltr_info.flag = ICE_FLTR_TX;
list->fltr_info.src_id = ICE_SRC_ID_VSI;
list->fltr_info.vsi_handle = vsi->idx;
list->fltr_info.l_data.ethertype_mac.ethertype = vsi->ethtype;
INIT_LIST_HEAD(&list->list_entry);
list_add(&list->list_entry, &tmp_add_list);
if (add_rule)
status = ice_add_eth_mac(&pf->hw, &tmp_add_list);
else
status = ice_remove_eth_mac(&pf->hw, &tmp_add_list);
if (status)
dev_err(&pf->pdev->dev,
"Failure Adding or Removing Ethertype on VSI %i error: %d\n",
vsi->vsi_num, status);
ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
}
/**
* ice_vsi_setup - Set up a VSI by a given type
* @pf: board private structure
@ -2277,6 +2325,9 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
vsi->port_info = pi;
vsi->vsw = pf->first_sw;
if (vsi->type == ICE_VSI_PF)
vsi->ethtype = ETH_P_PAUSE;
if (vsi->type == ICE_VSI_VF)
vsi->vf_id = vf_id;
@ -2374,14 +2425,23 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
goto unroll_vector_base;
}
/* Add switch rule to drop all Tx Flow Control Frames, of look up
* type ETHERTYPE from VSIs, and restrict malicious VF from sending
* out PAUSE or PFC frames. If enabled, FW can still send FC frames.
* The rule is added once for PF VSI in order to create appropriate
* recipe, since VSI/VSI list is ignored with drop action...
*/
if (vsi->type == ICE_VSI_PF)
ice_vsi_add_rem_eth_mac(vsi, true);
return vsi;
unroll_vector_base:
/* reclaim SW interrupts back to the common pool */
ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
pf->num_avail_sw_msix += vsi->num_q_vectors;
/* reclaim HW interrupt back to the common pool */
ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
pf->num_avail_hw_msix += vsi->num_q_vectors;
unroll_alloc_q_vector:
ice_vsi_free_q_vectors(vsi);
@ -2718,22 +2778,23 @@ int ice_vsi_release(struct ice_vsi *vsi)
/* reclaim interrupt vectors back to PF */
if (vsi->type != ICE_VSI_VF) {
/* reclaim SW interrupts back to the common pool */
ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector,
vsi->idx);
ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
pf->num_avail_sw_msix += vsi->num_q_vectors;
/* reclaim HW interrupts back to the common pool */
ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector,
vsi->idx);
ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
pf->num_avail_hw_msix += vsi->num_q_vectors;
} else if (test_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states)) {
/* Reclaim VF resources back only while freeing all VFs or
* vector reassignment is requested
*/
ice_free_res(vsi->back->hw_irq_tracker, vf->first_vector_idx,
ice_free_res(pf->hw_irq_tracker, vf->first_vector_idx,
vsi->idx);
pf->num_avail_hw_msix += pf->num_vf_msix;
}
if (vsi->type == ICE_VSI_PF)
ice_vsi_add_rem_eth_mac(vsi, false);
ice_remove_vsi_fltr(&pf->hw, vsi->idx);
ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);
ice_vsi_delete(vsi);
@ -2797,8 +2858,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
vsi->hw_base_vector = 0;
ice_vsi_clear_rings(vsi);
ice_vsi_free_arrays(vsi, false);
ice_dev_onetime_setup(&vsi->back->hw);
ice_vsi_free_arrays(vsi);
ice_dev_onetime_setup(&pf->hw);
if (vsi->type == ICE_VSI_VF)
ice_vsi_set_num_qs(vsi, vf->vf_id);
else
@ -2810,7 +2871,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
if (ret < 0)
goto err_vsi;
ret = ice_vsi_alloc_arrays(vsi, false);
ret = ice_vsi_alloc_arrays(vsi);
if (ret < 0)
goto err_vsi;
@ -2837,7 +2898,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
* receive traffic on first queue. Hence no need to capture
* return value
*/
if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags))
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
ice_vsi_cfg_rss_lut_key(vsi);
break;
case ICE_VSI_VF:
@ -2857,8 +2918,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi)
if (ret)
goto err_vectors;
vsi->back->q_left_tx -= vsi->alloc_txq;
vsi->back->q_left_rx -= vsi->alloc_rxq;
pf->q_left_tx -= vsi->alloc_txq;
pf->q_left_rx -= vsi->alloc_rxq;
break;
default:
break;
@ -2889,7 +2950,7 @@ err_rings:
}
err_vsi:
ice_vsi_clear(vsi);
set_bit(__ICE_RESET_FAILED, vsi->back->state);
set_bit(__ICE_RESET_FAILED, pf->state);
return ret;
}

View File

@ -317,42 +317,22 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
test_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags)) {
clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags);
if (vsi->current_netdev_flags & IFF_PROMISC) {
/* Apply Tx filter rule to get traffic from VMs */
status = ice_cfg_dflt_vsi(hw, vsi->idx, true,
ICE_FLTR_TX);
if (status) {
netdev_err(netdev, "Error setting default VSI %i tx rule\n",
vsi->vsi_num);
vsi->current_netdev_flags &= ~IFF_PROMISC;
err = -EIO;
goto out_promisc;
}
/* Apply Rx filter rule to get traffic from wire */
status = ice_cfg_dflt_vsi(hw, vsi->idx, true,
ICE_FLTR_RX);
if (status) {
netdev_err(netdev, "Error setting default VSI %i rx rule\n",
netdev_err(netdev, "Error setting default VSI %i Rx rule\n",
vsi->vsi_num);
vsi->current_netdev_flags &= ~IFF_PROMISC;
err = -EIO;
goto out_promisc;
}
} else {
/* Clear Tx filter rule to stop traffic from VMs */
status = ice_cfg_dflt_vsi(hw, vsi->idx, false,
ICE_FLTR_TX);
if (status) {
netdev_err(netdev, "Error clearing default VSI %i tx rule\n",
vsi->vsi_num);
vsi->current_netdev_flags |= IFF_PROMISC;
err = -EIO;
goto out_promisc;
}
/* Clear Rx filter to remove traffic from wire */
status = ice_cfg_dflt_vsi(hw, vsi->idx, false,
ICE_FLTR_RX);
if (status) {
netdev_err(netdev, "Error clearing default VSI %i rx rule\n",
netdev_err(netdev, "Error clearing default VSI %i Rx rule\n",
vsi->vsi_num);
vsi->current_netdev_flags |= IFF_PROMISC;
err = -EIO;
@ -1185,10 +1165,12 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) {
struct ice_vf *vf = &pf->vf[i];
mdd_detected = false;
reg = rd32(hw, VP_MDET_TX_PQM(i));
if (reg & VP_MDET_TX_PQM_VALID_M) {
wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF);
vf->num_mdd_events++;
mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@ -1196,7 +1178,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_TX_TCLAN(i));
if (reg & VP_MDET_TX_TCLAN_VALID_M) {
wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF);
vf->num_mdd_events++;
mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@ -1204,7 +1186,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_TX_TDPU(i));
if (reg & VP_MDET_TX_TDPU_VALID_M) {
wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF);
vf->num_mdd_events++;
mdd_detected = true;
dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
i);
}
@ -1212,14 +1194,13 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, VP_MDET_RX(i));
if (reg & VP_MDET_RX_VALID_M) {
wr32(hw, VP_MDET_RX(i), 0xFFFF);
vf->num_mdd_events++;
mdd_detected = true;
dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n",
i);
}
if (vf->num_mdd_events > ICE_DFLT_NUM_MDD_EVENTS_ALLOWED) {
dev_info(&pf->pdev->dev,
"Too many MDD events on VF %d, disabled\n", i);
if (mdd_detected) {
vf->num_mdd_events++;
dev_info(&pf->pdev->dev,
"Use PF Control I/F to re-enable the VF\n");
set_bit(ICE_VF_STATE_DIS, vf->vf_states);
@ -2872,6 +2853,9 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
struct ice_vsi *vsi = np->vsi;
int ret = 0;
/* Multiple features can be changed in one call so keep features in
* separate if/else statements to guarantee each feature is checked
*/
if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH))
ret = ice_vsi_manage_rss_lut(vsi, true);
else if (!(features & NETIF_F_RXHASH) &&
@ -2884,8 +2868,9 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
ret = ice_vsi_manage_vlan_stripping(vsi, false);
else if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
ret = ice_vsi_manage_vlan_insertion(vsi);
else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))

View File

@ -1969,6 +1969,65 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
return 0;
}
/**
* ice_add_eth_mac - Add ethertype and MAC based filter rule
* @hw: pointer to the hardware structure
* @em_list: list of ether type MAC filter, MAC is optional
*/
enum ice_status
ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list)
{
struct ice_fltr_list_entry *em_list_itr;
if (!em_list || !hw)
return ICE_ERR_PARAM;
list_for_each_entry(em_list_itr, em_list, list_entry) {
enum ice_sw_lkup_type l_type =
em_list_itr->fltr_info.lkup_type;
if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
l_type != ICE_SW_LKUP_ETHERTYPE)
return ICE_ERR_PARAM;
em_list_itr->fltr_info.flag = ICE_FLTR_TX;
em_list_itr->status = ice_add_rule_internal(hw, l_type,
em_list_itr);
if (em_list_itr->status)
return em_list_itr->status;
}
return 0;
}
/**
* ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule
* @hw: pointer to the hardware structure
* @em_list: list of ethertype or ethertype MAC entries
*/
enum ice_status
ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list)
{
struct ice_fltr_list_entry *em_list_itr, *tmp;
if (!em_list || !hw)
return ICE_ERR_PARAM;
list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) {
enum ice_sw_lkup_type l_type =
em_list_itr->fltr_info.lkup_type;
if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC &&
l_type != ICE_SW_LKUP_ETHERTYPE)
return ICE_ERR_PARAM;
em_list_itr->status = ice_remove_rule_internal(hw, l_type,
em_list_itr);
if (em_list_itr->status)
return em_list_itr->status;
}
return 0;
}
/**
* ice_rem_sw_rule_info
* @hw: pointer to the hardware structure

View File

@ -218,6 +218,10 @@ enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);
enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw);
enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
enum ice_status
ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list);
enum ice_status
ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list);
void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle);
enum ice_status
ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);

View File

@ -1849,6 +1849,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
if (err < 0)
return err;
/* cppcheck-suppress unreadVariable */
ip.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb);

View File

@ -326,6 +326,8 @@ struct ice_port_info {
u8 port_state;
#define ICE_SCHED_PORT_STATE_INIT 0x0
#define ICE_SCHED_PORT_STATE_READY 0x1
u8 lport;
#define ICE_LPORT_MASK 0xff
u16 dflt_tx_vsi_rule_id;
u16 dflt_tx_vsi_num;
u16 dflt_rx_vsi_rule_id;
@ -339,11 +341,9 @@ struct ice_port_info {
struct ice_dcbx_cfg remote_dcbx_cfg; /* Peer Cfg */
struct ice_dcbx_cfg desired_dcbx_cfg; /* CEE Desired Cfg */
/* LLDP/DCBX Status */
u8 dcbx_status;
u8 is_sw_lldp;
u8 lport;
#define ICE_LPORT_MASK 0xff
u8 is_vf;
u8 dcbx_status:3; /* see ICE_DCBX_STATUS_DIS */
u8 is_sw_lldp:1;
u8 is_vf:1;
};
struct ice_switch_info {

View File

@ -1814,14 +1814,22 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
struct ice_vsi *vsi = NULL;
struct ice_pf *pf = vf->pf;
unsigned long qmap;
u16 num_q_vectors;
int i;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
num_q_vectors = irqmap_info->num_vectors - ICE_NONQ_VECS_VF;
vsi = pf->vsi[vf->lan_vsi_idx];
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
!vsi || vsi->num_q_vectors < num_q_vectors ||
irqmap_info->num_vectors == 0) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
for (i = 0; i < irqmap_info->num_vectors; i++) {
for (i = 0; i < num_q_vectors; i++) {
struct ice_q_vector *q_vector = vsi->q_vectors[i];
map = &irqmap_info->vecmap[i];
vector_id = map->vector_id;
@ -1833,36 +1841,26 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
vsi = pf->vsi[vf->lan_vsi_idx];
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
/* lookout for the invalid queue index */
qmap = map->rxq_map;
q_vector->num_ring_rx = 0;
for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) {
struct ice_q_vector *q_vector;
if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
q_vector = vsi->q_vectors[i];
q_vector->num_ring_rx++;
q_vector->rx.itr_idx = map->rxitr_idx;
vsi->rx_rings[vsi_q_id]->q_vector = q_vector;
}
qmap = map->txq_map;
q_vector->num_ring_tx = 0;
for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) {
struct ice_q_vector *q_vector;
if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
q_vector = vsi->q_vectors[i];
q_vector->num_ring_tx++;
q_vector->tx.itr_idx = map->txitr_idx;
vsi->tx_rings[vsi_q_id]->q_vector = q_vector;
@ -2402,7 +2400,17 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
}
}
} else {
for (i = 0; i < vfl->num_elements; i++) {
/* In case of non_trusted VF, number of VLAN elements passed
* to PF for removal might be greater than number of VLANs
* filter programmed for that VF - So, use actual number of
* VLANS added earlier with add VLAN opcode. In order to avoid
* removing VLAN that doesn't exist, which result to sending
* erroneous failed message back to the VF
*/
int num_vf_vlan;
num_vf_vlan = vf->num_vlan;
for (i = 0; i < vfl->num_elements && i < num_vf_vlan; i++) {
u16 vid = vfl->vlan_id[i];
/* Make sure ice_vsi_kill_vlan is successful before