mirror of https://gitee.com/openkylin/linux.git
ice: Add support for VLANs and offloads
This patch adds support for VLANs. When a VLAN is created a switch filter is added to direct the VLAN traffic to the corresponding VSI. When a VLAN is deleted, the filter is deleted as well. This patch also adds support for the following hardware offloads. 1) VLAN tag insertion/stripping 2) Receive Side Scaling (RSS) 3) Tx checksum and TCP segmentation 4) Rx checksum Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
2b245cb294
commit
d76a60ba7a
|
@ -23,7 +23,10 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "ice_devids.h"
|
||||
#include "ice_type.h"
|
||||
#include "ice_txrx.h"
|
||||
|
@ -47,6 +50,8 @@
|
|||
#define ICE_MAX_SCATTER_RXQS 16
|
||||
#define ICE_Q_WAIT_RETRY_LIMIT 10
|
||||
#define ICE_Q_WAIT_MAX_RETRY (5 * ICE_Q_WAIT_RETRY_LIMIT)
|
||||
#define ICE_MAX_LG_RSS_QS 256
|
||||
#define ICE_MAX_SMALL_RSS_QS 8
|
||||
#define ICE_RES_VALID_BIT 0x8000
|
||||
#define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1)
|
||||
#define ICE_INVAL_Q_INDEX 0xffff
|
||||
|
@ -62,6 +67,7 @@
|
|||
|
||||
#define ICE_TX_DESC(R, i) (&(((struct ice_tx_desc *)((R)->desc))[i]))
|
||||
#define ICE_RX_DESC(R, i) (&(((union ice_32b_rx_flex_desc *)((R)->desc))[i]))
|
||||
#define ICE_TX_CTX_DESC(R, i) (&(((struct ice_tx_ctx_desc *)((R)->desc))[i]))
|
||||
|
||||
#define ice_for_each_txq(vsi, i) \
|
||||
for ((i) = 0; (i) < (vsi)->num_txq; (i)++)
|
||||
|
@ -113,6 +119,7 @@ struct ice_vsi {
|
|||
irqreturn_t (*irq_handler)(int irq, void *data);
|
||||
|
||||
DECLARE_BITMAP(state, __ICE_STATE_NBITS);
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
int num_q_vectors;
|
||||
int base_vector;
|
||||
enum ice_vsi_type type;
|
||||
|
@ -122,6 +129,13 @@ struct ice_vsi {
|
|||
/* Interrupt thresholds */
|
||||
u16 work_lmt;
|
||||
|
||||
/* RSS config */
|
||||
u16 rss_table_size; /* HW RSS table size */
|
||||
u16 rss_size; /* Allocated RSS queues */
|
||||
u8 *rss_hkey_user; /* User configured hash keys */
|
||||
u8 *rss_lut_user; /* User configured lookup table entries */
|
||||
u8 rss_lut_type; /* used to configure Get/Set RSS LUT AQ call */
|
||||
|
||||
u16 max_frame;
|
||||
u16 rx_buf_len;
|
||||
|
||||
|
@ -181,6 +195,7 @@ struct ice_pf {
|
|||
struct mutex avail_q_mutex; /* protects access to avail_[rx|tx]qs */
|
||||
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
|
||||
u32 msg_enable;
|
||||
u32 hw_csum_rx_error;
|
||||
u32 oicr_idx; /* Other interrupt cause vector index */
|
||||
u32 num_lan_msix; /* Total MSIX vectors for base driver */
|
||||
u32 num_avail_msix; /* remaining MSIX vectors left unclaimed */
|
||||
|
@ -224,4 +239,8 @@ static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi,
|
|||
wr32(hw, GLINT_DYN_CTL(vector), val);
|
||||
}
|
||||
|
||||
int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
|
||||
int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
|
||||
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);
|
||||
|
||||
#endif /* _ICE_H_ */
|
||||
|
|
|
@ -968,6 +968,60 @@ struct ice_aqc_nvm {
|
|||
__le32 addr_low;
|
||||
};
|
||||
|
||||
/* Get/Set RSS key (indirect 0x0B04/0x0B02) */
|
||||
struct ice_aqc_get_set_rss_key {
|
||||
#define ICE_AQC_GSET_RSS_KEY_VSI_VALID BIT(15)
|
||||
#define ICE_AQC_GSET_RSS_KEY_VSI_ID_S 0
|
||||
#define ICE_AQC_GSET_RSS_KEY_VSI_ID_M (0x3FF << ICE_AQC_GSET_RSS_KEY_VSI_ID_S)
|
||||
__le16 vsi_id;
|
||||
u8 reserved[6];
|
||||
__le32 addr_high;
|
||||
__le32 addr_low;
|
||||
};
|
||||
|
||||
#define ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE 0x28
|
||||
#define ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE 0xC
|
||||
|
||||
struct ice_aqc_get_set_rss_keys {
|
||||
u8 standard_rss_key[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];
|
||||
u8 extended_hash_key[ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE];
|
||||
};
|
||||
|
||||
/* Get/Set RSS LUT (indirect 0x0B05/0x0B03) */
|
||||
struct ice_aqc_get_set_rss_lut {
|
||||
#define ICE_AQC_GSET_RSS_LUT_VSI_VALID BIT(15)
|
||||
#define ICE_AQC_GSET_RSS_LUT_VSI_ID_S 0
|
||||
#define ICE_AQC_GSET_RSS_LUT_VSI_ID_M (0x1FF << ICE_AQC_GSET_RSS_LUT_VSI_ID_S)
|
||||
__le16 vsi_id;
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S 0
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M \
|
||||
(0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S)
|
||||
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI 0
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF 1
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL 2
|
||||
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S 2
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M \
|
||||
(0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S)
|
||||
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128 128
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG 0
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512 512
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG 1
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K 2048
|
||||
#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG 2
|
||||
|
||||
#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S 4
|
||||
#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M \
|
||||
(0xF << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S)
|
||||
|
||||
__le16 flags;
|
||||
__le32 reserved;
|
||||
__le32 addr_high;
|
||||
__le32 addr_low;
|
||||
};
|
||||
|
||||
/* Add TX LAN Queues (indirect 0x0C30) */
|
||||
struct ice_aqc_add_txqs {
|
||||
u8 num_qgrps;
|
||||
|
@ -1089,6 +1143,8 @@ struct ice_aq_desc {
|
|||
struct ice_aqc_query_txsched_res query_sched_res;
|
||||
struct ice_aqc_add_move_delete_elem add_move_delete_elem;
|
||||
struct ice_aqc_nvm nvm;
|
||||
struct ice_aqc_get_set_rss_lut get_set_rss_lut;
|
||||
struct ice_aqc_get_set_rss_key get_set_rss_key;
|
||||
struct ice_aqc_add_txqs add_txqs;
|
||||
struct ice_aqc_dis_txqs dis_txqs;
|
||||
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
|
||||
|
@ -1171,6 +1227,12 @@ enum ice_adminq_opc {
|
|||
/* NVM commands */
|
||||
ice_aqc_opc_nvm_read = 0x0701,
|
||||
|
||||
/* RSS commands */
|
||||
ice_aqc_opc_set_rss_key = 0x0B02,
|
||||
ice_aqc_opc_set_rss_lut = 0x0B03,
|
||||
ice_aqc_opc_get_rss_key = 0x0B04,
|
||||
ice_aqc_opc_get_rss_lut = 0x0B05,
|
||||
|
||||
/* TX queue handling commands/events */
|
||||
ice_aqc_opc_add_txqs = 0x0C30,
|
||||
ice_aqc_opc_dis_txqs = 0x0C31,
|
||||
|
|
|
@ -1261,6 +1261,194 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
|
|||
ice_aq_clear_pxe_mode(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ice_aq_get_set_rss_lut
|
||||
* @hw: pointer to the hardware structure
|
||||
* @vsi_id: VSI FW index
|
||||
* @lut_type: LUT table type
|
||||
* @lut: pointer to the LUT buffer provided by the caller
|
||||
* @lut_size: size of the LUT buffer
|
||||
* @glob_lut_idx: global LUT index
|
||||
* @set: set true to set the table, false to get the table
|
||||
*
|
||||
* Internal function to get (0x0B05) or set (0x0B03) RSS look up table
|
||||
*/
|
||||
static enum ice_status
|
||||
__ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
|
||||
u16 lut_size, u8 glob_lut_idx, bool set)
|
||||
{
|
||||
struct ice_aqc_get_set_rss_lut *cmd_resp;
|
||||
struct ice_aq_desc desc;
|
||||
enum ice_status status;
|
||||
u16 flags = 0;
|
||||
|
||||
cmd_resp = &desc.params.get_set_rss_lut;
|
||||
|
||||
if (set) {
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_lut);
|
||||
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
|
||||
} else {
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_lut);
|
||||
}
|
||||
|
||||
cmd_resp->vsi_id = cpu_to_le16(((vsi_id <<
|
||||
ICE_AQC_GSET_RSS_LUT_VSI_ID_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_VSI_ID_M) |
|
||||
ICE_AQC_GSET_RSS_LUT_VSI_VALID);
|
||||
|
||||
switch (lut_type) {
|
||||
case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI:
|
||||
case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF:
|
||||
case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL:
|
||||
flags |= ((lut_type << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M);
|
||||
break;
|
||||
default:
|
||||
status = ICE_ERR_PARAM;
|
||||
goto ice_aq_get_set_rss_lut_exit;
|
||||
}
|
||||
|
||||
if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL) {
|
||||
flags |= ((glob_lut_idx << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M);
|
||||
|
||||
if (!set)
|
||||
goto ice_aq_get_set_rss_lut_send;
|
||||
} else if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF) {
|
||||
if (!set)
|
||||
goto ice_aq_get_set_rss_lut_send;
|
||||
} else {
|
||||
goto ice_aq_get_set_rss_lut_send;
|
||||
}
|
||||
|
||||
/* LUT size is only valid for Global and PF table types */
|
||||
if (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128) {
|
||||
flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG <<
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;
|
||||
} else if (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512) {
|
||||
flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG <<
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;
|
||||
} else if ((lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K) &&
|
||||
(lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF)) {
|
||||
flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG <<
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &
|
||||
ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;
|
||||
} else {
|
||||
status = ICE_ERR_PARAM;
|
||||
goto ice_aq_get_set_rss_lut_exit;
|
||||
}
|
||||
|
||||
ice_aq_get_set_rss_lut_send:
|
||||
cmd_resp->flags = cpu_to_le16(flags);
|
||||
status = ice_aq_send_cmd(hw, &desc, lut, lut_size, NULL);
|
||||
|
||||
ice_aq_get_set_rss_lut_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_aq_get_rss_lut
|
||||
* @hw: pointer to the hardware structure
|
||||
* @vsi_id: VSI FW index
|
||||
* @lut_type: LUT table type
|
||||
* @lut: pointer to the LUT buffer provided by the caller
|
||||
* @lut_size: size of the LUT buffer
|
||||
*
|
||||
* get the RSS lookup table, PF or VSI type
|
||||
*/
|
||||
enum ice_status
|
||||
ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
|
||||
u16 lut_size)
|
||||
{
|
||||
return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_aq_set_rss_lut
|
||||
* @hw: pointer to the hardware structure
|
||||
* @vsi_id: VSI FW index
|
||||
* @lut_type: LUT table type
|
||||
* @lut: pointer to the LUT buffer provided by the caller
|
||||
* @lut_size: size of the LUT buffer
|
||||
*
|
||||
* set the RSS lookup table, PF or VSI type
|
||||
*/
|
||||
enum ice_status
|
||||
ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
|
||||
u16 lut_size)
|
||||
{
|
||||
return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ice_aq_get_set_rss_key
|
||||
* @hw: pointer to the hw struct
|
||||
* @vsi_id: VSI FW index
|
||||
* @key: pointer to key info struct
|
||||
* @set: set true to set the key, false to get the key
|
||||
*
|
||||
* get (0x0B04) or set (0x0B02) the RSS key per VSI
|
||||
*/
|
||||
static enum
|
||||
ice_status __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id,
|
||||
struct ice_aqc_get_set_rss_keys *key,
|
||||
bool set)
|
||||
{
|
||||
struct ice_aqc_get_set_rss_key *cmd_resp;
|
||||
u16 key_size = sizeof(*key);
|
||||
struct ice_aq_desc desc;
|
||||
|
||||
cmd_resp = &desc.params.get_set_rss_key;
|
||||
|
||||
if (set) {
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_key);
|
||||
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
|
||||
} else {
|
||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_key);
|
||||
}
|
||||
|
||||
cmd_resp->vsi_id = cpu_to_le16(((vsi_id <<
|
||||
ICE_AQC_GSET_RSS_KEY_VSI_ID_S) &
|
||||
ICE_AQC_GSET_RSS_KEY_VSI_ID_M) |
|
||||
ICE_AQC_GSET_RSS_KEY_VSI_VALID);
|
||||
|
||||
return ice_aq_send_cmd(hw, &desc, key, key_size, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_aq_get_rss_key
|
||||
* @hw: pointer to the hw struct
|
||||
* @vsi_id: VSI FW index
|
||||
* @key: pointer to key info struct
|
||||
*
|
||||
* get the RSS key per VSI
|
||||
*/
|
||||
enum ice_status
|
||||
ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,
|
||||
struct ice_aqc_get_set_rss_keys *key)
|
||||
{
|
||||
return __ice_aq_get_set_rss_key(hw, vsi_id, key, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_aq_set_rss_key
|
||||
* @hw: pointer to the hw struct
|
||||
* @vsi_id: VSI FW index
|
||||
* @keys: pointer to key info struct
|
||||
*
|
||||
* set the RSS key per VSI
|
||||
*/
|
||||
enum ice_status
|
||||
ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,
|
||||
struct ice_aqc_get_set_rss_keys *keys)
|
||||
{
|
||||
return __ice_aq_get_set_rss_key(hw, vsi_id, keys, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_aq_add_lan_txq
|
||||
* @hw: pointer to the hardware structure
|
||||
|
|
|
@ -33,6 +33,19 @@ enum ice_status ice_get_caps(struct ice_hw *hw);
|
|||
enum ice_status
|
||||
ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
|
||||
u32 rxq_index);
|
||||
|
||||
enum ice_status
|
||||
ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
|
||||
u16 lut_size);
|
||||
enum ice_status
|
||||
ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
|
||||
u16 lut_size);
|
||||
enum ice_status
|
||||
ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,
|
||||
struct ice_aqc_get_set_rss_keys *keys);
|
||||
enum ice_status
|
||||
ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,
|
||||
struct ice_aqc_get_set_rss_keys *keys);
|
||||
bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);
|
||||
enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);
|
||||
void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);
|
||||
|
|
|
@ -40,6 +40,65 @@ union ice_32byte_rx_desc {
|
|||
} wb; /* writeback */
|
||||
};
|
||||
|
||||
struct ice_rx_ptype_decoded {
|
||||
u32 ptype:10;
|
||||
u32 known:1;
|
||||
u32 outer_ip:1;
|
||||
u32 outer_ip_ver:2;
|
||||
u32 outer_frag:1;
|
||||
u32 tunnel_type:3;
|
||||
u32 tunnel_end_prot:2;
|
||||
u32 tunnel_end_frag:1;
|
||||
u32 inner_prot:4;
|
||||
u32 payload_layer:3;
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_outer_ip {
|
||||
ICE_RX_PTYPE_OUTER_L2 = 0,
|
||||
ICE_RX_PTYPE_OUTER_IP = 1,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_outer_ip_ver {
|
||||
ICE_RX_PTYPE_OUTER_NONE = 0,
|
||||
ICE_RX_PTYPE_OUTER_IPV4 = 1,
|
||||
ICE_RX_PTYPE_OUTER_IPV6 = 2,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_outer_fragmented {
|
||||
ICE_RX_PTYPE_NOT_FRAG = 0,
|
||||
ICE_RX_PTYPE_FRAG = 1,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_tunnel_type {
|
||||
ICE_RX_PTYPE_TUNNEL_NONE = 0,
|
||||
ICE_RX_PTYPE_TUNNEL_IP_IP = 1,
|
||||
ICE_RX_PTYPE_TUNNEL_IP_GRENAT = 2,
|
||||
ICE_RX_PTYPE_TUNNEL_IP_GRENAT_MAC = 3,
|
||||
ICE_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_tunnel_end_prot {
|
||||
ICE_RX_PTYPE_TUNNEL_END_NONE = 0,
|
||||
ICE_RX_PTYPE_TUNNEL_END_IPV4 = 1,
|
||||
ICE_RX_PTYPE_TUNNEL_END_IPV6 = 2,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_inner_prot {
|
||||
ICE_RX_PTYPE_INNER_PROT_NONE = 0,
|
||||
ICE_RX_PTYPE_INNER_PROT_UDP = 1,
|
||||
ICE_RX_PTYPE_INNER_PROT_TCP = 2,
|
||||
ICE_RX_PTYPE_INNER_PROT_SCTP = 3,
|
||||
ICE_RX_PTYPE_INNER_PROT_ICMP = 4,
|
||||
ICE_RX_PTYPE_INNER_PROT_TIMESYNC = 5,
|
||||
};
|
||||
|
||||
enum ice_rx_ptype_payload_layer {
|
||||
ICE_RX_PTYPE_PAYLOAD_LAYER_NONE = 0,
|
||||
ICE_RX_PTYPE_PAYLOAD_LAYER_PAY2 = 1,
|
||||
ICE_RX_PTYPE_PAYLOAD_LAYER_PAY3 = 2,
|
||||
ICE_RX_PTYPE_PAYLOAD_LAYER_PAY4 = 3,
|
||||
};
|
||||
|
||||
/* RX Flex Descriptor
|
||||
* This descriptor is used instead of the legacy version descriptor when
|
||||
* ice_rlan_ctx.adv_desc is set
|
||||
|
@ -88,6 +147,41 @@ union ice_32b_rx_flex_desc {
|
|||
} wb; /* writeback */
|
||||
};
|
||||
|
||||
/* Rx Flex Descriptor NIC Profile
|
||||
* This descriptor corresponds to RxDID 2 which contains
|
||||
* metadata fields for RSS, flow id and timestamp info
|
||||
*/
|
||||
struct ice_32b_rx_flex_desc_nic {
|
||||
/* Qword 0 */
|
||||
u8 rxdid;
|
||||
u8 mir_id_umb_cast;
|
||||
__le16 ptype_flexi_flags0;
|
||||
__le16 pkt_len;
|
||||
__le16 hdr_len_sph_flex_flags1;
|
||||
|
||||
/* Qword 1 */
|
||||
__le16 status_error0;
|
||||
__le16 l2tag1;
|
||||
__le32 rss_hash;
|
||||
|
||||
/* Qword 2 */
|
||||
__le16 status_error1;
|
||||
u8 flexi_flags2;
|
||||
u8 ts_low;
|
||||
__le16 l2tag2_1st;
|
||||
__le16 l2tag2_2nd;
|
||||
|
||||
/* Qword 3 */
|
||||
__le32 flow_id;
|
||||
union {
|
||||
struct {
|
||||
__le16 vlan_id;
|
||||
__le16 flow_id_ipv6;
|
||||
} flex;
|
||||
__le32 ts_high;
|
||||
} flex_ts;
|
||||
};
|
||||
|
||||
/* Receive Flex Descriptor profile IDs: There are a total
|
||||
* of 64 profiles where profile IDs 0/1 are for legacy; and
|
||||
* profiles 2-63 are flex profiles that can be programmed
|
||||
|
@ -241,12 +335,56 @@ enum ice_tx_desc_dtype_value {
|
|||
enum ice_tx_desc_cmd_bits {
|
||||
ICE_TX_DESC_CMD_EOP = 0x0001,
|
||||
ICE_TX_DESC_CMD_RS = 0x0002,
|
||||
ICE_TX_DESC_CMD_IL2TAG1 = 0x0008,
|
||||
ICE_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */
|
||||
ICE_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */
|
||||
ICE_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */
|
||||
ICE_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */
|
||||
ICE_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */
|
||||
};
|
||||
|
||||
#define ICE_TXD_QW1_OFFSET_S 16
|
||||
#define ICE_TXD_QW1_OFFSET_M (0x3FFFFULL << ICE_TXD_QW1_OFFSET_S)
|
||||
|
||||
enum ice_tx_desc_len_fields {
|
||||
/* Note: These are predefined bit offsets */
|
||||
ICE_TX_DESC_LEN_MACLEN_S = 0, /* 7 BITS */
|
||||
ICE_TX_DESC_LEN_IPLEN_S = 7, /* 7 BITS */
|
||||
ICE_TX_DESC_LEN_L4_LEN_S = 14 /* 4 BITS */
|
||||
};
|
||||
|
||||
#define ICE_TXD_QW1_TX_BUF_SZ_S 34
|
||||
#define ICE_TXD_QW1_L2TAG1_S 48
|
||||
|
||||
/* Context descriptors */
|
||||
struct ice_tx_ctx_desc {
|
||||
__le32 tunneling_params;
|
||||
__le16 l2tag2;
|
||||
__le16 rsvd;
|
||||
__le64 qw1;
|
||||
};
|
||||
|
||||
#define ICE_TXD_CTX_QW1_CMD_S 4
|
||||
#define ICE_TXD_CTX_QW1_CMD_M (0x7FUL << ICE_TXD_CTX_QW1_CMD_S)
|
||||
|
||||
#define ICE_TXD_CTX_QW1_TSO_LEN_S 30
|
||||
#define ICE_TXD_CTX_QW1_TSO_LEN_M \
|
||||
(0x3FFFFULL << ICE_TXD_CTX_QW1_TSO_LEN_S)
|
||||
|
||||
#define ICE_TXD_CTX_QW1_MSS_S 50
|
||||
|
||||
enum ice_tx_ctx_desc_cmd_bits {
|
||||
ICE_TX_CTX_DESC_TSO = 0x01,
|
||||
ICE_TX_CTX_DESC_TSYN = 0x02,
|
||||
ICE_TX_CTX_DESC_IL2TAG2 = 0x04,
|
||||
ICE_TX_CTX_DESC_IL2TAG2_IL2H = 0x08,
|
||||
ICE_TX_CTX_DESC_SWTCH_NOTAG = 0x00,
|
||||
ICE_TX_CTX_DESC_SWTCH_UPLINK = 0x10,
|
||||
ICE_TX_CTX_DESC_SWTCH_LOCAL = 0x20,
|
||||
ICE_TX_CTX_DESC_SWTCH_VSI = 0x30,
|
||||
ICE_TX_CTX_DESC_RESERVED = 0x40
|
||||
};
|
||||
|
||||
#define ICE_LAN_TXQ_MAX_QGRPS 127
|
||||
#define ICE_LAN_TXQ_MAX_QDIS 1023
|
||||
|
||||
|
@ -289,4 +427,35 @@ struct ice_tlan_ctx {
|
|||
u8 pkt_shaper_prof_idx;
|
||||
u8 int_q_state; /* width not needed - internal do not write */
|
||||
};
|
||||
|
||||
/* macro to make the table lines short */
|
||||
#define ICE_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
|
||||
{ PTYPE, \
|
||||
1, \
|
||||
ICE_RX_PTYPE_OUTER_##OUTER_IP, \
|
||||
ICE_RX_PTYPE_OUTER_##OUTER_IP_VER, \
|
||||
ICE_RX_PTYPE_##OUTER_FRAG, \
|
||||
ICE_RX_PTYPE_TUNNEL_##T, \
|
||||
ICE_RX_PTYPE_TUNNEL_END_##TE, \
|
||||
ICE_RX_PTYPE_##TEF, \
|
||||
ICE_RX_PTYPE_INNER_PROT_##I, \
|
||||
ICE_RX_PTYPE_PAYLOAD_LAYER_##PL }
|
||||
|
||||
#define ICE_PTT_UNUSED_ENTRY(PTYPE) { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
|
||||
/* shorter macros makes the table fit but are terse */
|
||||
#define ICE_RX_PTYPE_NOF ICE_RX_PTYPE_NOT_FRAG
|
||||
|
||||
/* Lookup table mapping the HW PTYPE to the bit field for decoding */
|
||||
static const struct ice_rx_ptype_decoded ice_ptype_lkup[] = {
|
||||
/* L2 Packet types */
|
||||
ICE_PTT_UNUSED_ENTRY(0),
|
||||
ICE_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
|
||||
ICE_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
|
||||
};
|
||||
|
||||
static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)
|
||||
{
|
||||
return ice_ptype_lkup[ptype];
|
||||
}
|
||||
#endif /* _ICE_LAN_TX_RX_H_ */
|
||||
|
|
|
@ -663,6 +663,35 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_set_rss_params - Setup RSS capabilities per VSI type
|
||||
* @vsi: the VSI being configured
|
||||
*/
|
||||
static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
|
||||
{
|
||||
struct ice_hw_common_caps *cap;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
|
||||
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
|
||||
vsi->rss_size = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
cap = &pf->hw.func_caps.common_cap;
|
||||
switch (vsi->type) {
|
||||
case ICE_VSI_PF:
|
||||
/* PF VSI will inherit RSS instance of PF */
|
||||
vsi->rss_table_size = cap->rss_table_size;
|
||||
vsi->rss_size = min_t(int, num_online_cpus(),
|
||||
BIT(cap->rss_table_entry_width));
|
||||
vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_setup_q_map - Setup a VSI queue map
|
||||
* @vsi: the VSI being configured
|
||||
|
@ -670,7 +699,8 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)
|
|||
*/
|
||||
static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
|
||||
{
|
||||
u16 offset = 0, qmap = 0, pow = 0, qcount;
|
||||
u16 offset = 0, qmap = 0, numq_tc;
|
||||
u16 pow = 0, max_rss = 0, qcount;
|
||||
u16 qcount_tx = vsi->alloc_txq;
|
||||
u16 qcount_rx = vsi->alloc_rxq;
|
||||
bool ena_tc0 = false;
|
||||
|
@ -689,13 +719,7 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
|
|||
vsi->tc_cfg.ena_tc |= 1;
|
||||
}
|
||||
|
||||
qcount = qcount_rx / vsi->tc_cfg.numtc;
|
||||
|
||||
/* find higher power-of-2 of qcount */
|
||||
pow = ilog2(qcount);
|
||||
|
||||
if (!is_power_of_2(qcount))
|
||||
pow++;
|
||||
numq_tc = qcount_rx / vsi->tc_cfg.numtc;
|
||||
|
||||
/* TC mapping is a function of the number of Rx queues assigned to the
|
||||
* VSI for each traffic class and the offset of these queues.
|
||||
|
@ -708,6 +732,26 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
|
|||
*
|
||||
* Setup number and offset of Rx queues for all TCs for the VSI
|
||||
*/
|
||||
|
||||
/* qcount will change if RSS is enabled */
|
||||
if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) {
|
||||
if (vsi->type == ICE_VSI_PF)
|
||||
max_rss = ICE_MAX_LG_RSS_QS;
|
||||
else
|
||||
max_rss = ICE_MAX_SMALL_RSS_QS;
|
||||
|
||||
qcount = min_t(int, numq_tc, max_rss);
|
||||
qcount = min_t(int, qcount, vsi->rss_size);
|
||||
} else {
|
||||
qcount = numq_tc;
|
||||
}
|
||||
|
||||
/* find higher power-of-2 of qcount */
|
||||
pow = ilog2(qcount);
|
||||
|
||||
if (!is_power_of_2(qcount))
|
||||
pow++;
|
||||
|
||||
for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
|
||||
if (!(vsi->tc_cfg.ena_tc & BIT(i))) {
|
||||
/* TC is not enabled */
|
||||
|
@ -783,6 +827,33 @@ static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt)
|
|||
/* No Outer tag support outer_tag_flags remains to zero */
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI
|
||||
* @ctxt: the VSI context being set
|
||||
* @vsi: the VSI being configured
|
||||
*/
|
||||
static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
|
||||
{
|
||||
u8 lut_type, hash_type;
|
||||
|
||||
switch (vsi->type) {
|
||||
case ICE_VSI_PF:
|
||||
/* PF VSI will inherit RSS instance of PF */
|
||||
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
|
||||
hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
|
||||
vsi->type);
|
||||
return;
|
||||
}
|
||||
|
||||
ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
|
||||
ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
|
||||
((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &
|
||||
ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_add - Create a new VSI or fetch preallocated VSI
|
||||
* @vsi: the VSI being configured
|
||||
|
@ -810,6 +881,10 @@ static int ice_vsi_add(struct ice_vsi *vsi)
|
|||
if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB)
|
||||
ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
|
||||
|
||||
/* Set LUT type and HASH type if RSS is enabled */
|
||||
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
|
||||
ice_set_rss_vsi_ctx(&ctxt, vsi);
|
||||
|
||||
ctxt.info.sw_id = vsi->port_info->sw_id;
|
||||
ice_vsi_setup_q_map(vsi, &ctxt);
|
||||
|
||||
|
@ -1629,6 +1704,10 @@ static void ice_vsi_free_q_vectors(struct ice_vsi *vsi)
|
|||
*/
|
||||
static int ice_cfg_netdev(struct ice_vsi *vsi)
|
||||
{
|
||||
netdev_features_t csumo_features;
|
||||
netdev_features_t vlano_features;
|
||||
netdev_features_t dflt_features;
|
||||
netdev_features_t tso_features;
|
||||
struct ice_netdev_priv *np;
|
||||
struct net_device *netdev;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
@ -1642,13 +1721,31 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
|
|||
np = netdev_priv(netdev);
|
||||
np->vsi = vsi;
|
||||
|
||||
dflt_features = NETIF_F_SG |
|
||||
NETIF_F_HIGHDMA |
|
||||
NETIF_F_RXHASH;
|
||||
|
||||
csumo_features = NETIF_F_RXCSUM |
|
||||
NETIF_F_IP_CSUM |
|
||||
NETIF_F_IPV6_CSUM;
|
||||
|
||||
vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |
|
||||
NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_CTAG_RX;
|
||||
|
||||
tso_features = NETIF_F_TSO;
|
||||
|
||||
/* set features that user can change */
|
||||
netdev->hw_features = NETIF_F_SG |
|
||||
NETIF_F_HIGHDMA |
|
||||
NETIF_F_RXHASH;
|
||||
netdev->hw_features = dflt_features | csumo_features |
|
||||
vlano_features | tso_features;
|
||||
|
||||
/* enable features */
|
||||
netdev->features |= netdev->hw_features;
|
||||
/* encap and VLAN devices inherit default, csumo and tso features */
|
||||
netdev->hw_enc_features |= dflt_features | csumo_features |
|
||||
tso_features;
|
||||
netdev->vlan_features |= dflt_features | csumo_features |
|
||||
tso_features;
|
||||
|
||||
if (vsi->type == ICE_VSI_PF) {
|
||||
SET_NETDEV_DEV(netdev, &vsi->back->pdev->dev);
|
||||
|
@ -1862,6 +1959,83 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_fill_rss_lut - Fill the RSS lookup table with default values
|
||||
* @lut: Lookup table
|
||||
* @rss_table_size: Lookup table size
|
||||
* @rss_size: Range of queue number for hashing
|
||||
*/
|
||||
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < rss_table_size; i++)
|
||||
lut[i] = i % rss_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_cfg_rss - Configure RSS params for a VSI
|
||||
* @vsi: VSI to be configured
|
||||
*/
|
||||
static int ice_vsi_cfg_rss(struct ice_vsi *vsi)
|
||||
{
|
||||
u8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];
|
||||
struct ice_aqc_get_set_rss_keys *key;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
enum ice_status status;
|
||||
int err = 0;
|
||||
u8 *lut;
|
||||
|
||||
vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq);
|
||||
|
||||
lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL);
|
||||
if (!lut)
|
||||
return -ENOMEM;
|
||||
|
||||
if (vsi->rss_lut_user)
|
||||
memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
|
||||
else
|
||||
ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);
|
||||
|
||||
status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type,
|
||||
lut, vsi->rss_table_size);
|
||||
|
||||
if (status) {
|
||||
dev_err(&vsi->back->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);
|
||||
if (!key) {
|
||||
err = -ENOMEM;
|
||||
goto ice_vsi_cfg_rss_exit;
|
||||
}
|
||||
|
||||
if (vsi->rss_hkey_user)
|
||||
memcpy(seed, vsi->rss_hkey_user,
|
||||
ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
|
||||
else
|
||||
netdev_rss_key_fill((void *)seed,
|
||||
ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
|
||||
memcpy(&key->standard_rss_key, seed,
|
||||
ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
|
||||
|
||||
status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key);
|
||||
|
||||
if (status) {
|
||||
dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n",
|
||||
status);
|
||||
err = -EIO;
|
||||
}
|
||||
|
||||
devm_kfree(&pf->pdev->dev, key);
|
||||
ice_vsi_cfg_rss_exit:
|
||||
devm_kfree(&pf->pdev->dev, lut);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_setup - Set up a VSI by a given type
|
||||
* @pf: board private structure
|
||||
|
@ -1897,6 +2071,9 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,
|
|||
goto err_get_qs;
|
||||
}
|
||||
|
||||
/* set RSS capabilities */
|
||||
ice_vsi_set_rss_params(vsi);
|
||||
|
||||
/* create the VSI */
|
||||
ret = ice_vsi_add(vsi);
|
||||
if (ret)
|
||||
|
@ -1932,6 +2109,12 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,
|
|||
|
||||
ice_vsi_map_rings_to_vectors(vsi);
|
||||
|
||||
/* Do not exit if configuring RSS had an issue, at least
|
||||
* receive traffic on first queue. Hence no need to capture
|
||||
* return value
|
||||
*/
|
||||
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
|
||||
ice_vsi_cfg_rss(vsi);
|
||||
break;
|
||||
default:
|
||||
/* if vsi type is not recognized, clean up the resources and
|
||||
|
@ -1966,6 +2149,140 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_add_vlan - Add vsi membership for given vlan
|
||||
* @vsi: the vsi being configured
|
||||
* @vid: vlan id to be added
|
||||
*/
|
||||
static int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid)
|
||||
{
|
||||
struct ice_fltr_list_entry *tmp;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
LIST_HEAD(tmp_add_list);
|
||||
enum ice_status status;
|
||||
int err = 0;
|
||||
|
||||
tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
|
||||
tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
|
||||
tmp->fltr_info.flag = ICE_FLTR_TX;
|
||||
tmp->fltr_info.src = vsi->vsi_num;
|
||||
tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num;
|
||||
tmp->fltr_info.l_data.vlan.vlan_id = vid;
|
||||
|
||||
INIT_LIST_HEAD(&tmp->list_entry);
|
||||
list_add(&tmp->list_entry, &tmp_add_list);
|
||||
|
||||
status = ice_add_vlan(&pf->hw, &tmp_add_list);
|
||||
if (status) {
|
||||
err = -ENODEV;
|
||||
dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n",
|
||||
vid, vsi->vsi_num);
|
||||
}
|
||||
|
||||
ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vlan_rx_add_vid - Add a vlan id filter to HW offload
|
||||
* @netdev: network interface to be adjusted
|
||||
* @proto: unused protocol
|
||||
* @vid: vlan id to be added
|
||||
*
|
||||
* net_device_ops implementation for adding vlan ids
|
||||
*/
|
||||
static int ice_vlan_rx_add_vid(struct net_device *netdev,
|
||||
__always_unused __be16 proto, u16 vid)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
int ret = 0;
|
||||
|
||||
if (vid >= VLAN_N_VID) {
|
||||
netdev_err(netdev, "VLAN id requested %d is out of range %d\n",
|
||||
vid, VLAN_N_VID);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vsi->info.pvid)
|
||||
return -EINVAL;
|
||||
|
||||
/* Add all VLAN ids including 0 to the switch filter. VLAN id 0 is
|
||||
* needed to continue allowing all untagged packets since VLAN prune
|
||||
* list is applied to all packets by the switch
|
||||
*/
|
||||
ret = ice_vsi_add_vlan(vsi, vid);
|
||||
|
||||
if (!ret)
|
||||
set_bit(vid, vsi->active_vlans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_kill_vlan - Remove VSI membership for a given VLAN
|
||||
* @vsi: the VSI being configured
|
||||
* @vid: VLAN id to be removed
|
||||
*/
|
||||
static void ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid)
|
||||
{
|
||||
struct ice_fltr_list_entry *list;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
LIST_HEAD(tmp_add_list);
|
||||
|
||||
list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
|
||||
list->fltr_info.fwd_id.vsi_id = vsi->vsi_num;
|
||||
list->fltr_info.fltr_act = ICE_FWD_TO_VSI;
|
||||
list->fltr_info.l_data.vlan.vlan_id = vid;
|
||||
list->fltr_info.flag = ICE_FLTR_TX;
|
||||
list->fltr_info.src = vsi->vsi_num;
|
||||
|
||||
INIT_LIST_HEAD(&list->list_entry);
|
||||
list_add(&list->list_entry, &tmp_add_list);
|
||||
|
||||
if (ice_remove_vlan(&pf->hw, &tmp_add_list))
|
||||
dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n",
|
||||
vid, vsi->vsi_num);
|
||||
|
||||
ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
|
||||
* @netdev: network interface to be adjusted
|
||||
* @proto: unused protocol
|
||||
* @vid: vlan id to be removed
|
||||
*
|
||||
* net_device_ops implementation for removing vlan ids
|
||||
*/
|
||||
static int ice_vlan_rx_kill_vid(struct net_device *netdev,
|
||||
__always_unused __be16 proto, u16 vid)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
|
||||
if (vsi->info.pvid)
|
||||
return -EINVAL;
|
||||
|
||||
/* return code is ignored as there is nothing a user
|
||||
* can do about failure to remove and a log message was
|
||||
* already printed from the other function
|
||||
*/
|
||||
ice_vsi_kill_vlan(vsi, vid);
|
||||
|
||||
clear_bit(vid, vsi->active_vlans);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_setup_pf_sw - Setup the HW switch on startup or after reset
|
||||
* @pf: board private structure
|
||||
|
@ -2047,9 +2364,14 @@ static void ice_determine_q_usage(struct ice_pf *pf)
|
|||
q_left_tx = pf->hw.func_caps.common_cap.num_txq;
|
||||
q_left_rx = pf->hw.func_caps.common_cap.num_rxq;
|
||||
|
||||
/* initial support for only 1 tx and 1 rx queue */
|
||||
/* initial support for only 1 tx queue */
|
||||
pf->num_lan_tx = 1;
|
||||
pf->num_lan_rx = 1;
|
||||
|
||||
/* only 1 rx queue unless RSS is enabled */
|
||||
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags))
|
||||
pf->num_lan_rx = 1;
|
||||
else
|
||||
pf->num_lan_rx = min_t(int, q_left_rx, num_online_cpus());
|
||||
|
||||
pf->q_left_tx = q_left_tx - pf->num_lan_tx;
|
||||
pf->q_left_rx = q_left_rx - pf->num_lan_rx;
|
||||
|
@ -2087,6 +2409,9 @@ static void ice_init_pf(struct ice_pf *pf)
|
|||
bitmap_zero(pf->avail_rxqs, ICE_MAX_RXQS);
|
||||
mutex_unlock(&pf->avail_q_mutex);
|
||||
|
||||
if (pf->hw.func_caps.common_cap.rss_table_size)
|
||||
set_bit(ICE_FLAG_RSS_ENA, pf->flags);
|
||||
|
||||
/* setup service timer and periodic service task */
|
||||
timer_setup(&pf->serv_tmr, ice_service_timer, 0);
|
||||
pf->serv_tmr_period = HZ;
|
||||
|
@ -2483,6 +2808,144 @@ static void __exit ice_module_exit(void)
|
|||
}
|
||||
module_exit(ice_module_exit);
|
||||
|
||||
/**
|
||||
* ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
|
||||
* @vsi: the vsi being changed
|
||||
*/
|
||||
static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
|
||||
{
|
||||
struct device *dev = &vsi->back->pdev->dev;
|
||||
struct ice_hw *hw = &vsi->back->hw;
|
||||
struct ice_vsi_ctx ctxt = { 0 };
|
||||
enum ice_status status;
|
||||
|
||||
/* Here we are configuring the VSI to let the driver add VLAN tags by
|
||||
* setting port_vlan_flags to ICE_AQ_VSI_PVLAN_MODE_ALL. The actual VLAN
|
||||
* tag insertion happens in the Tx hot path, in ice_tx_map.
|
||||
*/
|
||||
ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_MODE_ALL;
|
||||
|
||||
ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
|
||||
ctxt.vsi_num = vsi->vsi_num;
|
||||
|
||||
status = ice_aq_update_vsi(hw, &ctxt, NULL);
|
||||
if (status) {
|
||||
dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n",
|
||||
status, hw->adminq.sq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
vsi->info.port_vlan_flags = ctxt.info.port_vlan_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
|
||||
* @vsi: the vsi being changed
|
||||
* @ena: boolean value indicating if this is a enable or disable request
|
||||
*/
|
||||
static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
|
||||
{
|
||||
struct device *dev = &vsi->back->pdev->dev;
|
||||
struct ice_hw *hw = &vsi->back->hw;
|
||||
struct ice_vsi_ctx ctxt = { 0 };
|
||||
enum ice_status status;
|
||||
|
||||
/* Here we are configuring what the VSI should do with the VLAN tag in
|
||||
* the Rx packet. We can either leave the tag in the packet or put it in
|
||||
* the Rx descriptor.
|
||||
*/
|
||||
if (ena) {
|
||||
/* Strip VLAN tag from Rx packet and put it in the desc */
|
||||
ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH;
|
||||
} else {
|
||||
/* Disable stripping. Leave tag in packet */
|
||||
ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_NOTHING;
|
||||
}
|
||||
|
||||
ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
|
||||
ctxt.vsi_num = vsi->vsi_num;
|
||||
|
||||
status = ice_aq_update_vsi(hw, &ctxt, NULL);
|
||||
if (status) {
|
||||
dev_err(dev, "update VSI for VALN strip failed, ena = %d err %d aq_err %d\n",
|
||||
ena, status, hw->adminq.sq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
vsi->info.port_vlan_flags = ctxt.info.port_vlan_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_set_features - set the netdev feature flags
|
||||
* @netdev: ptr to the netdev being adjusted
|
||||
* @features: the feature set that the stack is suggesting
|
||||
*/
|
||||
static int ice_set_features(struct net_device *netdev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
int ret = 0;
|
||||
|
||||
if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
|
||||
!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
|
||||
ret = ice_vsi_manage_vlan_stripping(vsi, true);
|
||||
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))
|
||||
ret = ice_vsi_manage_vlan_insertion(vsi);
|
||||
else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) &&
|
||||
(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
|
||||
ret = ice_vsi_manage_vlan_insertion(vsi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_vlan_setup - Setup vlan offload properties on a VSI
|
||||
* @vsi: VSI to setup vlan properties for
|
||||
*/
|
||||
static int ice_vsi_vlan_setup(struct ice_vsi *vsi)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
|
||||
ret = ice_vsi_manage_vlan_stripping(vsi, true);
|
||||
if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)
|
||||
ret = ice_vsi_manage_vlan_insertion(vsi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_restore_vlan - Reinstate VLANs when vsi/netdev comes back up
|
||||
* @vsi: the VSI being brought back up
|
||||
*/
|
||||
static int ice_restore_vlan(struct ice_vsi *vsi)
|
||||
{
|
||||
int err;
|
||||
u16 vid;
|
||||
|
||||
if (!vsi->netdev)
|
||||
return -EINVAL;
|
||||
|
||||
err = ice_vsi_vlan_setup(vsi);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID) {
|
||||
err = ice_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q), vid);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance
|
||||
* @ring: The Tx ring to configure
|
||||
|
@ -2735,6 +3198,10 @@ static int ice_vsi_cfg(struct ice_vsi *vsi)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = ice_restore_vlan(vsi);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ice_vsi_cfg_txqs(vsi);
|
||||
if (!err)
|
||||
err = ice_vsi_cfg_rxqs(vsi);
|
||||
|
@ -3213,6 +3680,22 @@ static void ice_vsi_close(struct ice_vsi *vsi)
|
|||
ice_vsi_free_rx_rings(vsi);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_rss_clean - Delete RSS related VSI structures that hold user inputs
|
||||
* @vsi: the VSI being removed
|
||||
*/
|
||||
static void ice_rss_clean(struct ice_vsi *vsi)
|
||||
{
|
||||
struct ice_pf *pf;
|
||||
|
||||
pf = vsi->back;
|
||||
|
||||
if (vsi->rss_hkey_user)
|
||||
devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user);
|
||||
if (vsi->rss_lut_user)
|
||||
devm_kfree(&pf->pdev->dev, vsi->rss_lut_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_release - Delete a VSI and free its resources
|
||||
* @vsi: the VSI being removed
|
||||
|
@ -3233,6 +3716,10 @@ static int ice_vsi_release(struct ice_vsi *vsi)
|
|||
vsi->netdev = NULL;
|
||||
}
|
||||
|
||||
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
|
||||
ice_rss_clean(vsi);
|
||||
|
||||
/* Disable VSI and free resources */
|
||||
ice_vsi_dis_irq(vsi);
|
||||
ice_vsi_close(vsi);
|
||||
|
||||
|
@ -3254,6 +3741,91 @@ static int ice_vsi_release(struct ice_vsi *vsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_set_rss - Set RSS keys and lut
|
||||
* @vsi: Pointer to VSI structure
|
||||
* @seed: RSS hash seed
|
||||
* @lut: Lookup table
|
||||
* @lut_size: Lookup table size
|
||||
*
|
||||
* Returns 0 on success, negative on failure
|
||||
*/
|
||||
int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
|
||||
{
|
||||
struct ice_pf *pf = vsi->back;
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
enum ice_status status;
|
||||
|
||||
if (seed) {
|
||||
struct ice_aqc_get_set_rss_keys *buf =
|
||||
(struct ice_aqc_get_set_rss_keys *)seed;
|
||||
|
||||
status = ice_aq_set_rss_key(hw, vsi->vsi_num, buf);
|
||||
|
||||
if (status) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"Cannot set RSS key, err %d aq_err %d\n",
|
||||
status, hw->adminq.rq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (lut) {
|
||||
status = ice_aq_set_rss_lut(hw, vsi->vsi_num,
|
||||
vsi->rss_lut_type, lut, lut_size);
|
||||
if (status) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"Cannot set RSS lut, err %d aq_err %d\n",
|
||||
status, hw->adminq.rq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_rss - Get RSS keys and lut
|
||||
* @vsi: Pointer to VSI structure
|
||||
* @seed: Buffer to store the keys
|
||||
* @lut: Buffer to store the lookup table entries
|
||||
* @lut_size: Size of buffer to store the lookup table entries
|
||||
*
|
||||
* Returns 0 on success, negative on failure
|
||||
*/
|
||||
int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
|
||||
{
|
||||
struct ice_pf *pf = vsi->back;
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
enum ice_status status;
|
||||
|
||||
if (seed) {
|
||||
struct ice_aqc_get_set_rss_keys *buf =
|
||||
(struct ice_aqc_get_set_rss_keys *)seed;
|
||||
|
||||
status = ice_aq_get_rss_key(hw, vsi->vsi_num, buf);
|
||||
if (status) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"Cannot get RSS key, err %d aq_err %d\n",
|
||||
status, hw->adminq.rq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (lut) {
|
||||
status = ice_aq_get_rss_lut(hw, vsi->vsi_num,
|
||||
vsi->rss_lut_type, lut, lut_size);
|
||||
if (status) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
"Cannot get RSS lut, err %d aq_err %d\n",
|
||||
status, hw->adminq.rq_last_status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_open - Called when a network interface becomes active
|
||||
* @netdev: network interface device structure
|
||||
|
@ -3306,4 +3878,7 @@ static const struct net_device_ops ice_netdev_ops = {
|
|||
.ndo_open = ice_open,
|
||||
.ndo_stop = ice_stop,
|
||||
.ndo_start_xmit = ice_start_xmit,
|
||||
.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
|
||||
.ndo_set_features = ice_set_features,
|
||||
};
|
||||
|
|
|
@ -1217,6 +1217,117 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_find_vlan_entry
|
||||
* @hw: pointer to the hardware structure
|
||||
* @vlan_id: VLAN id to search for
|
||||
*
|
||||
* Helper function to search for a VLAN entry using a given VLAN id
|
||||
* Returns pointer to the entry if found.
|
||||
*/
|
||||
static struct ice_fltr_mgmt_list_entry *
|
||||
ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id)
|
||||
{
|
||||
struct ice_fltr_mgmt_list_entry *vlan_list_itr, *vlan_ret = NULL;
|
||||
struct ice_switch_info *sw = hw->switch_info;
|
||||
|
||||
mutex_lock(&sw->vlan_list_lock);
|
||||
list_for_each_entry(vlan_list_itr, &sw->vlan_list_head, list_entry)
|
||||
if (vlan_list_itr->fltr_info.l_data.vlan.vlan_id == vlan_id) {
|
||||
vlan_ret = vlan_list_itr;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&sw->vlan_list_lock);
|
||||
return vlan_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_add_vlan_internal - Add one VLAN based filter rule
|
||||
* @hw: pointer to the hardware structure
|
||||
* @f_entry: filter entry containing one VLAN information
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
|
||||
{
|
||||
struct ice_fltr_info *new_fltr, *cur_fltr;
|
||||
struct ice_fltr_mgmt_list_entry *v_list_itr;
|
||||
u16 vlan_id;
|
||||
|
||||
new_fltr = &f_entry->fltr_info;
|
||||
/* VLAN id should only be 12 bits */
|
||||
if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
vlan_id = new_fltr->l_data.vlan.vlan_id;
|
||||
v_list_itr = ice_find_vlan_entry(hw, vlan_id);
|
||||
if (!v_list_itr) {
|
||||
u16 vsi_id = ICE_VSI_INVAL_ID;
|
||||
enum ice_status status;
|
||||
u16 vsi_list_id = 0;
|
||||
|
||||
if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
|
||||
enum ice_sw_lkup_type lkup_type = new_fltr->lkup_type;
|
||||
|
||||
/* All VLAN pruning rules use a VSI list.
|
||||
* Convert the action to forwarding to a VSI list.
|
||||
*/
|
||||
vsi_id = new_fltr->fwd_id.vsi_id;
|
||||
status = ice_create_vsi_list_rule(hw, &vsi_id, 1,
|
||||
&vsi_list_id,
|
||||
lkup_type);
|
||||
if (status)
|
||||
return status;
|
||||
new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
|
||||
new_fltr->fwd_id.vsi_list_id = vsi_list_id;
|
||||
}
|
||||
|
||||
status = ice_create_pkt_fwd_rule(hw, f_entry);
|
||||
if (!status && vsi_id != ICE_VSI_INVAL_ID) {
|
||||
v_list_itr = ice_find_vlan_entry(hw, vlan_id);
|
||||
if (!v_list_itr)
|
||||
return ICE_ERR_DOES_NOT_EXIST;
|
||||
v_list_itr->vsi_list_info =
|
||||
ice_create_vsi_list_map(hw, &vsi_id, 1,
|
||||
vsi_list_id);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cur_fltr = &v_list_itr->fltr_info;
|
||||
return ice_handle_vsi_list_mgmt(hw, v_list_itr, cur_fltr, new_fltr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_add_vlan - Add VLAN based filter rule
|
||||
* @hw: pointer to the hardware structure
|
||||
* @v_list: list of VLAN entries and forwarding information
|
||||
*/
|
||||
enum ice_status
|
||||
ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
|
||||
{
|
||||
struct ice_fltr_list_entry *v_list_itr;
|
||||
|
||||
if (!v_list || !hw)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
list_for_each_entry(v_list_itr, v_list, list_entry) {
|
||||
enum ice_status status;
|
||||
|
||||
if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
status = ice_add_vlan_internal(hw, v_list_itr);
|
||||
if (status) {
|
||||
v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;
|
||||
return status;
|
||||
}
|
||||
v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_remove_vsi_list_rule
|
||||
* @hw: pointer to the hardware structure
|
||||
|
@ -1515,6 +1626,54 @@ ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_remove_vlan_internal - Remove one VLAN based filter rule
|
||||
* @hw: pointer to the hardware structure
|
||||
* @f_entry: filter entry containing one VLAN information
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_remove_vlan_internal(struct ice_hw *hw,
|
||||
struct ice_fltr_list_entry *f_entry)
|
||||
{
|
||||
struct ice_fltr_info *new_fltr;
|
||||
struct ice_fltr_mgmt_list_entry *v_list_elem;
|
||||
u16 vsi_id;
|
||||
|
||||
new_fltr = &f_entry->fltr_info;
|
||||
|
||||
v_list_elem = ice_find_vlan_entry(hw, new_fltr->l_data.vlan.vlan_id);
|
||||
if (!v_list_elem)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
vsi_id = f_entry->fltr_info.fwd_id.vsi_id;
|
||||
return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, v_list_elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_remove_vlan - Remove VLAN based filter rule
|
||||
* @hw: pointer to the hardware structure
|
||||
* @v_list: list of VLAN entries and forwarding information
|
||||
*/
|
||||
enum ice_status
|
||||
ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
|
||||
{
|
||||
struct ice_fltr_list_entry *v_list_itr;
|
||||
enum ice_status status = 0;
|
||||
|
||||
if (!v_list || !hw)
|
||||
return ICE_ERR_PARAM;
|
||||
|
||||
list_for_each_entry(v_list_itr, v_list, list_entry) {
|
||||
status = ice_remove_vlan_internal(hw, v_list_itr);
|
||||
if (status) {
|
||||
v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;
|
||||
return status;
|
||||
}
|
||||
v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_add_to_vsi_fltr_list - Add VSI filters to the list
|
||||
* @hw: pointer to the hardware structure
|
||||
|
@ -1600,6 +1759,16 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id,
|
|||
}
|
||||
break;
|
||||
case ICE_SW_LKUP_VLAN:
|
||||
mutex_lock(&sw->vlan_list_lock);
|
||||
status = ice_add_to_vsi_fltr_list(hw, vsi_id,
|
||||
&sw->vlan_list_head,
|
||||
&remove_list_head);
|
||||
mutex_unlock(&sw->vlan_list_lock);
|
||||
if (!status) {
|
||||
ice_remove_vlan(hw, &remove_list_head);
|
||||
goto free_fltr_list;
|
||||
}
|
||||
break;
|
||||
case ICE_SW_LKUP_MAC_VLAN:
|
||||
case ICE_SW_LKUP_ETHERTYPE:
|
||||
case ICE_SW_LKUP_ETHERTYPE_MAC:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#define ICE_SW_CFG_MAX_BUF_LEN 2048
|
||||
#define ICE_DFLT_VSI_INVAL 0xff
|
||||
#define ICE_VSI_INVAL_ID 0xffff
|
||||
|
||||
/* VSI context structure for add/get/update/free operations */
|
||||
struct ice_vsi_ctx {
|
||||
|
@ -152,4 +153,7 @@ enum ice_status ice_get_initial_sw_cfg(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);
|
||||
void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);
|
||||
enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);
|
||||
enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list);
|
||||
|
||||
#endif /* _ICE_SWITCH_H_ */
|
||||
|
|
|
@ -796,6 +796,134 @@ static bool ice_is_non_eop(struct ice_ring *rx_ring,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptype_to_htype - get a hash type
|
||||
* @ptype: the ptype value from the descriptor
|
||||
*
|
||||
* Returns a hash type to be used by skb_set_hash
|
||||
*/
|
||||
static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype)
|
||||
{
|
||||
return PKT_HASH_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_rx_hash - set the hash value in the skb
|
||||
* @rx_ring: descriptor ring
|
||||
* @rx_desc: specific descriptor
|
||||
* @skb: pointer to current skb
|
||||
* @rx_ptype: the ptype value from the descriptor
|
||||
*/
|
||||
static void
|
||||
ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,
|
||||
struct sk_buff *skb, u8 rx_ptype)
|
||||
{
|
||||
struct ice_32b_rx_flex_desc_nic *nic_mdid;
|
||||
u32 hash;
|
||||
|
||||
if (!(rx_ring->netdev->features & NETIF_F_RXHASH))
|
||||
return;
|
||||
|
||||
if (rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC)
|
||||
return;
|
||||
|
||||
nic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
|
||||
hash = le32_to_cpu(nic_mdid->rss_hash);
|
||||
skb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_rx_csum - Indicate in skb if checksum is good
|
||||
* @vsi: the VSI we care about
|
||||
* @skb: skb currently being received and modified
|
||||
* @rx_desc: the receive descriptor
|
||||
* @ptype: the packet type decoded by hardware
|
||||
*
|
||||
* skb->protocol must be set before this function is called
|
||||
*/
|
||||
static void ice_rx_csum(struct ice_vsi *vsi, struct sk_buff *skb,
|
||||
union ice_32b_rx_flex_desc *rx_desc, u8 ptype)
|
||||
{
|
||||
struct ice_rx_ptype_decoded decoded;
|
||||
u32 rx_error, rx_status;
|
||||
bool ipv4, ipv6;
|
||||
|
||||
rx_status = le16_to_cpu(rx_desc->wb.status_error0);
|
||||
rx_error = rx_status;
|
||||
|
||||
decoded = ice_decode_rx_desc_ptype(ptype);
|
||||
|
||||
/* Start with CHECKSUM_NONE and by default csum_level = 0 */
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb_checksum_none_assert(skb);
|
||||
|
||||
/* check if Rx checksum is enabled */
|
||||
if (!(vsi->netdev->features & NETIF_F_RXCSUM))
|
||||
return;
|
||||
|
||||
/* check if HW has decoded the packet and checksum */
|
||||
if (!(rx_status & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S)))
|
||||
return;
|
||||
|
||||
if (!(decoded.known && decoded.outer_ip))
|
||||
return;
|
||||
|
||||
ipv4 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) &&
|
||||
(decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4);
|
||||
ipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) &&
|
||||
(decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6);
|
||||
|
||||
if (ipv4 && (rx_error & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) |
|
||||
BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S))))
|
||||
goto checksum_fail;
|
||||
else if (ipv6 && (rx_status &
|
||||
(BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S))))
|
||||
goto checksum_fail;
|
||||
|
||||
/* check for L4 errors and handle packets that were not able to be
|
||||
* checksummed due to arrival speed
|
||||
*/
|
||||
if (rx_error & BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_L4E_S))
|
||||
goto checksum_fail;
|
||||
|
||||
/* Only report checksum unnecessary for TCP, UDP, or SCTP */
|
||||
switch (decoded.inner_prot) {
|
||||
case ICE_RX_PTYPE_INNER_PROT_TCP:
|
||||
case ICE_RX_PTYPE_INNER_PROT_UDP:
|
||||
case ICE_RX_PTYPE_INNER_PROT_SCTP:
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
checksum_fail:
|
||||
vsi->back->hw_csum_rx_error++;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_process_skb_fields - Populate skb header fields from Rx descriptor
|
||||
* @rx_ring: rx descriptor ring packet is being transacted on
|
||||
* @rx_desc: pointer to the EOP Rx descriptor
|
||||
* @skb: pointer to current skb being populated
|
||||
* @ptype: the packet type decoded by hardware
|
||||
*
|
||||
* This function checks the ring, descriptor, and packet information in
|
||||
* order to populate the hash, checksum, VLAN, protocol, and
|
||||
* other fields within the skb.
|
||||
*/
|
||||
static void ice_process_skb_fields(struct ice_ring *rx_ring,
|
||||
union ice_32b_rx_flex_desc *rx_desc,
|
||||
struct sk_buff *skb, u8 ptype)
|
||||
{
|
||||
ice_rx_hash(rx_ring, rx_desc, skb, ptype);
|
||||
|
||||
/* modifies the skb - consumes the enet header */
|
||||
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
|
||||
|
||||
ice_rx_csum(rx_ring->vsi, skb, rx_desc, ptype);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_receive_skb - Send a completed packet up the stack
|
||||
* @rx_ring: rx ring in play
|
||||
|
@ -839,6 +967,7 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
|
|||
struct sk_buff *skb;
|
||||
u16 stat_err_bits;
|
||||
u16 vlan_tag = 0;
|
||||
u8 rx_ptype;
|
||||
|
||||
/* return some buffers to hardware, one at a time is too slow */
|
||||
if (cleaned_count >= ICE_RX_BUF_WRITE) {
|
||||
|
@ -882,6 +1011,9 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
|
|||
continue;
|
||||
}
|
||||
|
||||
rx_ptype = le16_to_cpu(rx_desc->wb.ptype_flex_flags0) &
|
||||
ICE_RX_FLEX_DESC_PTYPE_M;
|
||||
|
||||
stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_L2TAG1P_S);
|
||||
if (ice_test_staterr(rx_desc, stat_err_bits))
|
||||
vlan_tag = le16_to_cpu(rx_desc->wb.l2tag1);
|
||||
|
@ -897,6 +1029,9 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
|
|||
/* probably a little skewed due to removing CRC */
|
||||
total_rx_bytes += skb->len;
|
||||
|
||||
/* populate checksum, VLAN, and protocol */
|
||||
ice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
|
||||
|
||||
/* send completed skb up the stack */
|
||||
ice_receive_skb(rx_ring, skb, vlan_tag);
|
||||
|
||||
|
@ -1026,14 +1161,17 @@ static int ice_maybe_stop_tx(struct ice_ring *tx_ring, unsigned int size)
|
|||
* ice_tx_map - Build the Tx descriptor
|
||||
* @tx_ring: ring to send buffer on
|
||||
* @first: first buffer info buffer to use
|
||||
* @off: pointer to struct that holds offload parameters
|
||||
*
|
||||
* This function loops over the skb data pointed to by *first
|
||||
* and gets a physical address for each memory location and programs
|
||||
* it and the length into the transmit descriptor.
|
||||
*/
|
||||
static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)
|
||||
static void
|
||||
ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first,
|
||||
struct ice_tx_offload_params *off)
|
||||
{
|
||||
u64 td_offset = 0, td_tag = 0, td_cmd = 0;
|
||||
u64 td_offset, td_tag, td_cmd;
|
||||
u16 i = tx_ring->next_to_use;
|
||||
struct skb_frag_struct *frag;
|
||||
unsigned int data_len, size;
|
||||
|
@ -1042,6 +1180,9 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)
|
|||
struct sk_buff *skb;
|
||||
dma_addr_t dma;
|
||||
|
||||
td_tag = off->td_l2tag1;
|
||||
td_cmd = off->td_cmd;
|
||||
td_offset = off->td_offset;
|
||||
skb = first->skb;
|
||||
|
||||
data_len = skb->data_len;
|
||||
|
@ -1049,6 +1190,12 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)
|
|||
|
||||
tx_desc = ICE_TX_DESC(tx_ring, i);
|
||||
|
||||
if (first->tx_flags & ICE_TX_FLAGS_HW_VLAN) {
|
||||
td_cmd |= (u64)ICE_TX_DESC_CMD_IL2TAG1;
|
||||
td_tag = (first->tx_flags & ICE_TX_FLAGS_VLAN_M) >>
|
||||
ICE_TX_FLAGS_VLAN_S;
|
||||
}
|
||||
|
||||
dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
|
||||
|
||||
tx_buf = first;
|
||||
|
@ -1169,6 +1316,223 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)
|
|||
tx_ring->next_to_use = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_tx_csum - Enable Tx checksum offloads
|
||||
* @first: pointer to the first descriptor
|
||||
* @off: pointer to struct that holds offload parameters
|
||||
*
|
||||
* Returns 0 or error (negative) if checksum offload can't happen, 1 otherwise.
|
||||
*/
|
||||
static
|
||||
int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
|
||||
{
|
||||
u32 l4_len = 0, l3_len = 0, l2_len = 0;
|
||||
struct sk_buff *skb = first->skb;
|
||||
union {
|
||||
struct iphdr *v4;
|
||||
struct ipv6hdr *v6;
|
||||
unsigned char *hdr;
|
||||
} ip;
|
||||
union {
|
||||
struct tcphdr *tcp;
|
||||
unsigned char *hdr;
|
||||
} l4;
|
||||
__be16 frag_off, protocol;
|
||||
unsigned char *exthdr;
|
||||
u32 offset, cmd = 0;
|
||||
u8 l4_proto = 0;
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return 0;
|
||||
|
||||
ip.hdr = skb_network_header(skb);
|
||||
l4.hdr = skb_transport_header(skb);
|
||||
|
||||
/* compute outer L2 header size */
|
||||
l2_len = ip.hdr - skb->data;
|
||||
offset = (l2_len / 2) << ICE_TX_DESC_LEN_MACLEN_S;
|
||||
|
||||
if (skb->encapsulation)
|
||||
return -1;
|
||||
|
||||
/* Enable IP checksum offloads */
|
||||
protocol = vlan_get_protocol(skb);
|
||||
if (protocol == htons(ETH_P_IP)) {
|
||||
l4_proto = ip.v4->protocol;
|
||||
/* the stack computes the IP header already, the only time we
|
||||
* need the hardware to recompute it is in the case of TSO.
|
||||
*/
|
||||
if (first->tx_flags & ICE_TX_FLAGS_TSO)
|
||||
cmd |= ICE_TX_DESC_CMD_IIPT_IPV4_CSUM;
|
||||
else
|
||||
cmd |= ICE_TX_DESC_CMD_IIPT_IPV4;
|
||||
|
||||
} else if (protocol == htons(ETH_P_IPV6)) {
|
||||
cmd |= ICE_TX_DESC_CMD_IIPT_IPV6;
|
||||
exthdr = ip.hdr + sizeof(*ip.v6);
|
||||
l4_proto = ip.v6->nexthdr;
|
||||
if (l4.hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_proto,
|
||||
&frag_off);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compute inner L3 header size */
|
||||
l3_len = l4.hdr - ip.hdr;
|
||||
offset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;
|
||||
|
||||
/* Enable L4 checksum offloads */
|
||||
switch (l4_proto) {
|
||||
case IPPROTO_TCP:
|
||||
/* enable checksum offloads */
|
||||
cmd |= ICE_TX_DESC_CMD_L4T_EOFT_TCP;
|
||||
l4_len = l4.tcp->doff;
|
||||
offset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
/* enable UDP checksum offload */
|
||||
cmd |= ICE_TX_DESC_CMD_L4T_EOFT_UDP;
|
||||
l4_len = (sizeof(struct udphdr) >> 2);
|
||||
offset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S;
|
||||
break;
|
||||
case IPPROTO_SCTP:
|
||||
default:
|
||||
if (first->tx_flags & ICE_TX_FLAGS_TSO)
|
||||
return -1;
|
||||
skb_checksum_help(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
off->td_cmd |= cmd;
|
||||
off->td_offset |= offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
|
||||
* @tx_ring: ring to send buffer on
|
||||
* @first: pointer to struct ice_tx_buf
|
||||
*
|
||||
* Checks the skb and set up correspondingly several generic transmit flags
|
||||
* related to VLAN tagging for the HW, such as VLAN, DCB, etc.
|
||||
*
|
||||
* Returns error code indicate the frame should be dropped upon error and the
|
||||
* otherwise returns 0 to indicate the flags has been set properly.
|
||||
*/
|
||||
static int
|
||||
ice_tx_prepare_vlan_flags(struct ice_ring *tx_ring, struct ice_tx_buf *first)
|
||||
{
|
||||
struct sk_buff *skb = first->skb;
|
||||
__be16 protocol = skb->protocol;
|
||||
|
||||
if (protocol == htons(ETH_P_8021Q) &&
|
||||
!(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) {
|
||||
/* when HW VLAN acceleration is turned off by the user the
|
||||
* stack sets the protocol to 8021q so that the driver
|
||||
* can take any steps required to support the SW only
|
||||
* VLAN handling. In our case the driver doesn't need
|
||||
* to take any further steps so just set the protocol
|
||||
* to the encapsulated ethertype.
|
||||
*/
|
||||
skb->protocol = vlan_get_protocol(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if we have a HW VLAN tag being added, default to the HW one */
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
first->tx_flags |= skb_vlan_tag_get(skb) << ICE_TX_FLAGS_VLAN_S;
|
||||
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
|
||||
} else if (protocol == htons(ETH_P_8021Q)) {
|
||||
struct vlan_hdr *vhdr, _vhdr;
|
||||
|
||||
/* for SW VLAN, check the next protocol and store the tag */
|
||||
vhdr = (struct vlan_hdr *)skb_header_pointer(skb, ETH_HLEN,
|
||||
sizeof(_vhdr),
|
||||
&_vhdr);
|
||||
if (!vhdr)
|
||||
return -EINVAL;
|
||||
|
||||
first->tx_flags |= ntohs(vhdr->h_vlan_TCI) <<
|
||||
ICE_TX_FLAGS_VLAN_S;
|
||||
first->tx_flags |= ICE_TX_FLAGS_SW_VLAN;
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_tso - computes mss and TSO length to prepare for TSO
|
||||
* @first: pointer to struct ice_tx_buf
|
||||
* @off: pointer to struct that holds offload parameters
|
||||
*
|
||||
* Returns 0 or error (negative) if TSO can't happen, 1 otherwise.
|
||||
*/
|
||||
static
|
||||
int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
|
||||
{
|
||||
struct sk_buff *skb = first->skb;
|
||||
union {
|
||||
struct iphdr *v4;
|
||||
struct ipv6hdr *v6;
|
||||
unsigned char *hdr;
|
||||
} ip;
|
||||
union {
|
||||
struct tcphdr *tcp;
|
||||
unsigned char *hdr;
|
||||
} l4;
|
||||
u64 cd_mss, cd_tso_len;
|
||||
u32 paylen, l4_start;
|
||||
int err;
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return 0;
|
||||
|
||||
if (!skb_is_gso(skb))
|
||||
return 0;
|
||||
|
||||
err = skb_cow_head(skb, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
ip.hdr = skb_network_header(skb);
|
||||
l4.hdr = skb_transport_header(skb);
|
||||
|
||||
/* initialize outer IP header fields */
|
||||
if (ip.v4->version == 4) {
|
||||
ip.v4->tot_len = 0;
|
||||
ip.v4->check = 0;
|
||||
} else {
|
||||
ip.v6->payload_len = 0;
|
||||
}
|
||||
|
||||
/* determine offset of transport header */
|
||||
l4_start = l4.hdr - skb->data;
|
||||
|
||||
/* remove payload length from checksum */
|
||||
paylen = skb->len - l4_start;
|
||||
csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen));
|
||||
|
||||
/* compute length of segmentation header */
|
||||
off->header_len = (l4.tcp->doff * 4) + l4_start;
|
||||
|
||||
/* update gso_segs and bytecount */
|
||||
first->gso_segs = skb_shinfo(skb)->gso_segs;
|
||||
first->bytecount = (first->gso_segs - 1) * off->header_len;
|
||||
|
||||
cd_tso_len = skb->len - off->header_len;
|
||||
cd_mss = skb_shinfo(skb)->gso_size;
|
||||
|
||||
/* record cdesc_qw1 with TSO parameters */
|
||||
off->cd_qw1 |= ICE_TX_DESC_DTYPE_CTX |
|
||||
(ICE_TX_CTX_DESC_TSO << ICE_TXD_CTX_QW1_CMD_S) |
|
||||
(cd_tso_len << ICE_TXD_CTX_QW1_TSO_LEN_S) |
|
||||
(cd_mss << ICE_TXD_CTX_QW1_MSS_S);
|
||||
first->tx_flags |= ICE_TX_FLAGS_TSO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_txd_use_count - estimate the number of descriptors needed for Tx
|
||||
* @size: transmit request size in bytes
|
||||
|
@ -1322,8 +1686,10 @@ static bool ice_chk_linearize(struct sk_buff *skb, unsigned int count)
|
|||
static netdev_tx_t
|
||||
ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
|
||||
{
|
||||
struct ice_tx_offload_params offload = { 0 };
|
||||
struct ice_tx_buf *first;
|
||||
unsigned int count;
|
||||
int tso, csum;
|
||||
|
||||
count = ice_xmit_desc_count(skb);
|
||||
if (ice_chk_linearize(skb, count)) {
|
||||
|
@ -1344,13 +1710,46 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
|
|||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
offload.tx_ring = tx_ring;
|
||||
|
||||
/* record the location of the first descriptor for this packet */
|
||||
first = &tx_ring->tx_buf[tx_ring->next_to_use];
|
||||
first->skb = skb;
|
||||
first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
|
||||
first->gso_segs = 1;
|
||||
first->tx_flags = 0;
|
||||
|
||||
ice_tx_map(tx_ring, first);
|
||||
/* prepare the VLAN tagging flags for Tx */
|
||||
if (ice_tx_prepare_vlan_flags(tx_ring, first))
|
||||
goto out_drop;
|
||||
|
||||
/* set up TSO offload */
|
||||
tso = ice_tso(first, &offload);
|
||||
if (tso < 0)
|
||||
goto out_drop;
|
||||
|
||||
/* always set up Tx checksum offload */
|
||||
csum = ice_tx_csum(first, &offload);
|
||||
if (csum < 0)
|
||||
goto out_drop;
|
||||
|
||||
if (tso || offload.cd_tunnel_params) {
|
||||
struct ice_tx_ctx_desc *cdesc;
|
||||
int i = tx_ring->next_to_use;
|
||||
|
||||
/* grab the next descriptor */
|
||||
cdesc = ICE_TX_CTX_DESC(tx_ring, i);
|
||||
i++;
|
||||
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
|
||||
|
||||
/* setup context descriptor */
|
||||
cdesc->tunneling_params = cpu_to_le32(offload.cd_tunnel_params);
|
||||
cdesc->l2tag2 = cpu_to_le16(offload.cd_l2tag2);
|
||||
cdesc->rsvd = cpu_to_le16(0);
|
||||
cdesc->qw1 = cpu_to_le64(offload.cd_qw1);
|
||||
}
|
||||
|
||||
ice_tx_map(tx_ring, first, &offload);
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
out_drop:
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
|
||||
(R)->next_to_clean - (R)->next_to_use - 1)
|
||||
|
||||
#define ICE_TX_FLAGS_TSO BIT(0)
|
||||
#define ICE_TX_FLAGS_HW_VLAN BIT(1)
|
||||
#define ICE_TX_FLAGS_SW_VLAN BIT(2)
|
||||
#define ICE_TX_FLAGS_VLAN_M 0xffff0000
|
||||
#define ICE_TX_FLAGS_VLAN_S 16
|
||||
|
||||
struct ice_tx_buf {
|
||||
struct ice_tx_desc *next_to_watch;
|
||||
struct sk_buff *skb;
|
||||
|
@ -38,6 +44,17 @@ struct ice_tx_buf {
|
|||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
};
|
||||
|
||||
struct ice_tx_offload_params {
|
||||
u8 header_len;
|
||||
u32 td_cmd;
|
||||
u32 td_offset;
|
||||
u32 td_l2tag1;
|
||||
u16 cd_l2tag2;
|
||||
u32 cd_tunnel_params;
|
||||
u64 cd_qw1;
|
||||
struct ice_ring *tx_ring;
|
||||
};
|
||||
|
||||
struct ice_rx_buf {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t dma;
|
||||
|
|
Loading…
Reference in New Issue