Merge branch 'hns3-next' into net-next
Huazhong Tan says: ==================== This patch-set includes some new features for the HNS3 ethernet controller driver. [patch 01/06] adds support for configuring VF link status on the host. [patch 02/06] adds support for configuring VF spoof check. [patch 03/06] adds support for configuring VF trust. [patch 04/06] adds support for configuring VF bandwidth on the host. [patch 05/06] adds support for configuring VF MAC on the host. [patch 06/06] adds support for tx-scatter-gather-fraglist. ==================== Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
commit
48423dd7e6
|
@ -45,6 +45,7 @@ enum HCLGE_MBX_OPCODE {
|
|||
HCLGE_MBX_GET_LINK_MODE, /* (VF -> PF) get the link mode of pf */
|
||||
HCLGE_MBX_PUSH_VLAN_INFO, /* (PF -> VF) push port base vlan */
|
||||
HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */
|
||||
HCLGE_MBX_PUSH_PROMISC_INFO, /* (PF -> VF) push vf promisc info */
|
||||
|
||||
HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */
|
||||
HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */
|
||||
|
|
|
@ -364,6 +364,19 @@ struct hnae3_ae_dev {
|
|||
* Enable/disable HW GRO
|
||||
* add_arfs_entry
|
||||
* Check the 5-tuples of flow, and create flow director rule
|
||||
* get_vf_config
|
||||
* Get the VF configuration setting by the host
|
||||
* set_vf_link_state
|
||||
* Set VF link status
|
||||
* set_vf_spoofchk
|
||||
* Enable/disable spoof check for specified vf
|
||||
* set_vf_trust
|
||||
* Enable/disable trust for specified vf, if the vf being trusted, then
|
||||
* it can enable promisc mode
|
||||
* set_vf_rate
|
||||
* Set the max tx rate of specified vf.
|
||||
* set_vf_mac
|
||||
* Configure the default MAC for specified VF
|
||||
*/
|
||||
struct hnae3_ae_ops {
|
||||
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
|
||||
|
@ -529,6 +542,16 @@ struct hnae3_ae_ops {
|
|||
int (*mac_connect_phy)(struct hnae3_handle *handle);
|
||||
void (*mac_disconnect_phy)(struct hnae3_handle *handle);
|
||||
void (*restore_vlan_table)(struct hnae3_handle *handle);
|
||||
int (*get_vf_config)(struct hnae3_handle *handle, int vf,
|
||||
struct ifla_vf_info *ivf);
|
||||
int (*set_vf_link_state)(struct hnae3_handle *handle, int vf,
|
||||
int link_state);
|
||||
int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf,
|
||||
bool enable);
|
||||
int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable);
|
||||
int (*set_vf_rate)(struct hnae3_handle *handle, int vf,
|
||||
int min_tx_rate, int max_tx_rate, bool force);
|
||||
int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p);
|
||||
};
|
||||
|
||||
struct hnae3_dcb_ops {
|
||||
|
|
|
@ -681,7 +681,7 @@ static int hns3_set_tso(struct sk_buff *skb, u32 *paylen,
|
|||
return 0;
|
||||
|
||||
ret = skb_cow_head(skb, 0);
|
||||
if (unlikely(ret))
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
l3.hdr = skb_network_header(skb);
|
||||
|
@ -962,14 +962,6 @@ static int hns3_set_l2l3l4(struct sk_buff *skb, u8 ol4_proto,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hns3_set_txbd_baseinfo(u16 *bdtp_fe_sc_vld_ra_ri, int frag_end)
|
||||
{
|
||||
/* Config bd buffer end */
|
||||
if (!!frag_end)
|
||||
hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, 1U);
|
||||
hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1U);
|
||||
}
|
||||
|
||||
static int hns3_handle_vtags(struct hns3_enet_ring *tx_ring,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1062,7 +1054,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
|
|||
skb_reset_mac_len(skb);
|
||||
|
||||
ret = hns3_get_l4_protocol(skb, &ol4_proto, &il4_proto);
|
||||
if (unlikely(ret)) {
|
||||
if (unlikely(ret < 0)) {
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
ring->stats.tx_l4_proto_err++;
|
||||
u64_stats_update_end(&ring->syncp);
|
||||
|
@ -1072,7 +1064,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
|
|||
ret = hns3_set_l2l3l4(skb, ol4_proto, il4_proto,
|
||||
&type_cs_vlan_tso,
|
||||
&ol_type_vlan_len_msec);
|
||||
if (unlikely(ret)) {
|
||||
if (unlikely(ret < 0)) {
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
ring->stats.tx_l2l3l4_err++;
|
||||
u64_stats_update_end(&ring->syncp);
|
||||
|
@ -1081,7 +1073,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
|
|||
|
||||
ret = hns3_set_tso(skb, &paylen, &mss,
|
||||
&type_cs_vlan_tso);
|
||||
if (unlikely(ret)) {
|
||||
if (unlikely(ret < 0)) {
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
ring->stats.tx_tso_err++;
|
||||
u64_stats_update_end(&ring->syncp);
|
||||
|
@ -1102,9 +1094,10 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
|
|||
}
|
||||
|
||||
static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
||||
unsigned int size, int frag_end,
|
||||
enum hns_desc_type type)
|
||||
unsigned int size, enum hns_desc_type type)
|
||||
{
|
||||
#define HNS3_LIKELY_BD_NUM 1
|
||||
|
||||
struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
|
||||
struct hns3_desc *desc = &ring->desc[ring->next_to_use];
|
||||
struct device *dev = ring_to_dev(ring);
|
||||
|
@ -1118,7 +1111,7 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
|||
int ret;
|
||||
|
||||
ret = hns3_fill_skb_desc(ring, skb, desc);
|
||||
if (unlikely(ret))
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
|
||||
|
@ -1137,19 +1130,16 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
|||
desc_cb->length = size;
|
||||
|
||||
if (likely(size <= HNS3_MAX_BD_SIZE)) {
|
||||
u16 bdtp_fe_sc_vld_ra_ri = 0;
|
||||
|
||||
desc_cb->priv = priv;
|
||||
desc_cb->dma = dma;
|
||||
desc_cb->type = type;
|
||||
desc->addr = cpu_to_le64(dma);
|
||||
desc->tx.send_size = cpu_to_le16(size);
|
||||
hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end);
|
||||
desc->tx.bdtp_fe_sc_vld_ra_ri =
|
||||
cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
|
||||
cpu_to_le16(BIT(HNS3_TXD_VLD_B));
|
||||
|
||||
ring_ptr_move_fw(ring, next_to_use);
|
||||
return 0;
|
||||
return HNS3_LIKELY_BD_NUM;
|
||||
}
|
||||
|
||||
frag_buf_num = hns3_tx_bd_count(size);
|
||||
|
@ -1158,8 +1148,6 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
|||
|
||||
/* When frag size is bigger than hardware limit, split this frag */
|
||||
for (k = 0; k < frag_buf_num; k++) {
|
||||
u16 bdtp_fe_sc_vld_ra_ri = 0;
|
||||
|
||||
/* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
|
||||
desc_cb->priv = priv;
|
||||
desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k;
|
||||
|
@ -1170,11 +1158,8 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
|||
desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k);
|
||||
desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ?
|
||||
(u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE);
|
||||
hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri,
|
||||
frag_end && (k == frag_buf_num - 1) ?
|
||||
1 : 0);
|
||||
desc->tx.bdtp_fe_sc_vld_ra_ri =
|
||||
cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
|
||||
cpu_to_le16(BIT(HNS3_TXD_VLD_B));
|
||||
|
||||
/* move ring pointer to next */
|
||||
ring_ptr_move_fw(ring, next_to_use);
|
||||
|
@ -1183,23 +1168,78 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
|
|||
desc = &ring->desc[ring->next_to_use];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return frag_buf_num;
|
||||
}
|
||||
|
||||
static unsigned int hns3_nic_bd_num(struct sk_buff *skb)
|
||||
static unsigned int hns3_skb_bd_num(struct sk_buff *skb, unsigned int *bd_size,
|
||||
unsigned int bd_num)
|
||||
{
|
||||
unsigned int bd_num;
|
||||
unsigned int size;
|
||||
int i;
|
||||
|
||||
/* if the total len is within the max bd limit */
|
||||
if (likely(skb->len <= HNS3_MAX_BD_SIZE))
|
||||
return skb_shinfo(skb)->nr_frags + 1;
|
||||
size = skb_headlen(skb);
|
||||
while (size > HNS3_MAX_BD_SIZE) {
|
||||
bd_size[bd_num++] = HNS3_MAX_BD_SIZE;
|
||||
size -= HNS3_MAX_BD_SIZE;
|
||||
|
||||
bd_num = hns3_tx_bd_count(skb_headlen(skb));
|
||||
if (bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
bd_size[bd_num++] = size;
|
||||
if (bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||
bd_num += hns3_tx_bd_count(skb_frag_size(frag));
|
||||
size = skb_frag_size(frag);
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
while (size > HNS3_MAX_BD_SIZE) {
|
||||
bd_size[bd_num++] = HNS3_MAX_BD_SIZE;
|
||||
size -= HNS3_MAX_BD_SIZE;
|
||||
|
||||
if (bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
bd_size[bd_num++] = size;
|
||||
if (bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
static unsigned int hns3_tx_bd_num(struct sk_buff *skb, unsigned int *bd_size)
|
||||
{
|
||||
struct sk_buff *frag_skb;
|
||||
unsigned int bd_num = 0;
|
||||
|
||||
/* If the total len is within the max bd limit */
|
||||
if (likely(skb->len <= HNS3_MAX_BD_SIZE && !skb_has_frag_list(skb) &&
|
||||
skb_shinfo(skb)->nr_frags < HNS3_MAX_NON_TSO_BD_NUM))
|
||||
return skb_shinfo(skb)->nr_frags + 1U;
|
||||
|
||||
/* The below case will always be linearized, return
|
||||
* HNS3_MAX_BD_NUM_TSO + 1U to make sure it is linearized.
|
||||
*/
|
||||
if (unlikely(skb->len > HNS3_MAX_TSO_SIZE ||
|
||||
(!skb_is_gso(skb) && skb->len > HNS3_MAX_NON_TSO_SIZE)))
|
||||
return HNS3_MAX_TSO_BD_NUM + 1U;
|
||||
|
||||
bd_num = hns3_skb_bd_num(skb, bd_size, bd_num);
|
||||
|
||||
if (!skb_has_frag_list(skb) || bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
|
||||
skb_walk_frags(skb, frag_skb) {
|
||||
bd_num = hns3_skb_bd_num(frag_skb, bd_size, bd_num);
|
||||
if (bd_num > HNS3_MAX_TSO_BD_NUM)
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
return bd_num;
|
||||
|
@ -1218,26 +1258,26 @@ static unsigned int hns3_gso_hdr_len(struct sk_buff *skb)
|
|||
* 7 frags to to be larger than gso header len + mss, and the remaining
|
||||
* continuous 7 frags to be larger than MSS except the last 7 frags.
|
||||
*/
|
||||
static bool hns3_skb_need_linearized(struct sk_buff *skb)
|
||||
static bool hns3_skb_need_linearized(struct sk_buff *skb, unsigned int *bd_size,
|
||||
unsigned int bd_num)
|
||||
{
|
||||
int bd_limit = HNS3_MAX_BD_NUM_NORMAL - 1;
|
||||
unsigned int tot_len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bd_limit; i++)
|
||||
tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
|
||||
for (i = 0; i < HNS3_MAX_NON_TSO_BD_NUM - 1U; i++)
|
||||
tot_len += bd_size[i];
|
||||
|
||||
/* ensure headlen + the first 7 frags is greater than mss + header
|
||||
* and the first 7 frags is greater than mss.
|
||||
*/
|
||||
if (((tot_len + skb_headlen(skb)) < (skb_shinfo(skb)->gso_size +
|
||||
hns3_gso_hdr_len(skb))) || (tot_len < skb_shinfo(skb)->gso_size))
|
||||
/* ensure the first 8 frags is greater than mss + header */
|
||||
if (tot_len + bd_size[HNS3_MAX_NON_TSO_BD_NUM - 1U] <
|
||||
skb_shinfo(skb)->gso_size + hns3_gso_hdr_len(skb))
|
||||
return true;
|
||||
|
||||
/* ensure the remaining continuous 7 buffer is greater than mss */
|
||||
for (i = 0; i < (skb_shinfo(skb)->nr_frags - bd_limit - 1); i++) {
|
||||
tot_len -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
|
||||
tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i + bd_limit]);
|
||||
/* ensure every continuous 7 buffer is greater than mss
|
||||
* except the last one.
|
||||
*/
|
||||
for (i = 0; i < bd_num - HNS3_MAX_NON_TSO_BD_NUM; i++) {
|
||||
tot_len -= bd_size[i];
|
||||
tot_len += bd_size[i + HNS3_MAX_NON_TSO_BD_NUM - 1U];
|
||||
|
||||
if (tot_len < skb_shinfo(skb)->gso_size)
|
||||
return true;
|
||||
|
@ -1249,15 +1289,16 @@ static bool hns3_skb_need_linearized(struct sk_buff *skb)
|
|||
static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
|
||||
struct sk_buff **out_skb)
|
||||
{
|
||||
unsigned int bd_size[HNS3_MAX_TSO_BD_NUM + 1U];
|
||||
struct sk_buff *skb = *out_skb;
|
||||
unsigned int bd_num;
|
||||
|
||||
bd_num = hns3_nic_bd_num(skb);
|
||||
if (unlikely(bd_num > HNS3_MAX_BD_NUM_NORMAL)) {
|
||||
bd_num = hns3_tx_bd_num(skb, bd_size);
|
||||
if (unlikely(bd_num > HNS3_MAX_NON_TSO_BD_NUM)) {
|
||||
struct sk_buff *new_skb;
|
||||
|
||||
if (skb_is_gso(skb) && bd_num <= HNS3_MAX_BD_NUM_TSO &&
|
||||
!hns3_skb_need_linearized(skb))
|
||||
if (bd_num <= HNS3_MAX_TSO_BD_NUM && skb_is_gso(skb) &&
|
||||
!hns3_skb_need_linearized(skb, bd_size, bd_num))
|
||||
goto out;
|
||||
|
||||
/* manual split the send packet */
|
||||
|
@ -1267,9 +1308,10 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring,
|
|||
dev_kfree_skb_any(skb);
|
||||
*out_skb = new_skb;
|
||||
|
||||
bd_num = hns3_nic_bd_num(new_skb);
|
||||
if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_TSO) ||
|
||||
(!skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_NORMAL))
|
||||
bd_num = hns3_tx_bd_count(new_skb->len);
|
||||
if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_TSO_BD_NUM) ||
|
||||
(!skb_is_gso(new_skb) &&
|
||||
bd_num > HNS3_MAX_NON_TSO_BD_NUM))
|
||||
return -ENOMEM;
|
||||
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
|
@ -1314,6 +1356,37 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
|
|||
}
|
||||
}
|
||||
|
||||
static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring,
|
||||
struct sk_buff *skb, enum hns_desc_type type)
|
||||
{
|
||||
unsigned int size = skb_headlen(skb);
|
||||
int i, ret, bd_num = 0;
|
||||
|
||||
if (size) {
|
||||
ret = hns3_fill_desc(ring, skb, size, type);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
bd_num += ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||
|
||||
size = skb_frag_size(frag);
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
ret = hns3_fill_desc(ring, frag, size, DESC_TYPE_PAGE);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
bd_num += ret;
|
||||
}
|
||||
|
||||
return bd_num;
|
||||
}
|
||||
|
||||
netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
||||
|
@ -1321,58 +1394,54 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|||
&tx_ring_data(priv, skb->queue_mapping);
|
||||
struct hns3_enet_ring *ring = ring_data->ring;
|
||||
struct netdev_queue *dev_queue;
|
||||
skb_frag_t *frag;
|
||||
int next_to_use_head;
|
||||
int buf_num;
|
||||
int seg_num;
|
||||
int size;
|
||||
int pre_ntu, next_to_use_head;
|
||||
struct sk_buff *frag_skb;
|
||||
int bd_num = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Prefetch the data used later */
|
||||
prefetch(skb->data);
|
||||
|
||||
buf_num = hns3_nic_maybe_stop_tx(ring, &skb);
|
||||
if (unlikely(buf_num <= 0)) {
|
||||
if (buf_num == -EBUSY) {
|
||||
ret = hns3_nic_maybe_stop_tx(ring, &skb);
|
||||
if (unlikely(ret <= 0)) {
|
||||
if (ret == -EBUSY) {
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
ring->stats.tx_busy++;
|
||||
u64_stats_update_end(&ring->syncp);
|
||||
goto out_net_tx_busy;
|
||||
} else if (buf_num == -ENOMEM) {
|
||||
} else if (ret == -ENOMEM) {
|
||||
u64_stats_update_begin(&ring->syncp);
|
||||
ring->stats.sw_err_cnt++;
|
||||
u64_stats_update_end(&ring->syncp);
|
||||
}
|
||||
|
||||
hns3_rl_err(netdev, "xmit error: %d!\n", buf_num);
|
||||
hns3_rl_err(netdev, "xmit error: %d!\n", ret);
|
||||
goto out_err_tx_ok;
|
||||
}
|
||||
|
||||
/* No. of segments (plus a header) */
|
||||
seg_num = skb_shinfo(skb)->nr_frags + 1;
|
||||
/* Fill the first part */
|
||||
size = skb_headlen(skb);
|
||||
|
||||
next_to_use_head = ring->next_to_use;
|
||||
|
||||
ret = hns3_fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0,
|
||||
DESC_TYPE_SKB);
|
||||
if (unlikely(ret))
|
||||
ret = hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB);
|
||||
if (unlikely(ret < 0))
|
||||
goto fill_err;
|
||||
|
||||
/* Fill the fragments */
|
||||
for (i = 1; i < seg_num; i++) {
|
||||
frag = &skb_shinfo(skb)->frags[i - 1];
|
||||
size = skb_frag_size(frag);
|
||||
bd_num += ret;
|
||||
|
||||
ret = hns3_fill_desc(ring, frag, size,
|
||||
seg_num - 1 == i ? 1 : 0,
|
||||
DESC_TYPE_PAGE);
|
||||
if (!skb_has_frag_list(skb))
|
||||
goto out;
|
||||
|
||||
if (unlikely(ret))
|
||||
skb_walk_frags(skb, frag_skb) {
|
||||
ret = hns3_fill_skb_to_desc(ring, frag_skb, DESC_TYPE_PAGE);
|
||||
if (unlikely(ret < 0))
|
||||
goto fill_err;
|
||||
|
||||
bd_num += ret;
|
||||
}
|
||||
out:
|
||||
pre_ntu = ring->next_to_use ? (ring->next_to_use - 1) :
|
||||
(ring->desc_num - 1);
|
||||
ring->desc[pre_ntu].tx.bdtp_fe_sc_vld_ra_ri |=
|
||||
cpu_to_le16(BIT(HNS3_TXD_FE_B));
|
||||
|
||||
/* Complete translate all packets */
|
||||
dev_queue = netdev_get_tx_queue(netdev, ring_data->queue_index);
|
||||
|
@ -1380,7 +1449,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|||
|
||||
wmb(); /* Commit all data before submit */
|
||||
|
||||
hnae3_queue_xmit(ring->tqp, buf_num);
|
||||
hnae3_queue_xmit(ring->tqp, bd_num);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
|
@ -1413,6 +1482,16 @@ static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* For VF device, if there is a perm_addr, then the user will not
|
||||
* be allowed to change the address.
|
||||
*/
|
||||
if (!hns3_is_phys_func(h->pdev) &&
|
||||
!is_zero_ether_addr(netdev->perm_addr)) {
|
||||
netdev_err(netdev, "has permanent MAC %pM, user MAC %pM not allow\n",
|
||||
netdev->perm_addr, mac_addr->sa_data);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = h->ae_algo->ops->set_mac_addr(h, mac_addr->sa_data, false);
|
||||
if (ret) {
|
||||
netdev_err(netdev, "set_mac_address fail, ret=%d!\n", ret);
|
||||
|
@ -1643,6 +1722,29 @@ static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int hns3_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
|
||||
{
|
||||
struct hnae3_handle *handle = hns3_get_handle(netdev);
|
||||
|
||||
if (hns3_nic_resetting(netdev))
|
||||
return -EBUSY;
|
||||
|
||||
if (!handle->ae_algo->ops->set_vf_spoofchk)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return handle->ae_algo->ops->set_vf_spoofchk(handle, vf, enable);
|
||||
}
|
||||
|
||||
static int hns3_set_vf_trust(struct net_device *netdev, int vf, bool enable)
|
||||
{
|
||||
struct hnae3_handle *handle = hns3_get_handle(netdev);
|
||||
|
||||
if (!handle->ae_algo->ops->set_vf_trust)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return handle->ae_algo->ops->set_vf_trust(handle, vf, enable);
|
||||
}
|
||||
|
||||
static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
|
||||
{
|
||||
struct hnae3_handle *h = hns3_get_handle(netdev);
|
||||
|
@ -1805,6 +1907,57 @@ static int hns3_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int hns3_nic_get_vf_config(struct net_device *ndev, int vf,
|
||||
struct ifla_vf_info *ivf)
|
||||
{
|
||||
struct hnae3_handle *h = hns3_get_handle(ndev);
|
||||
|
||||
if (!h->ae_algo->ops->get_vf_config)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return h->ae_algo->ops->get_vf_config(h, vf, ivf);
|
||||
}
|
||||
|
||||
static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf,
|
||||
int link_state)
|
||||
{
|
||||
struct hnae3_handle *h = hns3_get_handle(ndev);
|
||||
|
||||
if (!h->ae_algo->ops->set_vf_link_state)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return h->ae_algo->ops->set_vf_link_state(h, vf, link_state);
|
||||
}
|
||||
|
||||
static int hns3_nic_set_vf_rate(struct net_device *ndev, int vf,
|
||||
int min_tx_rate, int max_tx_rate)
|
||||
{
|
||||
struct hnae3_handle *h = hns3_get_handle(ndev);
|
||||
|
||||
if (!h->ae_algo->ops->set_vf_rate)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return h->ae_algo->ops->set_vf_rate(h, vf, min_tx_rate, max_tx_rate,
|
||||
false);
|
||||
}
|
||||
|
||||
static int hns3_nic_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
|
||||
{
|
||||
struct hnae3_handle *h = hns3_get_handle(netdev);
|
||||
|
||||
if (!h->ae_algo->ops->set_vf_mac)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (is_multicast_ether_addr(mac)) {
|
||||
netdev_err(netdev,
|
||||
"Invalid MAC:%pM specified. Could not set MAC\n",
|
||||
mac);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return h->ae_algo->ops->set_vf_mac(h, vf_id, mac);
|
||||
}
|
||||
|
||||
static const struct net_device_ops hns3_nic_netdev_ops = {
|
||||
.ndo_open = hns3_nic_net_open,
|
||||
.ndo_stop = hns3_nic_net_stop,
|
||||
|
@ -1820,10 +1973,15 @@ static const struct net_device_ops hns3_nic_netdev_ops = {
|
|||
.ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
|
||||
.ndo_set_vf_vlan = hns3_ndo_set_vf_vlan,
|
||||
.ndo_set_vf_spoofchk = hns3_set_vf_spoofchk,
|
||||
.ndo_set_vf_trust = hns3_set_vf_trust,
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
.ndo_rx_flow_steer = hns3_rx_flow_steer,
|
||||
#endif
|
||||
|
||||
.ndo_get_vf_config = hns3_nic_get_vf_config,
|
||||
.ndo_set_vf_link_state = hns3_nic_set_vf_link_state,
|
||||
.ndo_set_vf_rate = hns3_nic_set_vf_rate,
|
||||
.ndo_set_vf_mac = hns3_nic_set_vf_mac,
|
||||
};
|
||||
|
||||
bool hns3_is_phys_func(struct pci_dev *pdev)
|
||||
|
@ -2069,9 +2227,8 @@ static void hns3_set_default_feature(struct net_device *netdev)
|
|||
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
|
||||
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
|
||||
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
|
||||
|
||||
netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
|
||||
NETIF_F_TSO_MANGLEID | NETIF_F_FRAGLIST;
|
||||
|
||||
netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
|
||||
|
||||
|
@ -2081,21 +2238,24 @@ static void hns3_set_default_feature(struct net_device *netdev)
|
|||
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
|
||||
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
|
||||
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
|
||||
NETIF_F_FRAGLIST;
|
||||
|
||||
netdev->vlan_features |=
|
||||
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
|
||||
NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
|
||||
NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
|
||||
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
|
||||
NETIF_F_FRAGLIST;
|
||||
|
||||
netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
|
||||
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
|
||||
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC |
|
||||
NETIF_F_FRAGLIST;
|
||||
|
||||
if (pdev->revision >= 0x21) {
|
||||
netdev->hw_features |= NETIF_F_GRO_HW;
|
||||
|
@ -2358,7 +2518,7 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring)
|
|||
netdev_tx_completed_queue(dev_queue, pkts, bytes);
|
||||
|
||||
if (unlikely(pkts && netif_carrier_ok(netdev) &&
|
||||
(ring_space(ring) > HNS3_MAX_BD_PER_PKT))) {
|
||||
ring_space(ring) > HNS3_MAX_TSO_BD_NUM)) {
|
||||
/* Make sure that anybody stopping the queue after this
|
||||
* sees the new next_to_clean.
|
||||
*/
|
||||
|
@ -3743,23 +3903,24 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
|
|||
}
|
||||
|
||||
/* Set mac addr if it is configured. or leave it to the AE driver */
|
||||
static int hns3_init_mac_addr(struct net_device *netdev, bool init)
|
||||
static int hns3_init_mac_addr(struct net_device *netdev)
|
||||
{
|
||||
struct hns3_nic_priv *priv = netdev_priv(netdev);
|
||||
struct hnae3_handle *h = priv->ae_handle;
|
||||
u8 mac_addr_temp[ETH_ALEN];
|
||||
int ret = 0;
|
||||
|
||||
if (h->ae_algo->ops->get_mac_addr && init) {
|
||||
if (h->ae_algo->ops->get_mac_addr)
|
||||
h->ae_algo->ops->get_mac_addr(h, mac_addr_temp);
|
||||
ether_addr_copy(netdev->dev_addr, mac_addr_temp);
|
||||
}
|
||||
|
||||
/* Check if the MAC address is valid, if not get a random one */
|
||||
if (!is_valid_ether_addr(netdev->dev_addr)) {
|
||||
if (!is_valid_ether_addr(mac_addr_temp)) {
|
||||
eth_hw_addr_random(netdev);
|
||||
dev_warn(priv->dev, "using random MAC address %pM\n",
|
||||
netdev->dev_addr);
|
||||
} else {
|
||||
ether_addr_copy(netdev->dev_addr, mac_addr_temp);
|
||||
ether_addr_copy(netdev->perm_addr, mac_addr_temp);
|
||||
}
|
||||
|
||||
if (h->ae_algo->ops->set_mac_addr)
|
||||
|
@ -3863,7 +4024,7 @@ static int hns3_client_init(struct hnae3_handle *handle)
|
|||
handle->kinfo.netdev = netdev;
|
||||
handle->priv = (void *)priv;
|
||||
|
||||
hns3_init_mac_addr(netdev, true);
|
||||
hns3_init_mac_addr(netdev);
|
||||
|
||||
hns3_set_default_feature(netdev);
|
||||
|
||||
|
@ -4331,7 +4492,7 @@ static int hns3_reset_notify_restore_enet(struct hnae3_handle *handle)
|
|||
bool vlan_filter_enable;
|
||||
int ret;
|
||||
|
||||
ret = hns3_init_mac_addr(netdev, false);
|
||||
ret = hns3_init_mac_addr(netdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ enum hns3_nic_state {
|
|||
#define HNS3_RING_NAME_LEN 16
|
||||
#define HNS3_BUFFER_SIZE_2048 2048
|
||||
#define HNS3_RING_MAX_PENDING 32760
|
||||
#define HNS3_RING_MIN_PENDING 24
|
||||
#define HNS3_RING_MIN_PENDING 72
|
||||
#define HNS3_RING_BD_MULTIPLE 8
|
||||
/* max frame size of mac */
|
||||
#define HNS3_MAC_MAX_FRAME 9728
|
||||
|
@ -195,9 +195,13 @@ enum hns3_nic_state {
|
|||
#define HNS3_VECTOR_INITED 1
|
||||
|
||||
#define HNS3_MAX_BD_SIZE 65535
|
||||
#define HNS3_MAX_BD_NUM_NORMAL 8
|
||||
#define HNS3_MAX_BD_NUM_TSO 63
|
||||
#define HNS3_MAX_BD_PER_PKT MAX_SKB_FRAGS
|
||||
#define HNS3_MAX_NON_TSO_BD_NUM 8U
|
||||
#define HNS3_MAX_TSO_BD_NUM 63U
|
||||
#define HNS3_MAX_TSO_SIZE \
|
||||
(HNS3_MAX_BD_SIZE * HNS3_MAX_TSO_BD_NUM)
|
||||
|
||||
#define HNS3_MAX_NON_TSO_SIZE \
|
||||
(HNS3_MAX_BD_SIZE * HNS3_MAX_NON_TSO_BD_NUM)
|
||||
|
||||
#define HNS3_VECTOR_GL0_OFFSET 0x100
|
||||
#define HNS3_VECTOR_GL1_OFFSET 0x200
|
||||
|
|
|
@ -244,7 +244,7 @@ enum hclge_opcode_type {
|
|||
/* QCN commands */
|
||||
HCLGE_OPC_QCN_MOD_CFG = 0x1A01,
|
||||
HCLGE_OPC_QCN_GRP_TMPLT_CFG = 0x1A02,
|
||||
HCLGE_OPC_QCN_SHAPPING_IR_CFG = 0x1A03,
|
||||
HCLGE_OPC_QCN_SHAPPING_CFG = 0x1A03,
|
||||
HCLGE_OPC_QCN_SHAPPING_BS_CFG = 0x1A04,
|
||||
HCLGE_OPC_QCN_QSET_LINK_CFG = 0x1A05,
|
||||
HCLGE_OPC_QCN_RP_STATUS_GET = 0x1A06,
|
||||
|
@ -1090,9 +1090,6 @@ void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
|
|||
enum hclge_opcode_type opcode, bool is_read);
|
||||
void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
|
||||
|
||||
int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
|
||||
struct hclge_promisc_param *param);
|
||||
|
||||
enum hclge_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw,
|
||||
struct hclge_desc *desc);
|
||||
enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw,
|
||||
|
|
|
@ -1110,6 +1110,82 @@ static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
static void hclge_dbg_dump_qs_shaper_single(struct hclge_dev *hdev, u16 qsid)
|
||||
{
|
||||
struct hclge_qs_shapping_cmd *shap_cfg_cmd;
|
||||
u8 ir_u, ir_b, ir_s, bs_b, bs_s;
|
||||
struct hclge_desc desc;
|
||||
u32 shapping_para;
|
||||
int ret;
|
||||
|
||||
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true);
|
||||
|
||||
shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
|
||||
shap_cfg_cmd->qs_id = cpu_to_le16(qsid);
|
||||
|
||||
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
|
||||
if (ret) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"qs%u failed to get tx_rate, ret=%d\n",
|
||||
qsid, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para);
|
||||
ir_b = hclge_tm_get_field(shapping_para, IR_B);
|
||||
ir_u = hclge_tm_get_field(shapping_para, IR_U);
|
||||
ir_s = hclge_tm_get_field(shapping_para, IR_S);
|
||||
bs_b = hclge_tm_get_field(shapping_para, BS_B);
|
||||
bs_s = hclge_tm_get_field(shapping_para, BS_S);
|
||||
|
||||
dev_info(&hdev->pdev->dev,
|
||||
"qs%u ir_b:%u, ir_u:%u, ir_s:%u, bs_b:%u, bs_s:%u\n",
|
||||
qsid, ir_b, ir_u, ir_s, bs_b, bs_s);
|
||||
}
|
||||
|
||||
static void hclge_dbg_dump_qs_shaper_all(struct hclge_dev *hdev)
|
||||
{
|
||||
struct hnae3_knic_private_info *kinfo;
|
||||
struct hclge_vport *vport;
|
||||
int vport_id, i;
|
||||
|
||||
for (vport_id = 0; vport_id <= pci_num_vf(hdev->pdev); vport_id++) {
|
||||
vport = &hdev->vport[vport_id];
|
||||
kinfo = &vport->nic.kinfo;
|
||||
|
||||
dev_info(&hdev->pdev->dev, "qs cfg of vport%d:\n", vport_id);
|
||||
|
||||
for (i = 0; i < kinfo->num_tc; i++) {
|
||||
u16 qsid = vport->qs_offset + i;
|
||||
|
||||
hclge_dbg_dump_qs_shaper_single(hdev, qsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
|
||||
const char *cmd_buf)
|
||||
{
|
||||
#define HCLGE_MAX_QSET_NUM 1024
|
||||
|
||||
u16 qsid;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou16(cmd_buf, 0, &qsid);
|
||||
if (ret) {
|
||||
hclge_dbg_dump_qs_shaper_all(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (qsid >= HCLGE_MAX_QSET_NUM) {
|
||||
dev_err(&hdev->pdev->dev, "qsid(%u) out of range[0-1023]\n",
|
||||
qsid);
|
||||
return;
|
||||
}
|
||||
|
||||
hclge_dbg_dump_qs_shaper_single(hdev, qsid);
|
||||
}
|
||||
|
||||
int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
|
||||
{
|
||||
#define DUMP_REG "dump reg"
|
||||
|
@ -1145,6 +1221,9 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
|
|||
&cmd_buf[sizeof("dump ncl_config")]);
|
||||
} else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
|
||||
hclge_dbg_dump_mac_tnl_status(hdev);
|
||||
} else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
|
||||
hclge_dbg_dump_qs_shaper(hdev,
|
||||
&cmd_buf[sizeof("dump qs shaper")]);
|
||||
} else {
|
||||
dev_info(&hdev->pdev->dev, "unknown command\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
|
||||
#define HCLGE_LINK_STATUS_MS 10
|
||||
|
||||
#define HCLGE_VF_VPORT_START_NUM 1
|
||||
|
||||
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps);
|
||||
static int hclge_init_vlan_config(struct hclge_dev *hdev);
|
||||
static void hclge_sync_vlan_filter(struct hclge_dev *hdev);
|
||||
|
@ -1182,6 +1184,35 @@ static void hclge_parse_link_mode(struct hclge_dev *hdev, u8 speed_ability)
|
|||
hclge_parse_backplane_link_mode(hdev, speed_ability);
|
||||
}
|
||||
|
||||
static u32 hclge_get_max_speed(u8 speed_ability)
|
||||
{
|
||||
if (speed_ability & HCLGE_SUPPORT_100G_BIT)
|
||||
return HCLGE_MAC_SPEED_100G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_50G_BIT)
|
||||
return HCLGE_MAC_SPEED_50G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_40G_BIT)
|
||||
return HCLGE_MAC_SPEED_40G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_25G_BIT)
|
||||
return HCLGE_MAC_SPEED_25G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_10G_BIT)
|
||||
return HCLGE_MAC_SPEED_10G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_1G_BIT)
|
||||
return HCLGE_MAC_SPEED_1G;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_100M_BIT)
|
||||
return HCLGE_MAC_SPEED_100M;
|
||||
|
||||
if (speed_ability & HCLGE_SUPPORT_10M_BIT)
|
||||
return HCLGE_MAC_SPEED_10M;
|
||||
|
||||
return HCLGE_MAC_SPEED_1G;
|
||||
}
|
||||
|
||||
static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
|
||||
{
|
||||
struct hclge_cfg_param_cmd *req;
|
||||
|
@ -1352,6 +1383,8 @@ static int hclge_configure(struct hclge_dev *hdev)
|
|||
|
||||
hclge_parse_link_mode(hdev, cfg.speed_ability);
|
||||
|
||||
hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability);
|
||||
|
||||
if ((hdev->tc_max > HNAE3_MAX_TC) ||
|
||||
(hdev->tc_max < 1)) {
|
||||
dev_warn(&hdev->pdev->dev, "TC num = %d.\n",
|
||||
|
@ -1633,6 +1666,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev)
|
|||
for (i = 0; i < num_vport; i++) {
|
||||
vport->back = hdev;
|
||||
vport->vport_id = i;
|
||||
vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO;
|
||||
vport->mps = HCLGE_MAC_DEFAULT_FRAME;
|
||||
vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE;
|
||||
vport->rxvlan_cfg.rx_vlan_offload_en = true;
|
||||
|
@ -2853,6 +2887,62 @@ static int hclge_get_status(struct hnae3_handle *handle)
|
|||
return hdev->hw.mac.link;
|
||||
}
|
||||
|
||||
static struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf)
|
||||
{
|
||||
if (pci_num_vf(hdev->pdev) == 0) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"SRIOV is disabled, can not get vport(%d) info.\n", vf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"vf id(%d) is out of range(0 <= vfid < %d)\n",
|
||||
vf, pci_num_vf(hdev->pdev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* VF start from 1 in vport */
|
||||
vf += HCLGE_VF_VPORT_START_NUM;
|
||||
return &hdev->vport[vf];
|
||||
}
|
||||
|
||||
static int hclge_get_vf_config(struct hnae3_handle *handle, int vf,
|
||||
struct ifla_vf_info *ivf)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
ivf->vf = vf;
|
||||
ivf->linkstate = vport->vf_info.link_state;
|
||||
ivf->spoofchk = vport->vf_info.spoofchk;
|
||||
ivf->trusted = vport->vf_info.trusted;
|
||||
ivf->min_tx_rate = 0;
|
||||
ivf->max_tx_rate = vport->vf_info.max_tx_rate;
|
||||
ether_addr_copy(ivf->mac, vport->vf_info.mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf,
|
||||
int link_state)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
vport->vf_info.link_state = link_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
|
||||
{
|
||||
u32 rst_src_reg, cmdq_src_reg, msix_src_reg;
|
||||
|
@ -4558,8 +4648,8 @@ static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle, int vector,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
|
||||
struct hclge_promisc_param *param)
|
||||
static int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
|
||||
struct hclge_promisc_param *param)
|
||||
{
|
||||
struct hclge_promisc_cfg_cmd *req;
|
||||
struct hclge_desc desc;
|
||||
|
@ -4586,8 +4676,9 @@ int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
|
||||
bool en_mc, bool en_bc, int vport_id)
|
||||
static void hclge_promisc_param_init(struct hclge_promisc_param *param,
|
||||
bool en_uc, bool en_mc, bool en_bc,
|
||||
int vport_id)
|
||||
{
|
||||
if (!param)
|
||||
return;
|
||||
|
@ -4602,12 +4693,21 @@ void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
|
|||
param->vf_id = vport_id;
|
||||
}
|
||||
|
||||
int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc,
|
||||
bool en_mc_pmc, bool en_bc_pmc)
|
||||
{
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
struct hclge_promisc_param param;
|
||||
|
||||
hclge_promisc_param_init(¶m, en_uc_pmc, en_mc_pmc, en_bc_pmc,
|
||||
vport->vport_id);
|
||||
return hclge_cmd_set_promisc_mode(hdev, ¶m);
|
||||
}
|
||||
|
||||
static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
|
||||
bool en_mc_pmc)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
struct hclge_promisc_param param;
|
||||
bool en_bc_pmc = true;
|
||||
|
||||
/* For revision 0x20, if broadcast promisc enabled, vlan filter is
|
||||
|
@ -4617,9 +4717,8 @@ static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
|
|||
if (handle->pdev->revision == 0x20)
|
||||
en_bc_pmc = handle->netdev_flags & HNAE3_BPE ? true : false;
|
||||
|
||||
hclge_promisc_param_init(¶m, en_uc_pmc, en_mc_pmc, en_bc_pmc,
|
||||
vport->vport_id);
|
||||
return hclge_cmd_set_promisc_mode(hdev, ¶m);
|
||||
return hclge_set_vport_promisc_mode(vport, en_uc_pmc, en_mc_pmc,
|
||||
en_bc_pmc);
|
||||
}
|
||||
|
||||
static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode)
|
||||
|
@ -7391,6 +7490,67 @@ static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev,
|
|||
return return_status;
|
||||
}
|
||||
|
||||
static bool hclge_check_vf_mac_exist(struct hclge_vport *vport, int vf_idx,
|
||||
u8 *mac_addr)
|
||||
{
|
||||
struct hclge_mac_vlan_tbl_entry_cmd req;
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
struct hclge_desc desc;
|
||||
u16 egress_port = 0;
|
||||
int i;
|
||||
|
||||
if (is_zero_ether_addr(mac_addr))
|
||||
return false;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
hnae3_set_field(egress_port, HCLGE_MAC_EPORT_VFID_M,
|
||||
HCLGE_MAC_EPORT_VFID_S, vport->vport_id);
|
||||
req.egress_port = cpu_to_le16(egress_port);
|
||||
hclge_prepare_mac_addr(&req, mac_addr, false);
|
||||
|
||||
if (hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false) != -ENOENT)
|
||||
return true;
|
||||
|
||||
vf_idx += HCLGE_VF_VPORT_START_NUM;
|
||||
for (i = hdev->num_vmdq_vport + 1; i < hdev->num_alloc_vport; i++)
|
||||
if (i != vf_idx &&
|
||||
ether_addr_equal(mac_addr, hdev->vport[i].vf_info.mac))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf,
|
||||
u8 *mac_addr)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
if (ether_addr_equal(mac_addr, vport->vf_info.mac)) {
|
||||
dev_info(&hdev->pdev->dev,
|
||||
"Specified MAC(=%pM) is same as before, no change committed!\n",
|
||||
mac_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hclge_check_vf_mac_exist(vport, vf, mac_addr)) {
|
||||
dev_err(&hdev->pdev->dev, "Specified MAC(=%pM) exists!\n",
|
||||
mac_addr);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
ether_addr_copy(vport->vf_info.mac, mac_addr);
|
||||
dev_info(&hdev->pdev->dev,
|
||||
"MAC of VF %d has been set to %pM, and it will be reinitialized!\n",
|
||||
vf, mac_addr);
|
||||
|
||||
return hclge_inform_reset_assert_to_vf(vport);
|
||||
}
|
||||
|
||||
static int hclge_add_mgr_tbl(struct hclge_dev *hdev,
|
||||
const struct hclge_mac_mgr_tbl_entry_cmd *req)
|
||||
{
|
||||
|
@ -7564,6 +7724,8 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid,
|
|||
__be16 proto)
|
||||
{
|
||||
#define HCLGE_MAX_VF_BYTES 16
|
||||
|
||||
struct hclge_vport *vport = &hdev->vport[vfid];
|
||||
struct hclge_vlan_filter_vf_cfg_cmd *req0;
|
||||
struct hclge_vlan_filter_vf_cfg_cmd *req1;
|
||||
struct hclge_desc desc[2];
|
||||
|
@ -7572,10 +7734,18 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid,
|
|||
int ret;
|
||||
|
||||
/* if vf vlan table is full, firmware will close vf vlan filter, it
|
||||
* is unable and unnecessary to add new vlan id to vf vlan filter
|
||||
* is unable and unnecessary to add new vlan id to vf vlan filter.
|
||||
* If spoof check is enable, and vf vlan is full, it shouldn't add
|
||||
* new vlan, because tx packets with these vlan id will be dropped.
|
||||
*/
|
||||
if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill)
|
||||
if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) {
|
||||
if (vport->vf_info.spoofchk && vlan) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"Can't add vlan due to spoof check is on and vf vlan table is full\n");
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
hclge_cmd_setup_basic_desc(&desc[0],
|
||||
HCLGE_OPC_VLAN_FILTER_VF_CFG, false);
|
||||
|
@ -8072,12 +8242,15 @@ static void hclge_restore_vlan_table(struct hnae3_handle *handle)
|
|||
}
|
||||
|
||||
list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) {
|
||||
if (vlan->hd_tbl_status)
|
||||
hclge_set_vlan_filter_hw(hdev,
|
||||
htons(ETH_P_8021Q),
|
||||
vport->vport_id,
|
||||
vlan->vlan_id,
|
||||
false);
|
||||
int ret;
|
||||
|
||||
if (!vlan->hd_tbl_status)
|
||||
continue;
|
||||
ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q),
|
||||
vport->vport_id,
|
||||
vlan->vlan_id, false);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9319,6 +9492,219 @@ static void hclge_stats_clear(struct hclge_dev *hdev)
|
|||
memset(&hdev->hw_stats, 0, sizeof(hdev->hw_stats));
|
||||
}
|
||||
|
||||
static int hclge_set_mac_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
|
||||
{
|
||||
return hclge_config_switch_param(hdev, vf, enable,
|
||||
HCLGE_SWITCH_ANTI_SPOOF_MASK);
|
||||
}
|
||||
|
||||
static int hclge_set_vlan_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
|
||||
{
|
||||
return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
|
||||
HCLGE_FILTER_FE_NIC_INGRESS_B,
|
||||
enable, vf);
|
||||
}
|
||||
|
||||
static int hclge_set_vf_spoofchk_hw(struct hclge_dev *hdev, int vf, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hclge_set_mac_spoofchk(hdev, vf, enable);
|
||||
if (ret) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"Set vf %d mac spoof check %s failed, ret=%d\n",
|
||||
vf, enable ? "on" : "off", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hclge_set_vlan_spoofchk(hdev, vf, enable);
|
||||
if (ret)
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"Set vf %d vlan spoof check %s failed, ret=%d\n",
|
||||
vf, enable ? "on" : "off", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hclge_set_vf_spoofchk(struct hnae3_handle *handle, int vf,
|
||||
bool enable)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
u32 new_spoofchk = enable ? 1 : 0;
|
||||
int ret;
|
||||
|
||||
if (hdev->pdev->revision == 0x20)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
if (vport->vf_info.spoofchk == new_spoofchk)
|
||||
return 0;
|
||||
|
||||
if (enable && test_bit(vport->vport_id, hdev->vf_vlan_full))
|
||||
dev_warn(&hdev->pdev->dev,
|
||||
"vf %d vlan table is full, enable spoof check may cause its packet send fail\n",
|
||||
vf);
|
||||
else if (enable && hclge_is_umv_space_full(vport))
|
||||
dev_warn(&hdev->pdev->dev,
|
||||
"vf %d mac table is full, enable spoof check may cause its packet send fail\n",
|
||||
vf);
|
||||
|
||||
ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vport->vf_info.spoofchk = new_spoofchk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev)
|
||||
{
|
||||
struct hclge_vport *vport = hdev->vport;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (hdev->pdev->revision == 0x20)
|
||||
return 0;
|
||||
|
||||
/* resume the vf spoof check state after reset */
|
||||
for (i = 0; i < hdev->num_alloc_vport; i++) {
|
||||
ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id,
|
||||
vport->vf_info.spoofchk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vport++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
u32 new_trusted = enable ? 1 : 0;
|
||||
bool en_bc_pmc;
|
||||
int ret;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
if (vport->vf_info.trusted == new_trusted)
|
||||
return 0;
|
||||
|
||||
/* Disable promisc mode for VF if it is not trusted any more. */
|
||||
if (!enable && vport->vf_info.promisc_enable) {
|
||||
en_bc_pmc = hdev->pdev->revision != 0x20;
|
||||
ret = hclge_set_vport_promisc_mode(vport, false, false,
|
||||
en_bc_pmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
vport->vf_info.promisc_enable = 0;
|
||||
hclge_inform_vf_promisc_info(vport);
|
||||
}
|
||||
|
||||
vport->vf_info.trusted = new_trusted;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hclge_reset_vf_rate(struct hclge_dev *hdev)
|
||||
{
|
||||
int ret;
|
||||
int vf;
|
||||
|
||||
/* reset vf rate to default value */
|
||||
for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) {
|
||||
struct hclge_vport *vport = &hdev->vport[vf];
|
||||
|
||||
vport->vf_info.max_tx_rate = 0;
|
||||
ret = hclge_tm_qs_shaper_cfg(vport, vport->vf_info.max_tx_rate);
|
||||
if (ret)
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"vf%d failed to reset to default, ret=%d\n",
|
||||
vf - HCLGE_VF_VPORT_START_NUM, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static int hclge_vf_rate_param_check(struct hclge_dev *hdev, int vf,
|
||||
int min_tx_rate, int max_tx_rate)
|
||||
{
|
||||
if (min_tx_rate != 0 ||
|
||||
max_tx_rate < 0 || max_tx_rate > hdev->hw.mac.max_speed) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"min_tx_rate:%d [0], max_tx_rate:%d [0, %u]\n",
|
||||
min_tx_rate, max_tx_rate, hdev->hw.mac.max_speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hclge_set_vf_rate(struct hnae3_handle *handle, int vf,
|
||||
int min_tx_rate, int max_tx_rate, bool force)
|
||||
{
|
||||
struct hclge_vport *vport = hclge_get_vport(handle);
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
int ret;
|
||||
|
||||
ret = hclge_vf_rate_param_check(hdev, vf, min_tx_rate, max_tx_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
if (!force && max_tx_rate == vport->vf_info.max_tx_rate)
|
||||
return 0;
|
||||
|
||||
ret = hclge_tm_qs_shaper_cfg(vport, max_tx_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vport->vf_info.max_tx_rate = max_tx_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hclge_resume_vf_rate(struct hclge_dev *hdev)
|
||||
{
|
||||
struct hnae3_handle *handle = &hdev->vport->nic;
|
||||
struct hclge_vport *vport;
|
||||
int ret;
|
||||
int vf;
|
||||
|
||||
/* resume the vf max_tx_rate after reset */
|
||||
for (vf = 0; vf < pci_num_vf(hdev->pdev); vf++) {
|
||||
vport = hclge_get_vf_vport(hdev, vf);
|
||||
if (!vport)
|
||||
return -EINVAL;
|
||||
|
||||
/* zero means max rate, after reset, firmware already set it to
|
||||
* max rate, so just continue.
|
||||
*/
|
||||
if (!vport->vf_info.max_tx_rate)
|
||||
continue;
|
||||
|
||||
ret = hclge_set_vf_rate(handle, vf, 0,
|
||||
vport->vf_info.max_tx_rate, true);
|
||||
if (ret) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"vf%d failed to resume tx_rate:%u, ret=%d\n",
|
||||
vf, vport->vf_info.max_tx_rate, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hclge_reset_vport_state(struct hclge_dev *hdev)
|
||||
{
|
||||
struct hclge_vport *vport = hdev->vport;
|
||||
|
@ -9418,6 +9804,13 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
|
|||
}
|
||||
|
||||
hclge_reset_vport_state(hdev);
|
||||
ret = hclge_reset_vport_spoofchk(hdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hclge_resume_vf_rate(hdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
|
||||
HCLGE_DRIVER_NAME);
|
||||
|
@ -9430,6 +9823,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
|
|||
struct hclge_dev *hdev = ae_dev->priv;
|
||||
struct hclge_mac *mac = &hdev->hw.mac;
|
||||
|
||||
hclge_reset_vf_rate(hdev);
|
||||
hclge_misc_affinity_teardown(hdev);
|
||||
hclge_state_uninit(hdev);
|
||||
|
||||
|
@ -10152,6 +10546,12 @@ static const struct hnae3_ae_ops hclge_ops = {
|
|||
.mac_connect_phy = hclge_mac_connect_phy,
|
||||
.mac_disconnect_phy = hclge_mac_disconnect_phy,
|
||||
.restore_vlan_table = hclge_restore_vlan_table,
|
||||
.get_vf_config = hclge_get_vf_config,
|
||||
.set_vf_link_state = hclge_set_vf_link_state,
|
||||
.set_vf_spoofchk = hclge_set_vf_spoofchk,
|
||||
.set_vf_trust = hclge_set_vf_trust,
|
||||
.set_vf_rate = hclge_set_vf_rate,
|
||||
.set_vf_mac = hclge_set_vf_mac,
|
||||
};
|
||||
|
||||
static struct hnae3_ae_algo ae_algo = {
|
||||
|
|
|
@ -258,6 +258,7 @@ struct hclge_mac {
|
|||
u8 support_autoneg;
|
||||
u8 speed_type; /* 0: sfp speed, 1: active speed */
|
||||
u32 speed;
|
||||
u32 max_speed;
|
||||
u32 speed_ability; /* speed ability supported by current media */
|
||||
u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */
|
||||
u32 fec_mode; /* active fec mode */
|
||||
|
@ -885,6 +886,15 @@ struct hclge_port_base_vlan_config {
|
|||
struct hclge_vlan_info vlan_info;
|
||||
};
|
||||
|
||||
struct hclge_vf_info {
|
||||
int link_state;
|
||||
u8 mac[ETH_ALEN];
|
||||
u32 spoofchk;
|
||||
u32 max_tx_rate;
|
||||
u32 trusted;
|
||||
u16 promisc_enable;
|
||||
};
|
||||
|
||||
struct hclge_vport {
|
||||
u16 alloc_tqps; /* Allocated Tx/Rx queues */
|
||||
|
||||
|
@ -916,15 +926,15 @@ struct hclge_vport {
|
|||
unsigned long state;
|
||||
unsigned long last_active_jiffies;
|
||||
u32 mps; /* Max packet size */
|
||||
struct hclge_vf_info vf_info;
|
||||
|
||||
struct list_head uc_mac_list; /* Store VF unicast table */
|
||||
struct list_head mc_mac_list; /* Store VF multicast table */
|
||||
struct list_head vlan_list; /* Store VF vlan table */
|
||||
};
|
||||
|
||||
void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
|
||||
bool en_mc, bool en_bc, int vport_id);
|
||||
|
||||
int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc,
|
||||
bool en_mc_pmc, bool en_bc_pmc);
|
||||
int hclge_add_uc_addr_common(struct hclge_vport *vport,
|
||||
const unsigned char *addr);
|
||||
int hclge_rm_uc_addr_common(struct hclge_vport *vport,
|
||||
|
@ -993,4 +1003,5 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
|
|||
struct hclge_desc *desc);
|
||||
void hclge_report_hw_error(struct hclge_dev *hdev,
|
||||
enum hnae3_hw_error_type type);
|
||||
void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
|
||||
#endif
|
||||
|
|
|
@ -205,12 +205,38 @@ static int hclge_map_unmap_ring_to_vf_vector(struct hclge_vport *vport, bool en,
|
|||
static int hclge_set_vf_promisc_mode(struct hclge_vport *vport,
|
||||
struct hclge_mbx_vf_to_pf_cmd *req)
|
||||
{
|
||||
bool en_bc = req->msg[1] ? true : false;
|
||||
struct hclge_promisc_param param;
|
||||
#define HCLGE_MBX_BC_INDEX 1
|
||||
#define HCLGE_MBX_UC_INDEX 2
|
||||
#define HCLGE_MBX_MC_INDEX 3
|
||||
|
||||
/* vf is not allowed to enable unicast/multicast broadcast */
|
||||
hclge_promisc_param_init(¶m, false, false, en_bc, vport->vport_id);
|
||||
return hclge_cmd_set_promisc_mode(vport->back, ¶m);
|
||||
bool en_bc = req->msg[HCLGE_MBX_BC_INDEX] ? true : false;
|
||||
bool en_uc = req->msg[HCLGE_MBX_UC_INDEX] ? true : false;
|
||||
bool en_mc = req->msg[HCLGE_MBX_MC_INDEX] ? true : false;
|
||||
int ret;
|
||||
|
||||
if (!vport->vf_info.trusted) {
|
||||
en_uc = false;
|
||||
en_mc = false;
|
||||
}
|
||||
|
||||
ret = hclge_set_vport_promisc_mode(vport, en_uc, en_mc, en_bc);
|
||||
if (req->mbx_need_resp)
|
||||
hclge_gen_resp_to_vf(vport, req, ret, NULL, 0);
|
||||
|
||||
vport->vf_info.promisc_enable = (en_uc || en_mc) ? 1 : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hclge_inform_vf_promisc_info(struct hclge_vport *vport)
|
||||
{
|
||||
u8 dest_vfid = (u8)vport->vport_id;
|
||||
u8 msg_data[2];
|
||||
|
||||
memcpy(&msg_data[0], &vport->vf_info.promisc_enable, sizeof(u16));
|
||||
|
||||
hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
|
||||
HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid);
|
||||
}
|
||||
|
||||
static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
|
||||
|
@ -223,6 +249,20 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
|
|||
if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_UC_MODIFY) {
|
||||
const u8 *old_addr = (const u8 *)(&mbx_req->msg[8]);
|
||||
|
||||
/* If VF MAC has been configured by the host then it
|
||||
* cannot be overridden by the MAC specified by the VM.
|
||||
*/
|
||||
if (!is_zero_ether_addr(vport->vf_info.mac) &&
|
||||
!ether_addr_equal(mac_addr, vport->vf_info.mac)) {
|
||||
status = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!is_valid_ether_addr(mac_addr)) {
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hclge_rm_uc_addr_common(vport, old_addr);
|
||||
status = hclge_add_uc_addr_common(vport, mac_addr);
|
||||
if (status) {
|
||||
|
@ -250,6 +290,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
if (mbx_req->mbx_need_resp & HCLGE_MBX_NEED_RESP_BIT)
|
||||
hclge_gen_resp_to_vf(vport, mbx_req, status, NULL, 0);
|
||||
|
||||
|
@ -324,6 +365,9 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
|
|||
proto = msg_cmd->proto;
|
||||
status = hclge_set_vlan_filter(handle, cpu_to_be16(proto),
|
||||
vlan, is_kill);
|
||||
if (mbx_req->mbx_need_resp)
|
||||
return hclge_gen_resp_to_vf(vport, mbx_req, status,
|
||||
NULL, 0);
|
||||
} else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
|
||||
struct hnae3_handle *handle = &vport->nic;
|
||||
bool en = msg_cmd->is_kill ? true : false;
|
||||
|
@ -398,6 +442,13 @@ static int hclge_get_vf_queue_info(struct hclge_vport *vport,
|
|||
HCLGE_TQPS_RSS_INFO_LEN);
|
||||
}
|
||||
|
||||
static int hclge_get_vf_mac_addr(struct hclge_vport *vport,
|
||||
struct hclge_mbx_vf_to_pf_cmd *mbx_req)
|
||||
{
|
||||
return hclge_gen_resp_to_vf(vport, mbx_req, 0, vport->vf_info.mac,
|
||||
ETH_ALEN);
|
||||
}
|
||||
|
||||
static int hclge_get_vf_queue_depth(struct hclge_vport *vport,
|
||||
struct hclge_mbx_vf_to_pf_cmd *mbx_req,
|
||||
bool gen_resp)
|
||||
|
@ -428,6 +479,9 @@ static int hclge_get_vf_media_type(struct hclge_vport *vport,
|
|||
static int hclge_get_link_info(struct hclge_vport *vport,
|
||||
struct hclge_mbx_vf_to_pf_cmd *mbx_req)
|
||||
{
|
||||
#define HCLGE_VF_LINK_STATE_UP 1U
|
||||
#define HCLGE_VF_LINK_STATE_DOWN 0U
|
||||
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
u16 link_status;
|
||||
u8 msg_data[8];
|
||||
|
@ -435,7 +489,19 @@ static int hclge_get_link_info(struct hclge_vport *vport,
|
|||
u16 duplex;
|
||||
|
||||
/* mac.link can only be 0 or 1 */
|
||||
link_status = (u16)hdev->hw.mac.link;
|
||||
switch (vport->vf_info.link_state) {
|
||||
case IFLA_VF_LINK_STATE_ENABLE:
|
||||
link_status = HCLGE_VF_LINK_STATE_UP;
|
||||
break;
|
||||
case IFLA_VF_LINK_STATE_DISABLE:
|
||||
link_status = HCLGE_VF_LINK_STATE_DOWN;
|
||||
break;
|
||||
case IFLA_VF_LINK_STATE_AUTO:
|
||||
default:
|
||||
link_status = (u16)hdev->hw.mac.link;
|
||||
break;
|
||||
}
|
||||
|
||||
duplex = hdev->hw.mac.duplex;
|
||||
memcpy(&msg_data[0], &link_status, sizeof(u16));
|
||||
memcpy(&msg_data[2], &hdev->hw.mac.speed, sizeof(u32));
|
||||
|
@ -749,6 +815,13 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
|
|||
case HCLGE_MBX_PUSH_LINK_STATUS:
|
||||
hclge_handle_link_change_event(hdev, req);
|
||||
break;
|
||||
case HCLGE_MBX_GET_MAC_ADDR:
|
||||
ret = hclge_get_vf_mac_addr(vport, req);
|
||||
if (ret)
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"PF failed(%d) to get MAC for VF\n",
|
||||
ret);
|
||||
break;
|
||||
case HCLGE_MBX_NCSI_ERROR:
|
||||
hclge_handle_ncsi_error(hdev);
|
||||
break;
|
||||
|
|
|
@ -511,6 +511,49 @@ static int hclge_tm_qs_bp_cfg(struct hclge_dev *hdev, u8 tc, u8 grp_id,
|
|||
return hclge_cmd_send(&hdev->hw, &desc, 1);
|
||||
}
|
||||
|
||||
int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate)
|
||||
{
|
||||
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
|
||||
struct hclge_qs_shapping_cmd *shap_cfg_cmd;
|
||||
struct hclge_dev *hdev = vport->back;
|
||||
struct hclge_desc desc;
|
||||
u8 ir_b, ir_u, ir_s;
|
||||
u32 shaper_para;
|
||||
int ret, i;
|
||||
|
||||
if (!max_tx_rate)
|
||||
max_tx_rate = HCLGE_ETHER_MAX_RATE;
|
||||
|
||||
ret = hclge_shaper_para_calc(max_tx_rate, HCLGE_SHAPER_LVL_QSET,
|
||||
&ir_b, &ir_u, &ir_s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s,
|
||||
HCLGE_SHAPER_BS_U_DEF,
|
||||
HCLGE_SHAPER_BS_S_DEF);
|
||||
|
||||
for (i = 0; i < kinfo->num_tc; i++) {
|
||||
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG,
|
||||
false);
|
||||
|
||||
shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
|
||||
shap_cfg_cmd->qs_id = cpu_to_le16(vport->qs_offset + i);
|
||||
shap_cfg_cmd->qs_shapping_para = cpu_to_le32(shaper_para);
|
||||
|
||||
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
|
||||
if (ret) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"vf%d, qs%u failed to set tx_rate:%d, ret=%d\n",
|
||||
vport->vport_id, shap_cfg_cmd->qs_id,
|
||||
max_tx_rate, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport)
|
||||
{
|
||||
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
|
||||
|
|
|
@ -96,6 +96,12 @@ struct hclge_pg_shapping_cmd {
|
|||
__le32 pg_shapping_para;
|
||||
};
|
||||
|
||||
struct hclge_qs_shapping_cmd {
|
||||
__le16 qs_id;
|
||||
u8 rsvd[2];
|
||||
__le32 qs_shapping_para;
|
||||
};
|
||||
|
||||
#define HCLGE_BP_GRP_NUM 32
|
||||
#define HCLGE_BP_SUB_GRP_ID_S 0
|
||||
#define HCLGE_BP_SUB_GRP_ID_M GENMASK(4, 0)
|
||||
|
@ -154,4 +160,6 @@ int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
|
|||
int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr);
|
||||
int hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats);
|
||||
int hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats);
|
||||
int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1105,6 +1105,7 @@ static int hclgevf_put_vector(struct hnae3_handle *handle, int vector)
|
|||
}
|
||||
|
||||
static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
|
||||
bool en_uc_pmc, bool en_mc_pmc,
|
||||
bool en_bc_pmc)
|
||||
{
|
||||
struct hclge_mbx_vf_to_pf_cmd *req;
|
||||
|
@ -1112,10 +1113,11 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
|
|||
int ret;
|
||||
|
||||
req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data;
|
||||
|
||||
hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_VF_TO_PF, false);
|
||||
req->msg[0] = HCLGE_MBX_SET_PROMISC_MODE;
|
||||
req->msg[1] = en_bc_pmc ? 1 : 0;
|
||||
req->msg[2] = en_uc_pmc ? 1 : 0;
|
||||
req->msg[3] = en_mc_pmc ? 1 : 0;
|
||||
|
||||
ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
|
||||
if (ret)
|
||||
|
@ -1125,9 +1127,17 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int hclgevf_set_promisc_mode(struct hclgevf_dev *hdev, bool en_bc_pmc)
|
||||
static int hclgevf_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
|
||||
bool en_mc_pmc)
|
||||
{
|
||||
return hclgevf_cmd_set_promisc_mode(hdev, en_bc_pmc);
|
||||
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
|
||||
struct pci_dev *pdev = hdev->pdev;
|
||||
bool en_bc_pmc;
|
||||
|
||||
en_bc_pmc = pdev->revision != 0x20;
|
||||
|
||||
return hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc,
|
||||
en_bc_pmc);
|
||||
}
|
||||
|
||||
static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, unsigned int tqp_id,
|
||||
|
@ -1166,11 +1176,37 @@ static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle)
|
|||
}
|
||||
}
|
||||
|
||||
static int hclgevf_get_host_mac_addr(struct hclgevf_dev *hdev, u8 *p)
|
||||
{
|
||||
u8 host_mac[ETH_ALEN];
|
||||
int status;
|
||||
|
||||
status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_MAC_ADDR, 0, NULL, 0,
|
||||
true, host_mac, ETH_ALEN);
|
||||
if (status) {
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"fail to get VF MAC from host %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
ether_addr_copy(p, host_mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p)
|
||||
{
|
||||
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
|
||||
u8 host_mac_addr[ETH_ALEN];
|
||||
|
||||
ether_addr_copy(p, hdev->hw.mac.mac_addr);
|
||||
if (hclgevf_get_host_mac_addr(hdev, host_mac_addr))
|
||||
return;
|
||||
|
||||
hdev->has_pf_mac = !is_zero_ether_addr(host_mac_addr);
|
||||
if (hdev->has_pf_mac)
|
||||
ether_addr_copy(p, host_mac_addr);
|
||||
else
|
||||
ether_addr_copy(p, hdev->hw.mac.mac_addr);
|
||||
}
|
||||
|
||||
static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p,
|
||||
|
@ -1267,7 +1303,7 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle,
|
|||
memcpy(&msg_data[3], &proto, sizeof(proto));
|
||||
ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
|
||||
HCLGE_MBX_VLAN_FILTER, msg_data,
|
||||
HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0);
|
||||
HCLGEVF_VLAN_MBX_MSG_LEN, true, NULL, 0);
|
||||
|
||||
/* when remove hw vlan filter failed, record the vlan id,
|
||||
* and try to remove it from hw later, to be consistence
|
||||
|
@ -2626,12 +2662,6 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (pdev->revision >= 0x21) {
|
||||
ret = hclgevf_set_promisc_mode(hdev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&hdev->pdev->dev, "Reset done\n");
|
||||
|
||||
return 0;
|
||||
|
@ -2706,17 +2736,6 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
|
|||
if (ret)
|
||||
goto err_config;
|
||||
|
||||
/* vf is not allowed to enable unicast/multicast promisc mode.
|
||||
* For revision 0x20, default to disable broadcast promisc mode,
|
||||
* firmware makes sure broadcast packets can be accepted.
|
||||
* For revision 0x21, default to enable broadcast promisc mode.
|
||||
*/
|
||||
if (pdev->revision >= 0x21) {
|
||||
ret = hclgevf_set_promisc_mode(hdev, true);
|
||||
if (ret)
|
||||
goto err_config;
|
||||
}
|
||||
|
||||
/* Initialize RSS for this VF */
|
||||
ret = hclgevf_rss_init_hw(hdev);
|
||||
if (ret) {
|
||||
|
@ -3130,6 +3149,7 @@ static const struct hnae3_ae_ops hclgevf_ops = {
|
|||
.get_global_queue_id = hclgevf_get_qid_global,
|
||||
.set_timer_task = hclgevf_set_timer_task,
|
||||
.get_link_mode = hclgevf_get_link_mode,
|
||||
.set_promisc_mode = hclgevf_set_promisc_mode,
|
||||
};
|
||||
|
||||
static struct hnae3_ae_algo ae_algovf = {
|
||||
|
|
|
@ -266,6 +266,7 @@ struct hclgevf_dev {
|
|||
u16 num_tx_desc; /* desc num of per tx queue */
|
||||
u16 num_rx_desc; /* desc num of per rx queue */
|
||||
u8 hw_tc_map;
|
||||
u8 has_pf_mac;
|
||||
|
||||
u16 num_msi;
|
||||
u16 num_msi_left;
|
||||
|
|
|
@ -205,6 +205,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
|
|||
case HCLGE_MBX_ASSERTING_RESET:
|
||||
case HCLGE_MBX_LINK_STAT_MODE:
|
||||
case HCLGE_MBX_PUSH_VLAN_INFO:
|
||||
case HCLGE_MBX_PUSH_PROMISC_INFO:
|
||||
/* set this mbx event as pending. This is required as we
|
||||
* might loose interrupt event when mbx task is busy
|
||||
* handling. This shall be cleared when mbx task just
|
||||
|
@ -248,6 +249,14 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev)
|
|||
crq->next_to_use);
|
||||
}
|
||||
|
||||
static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev,
|
||||
u16 promisc_info)
|
||||
{
|
||||
if (!promisc_info)
|
||||
dev_info(&hdev->pdev->dev,
|
||||
"Promisc mode is closed by host for being untrusted.\n");
|
||||
}
|
||||
|
||||
void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
|
||||
{
|
||||
enum hnae3_reset_type reset_type;
|
||||
|
@ -313,6 +322,9 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev)
|
|||
hclgevf_update_port_base_vlan_info(hdev, state,
|
||||
(u8 *)vlan_info, 8);
|
||||
break;
|
||||
case HCLGE_MBX_PUSH_PROMISC_INFO:
|
||||
hclgevf_parse_promisc_info(hdev, msg_q[1]);
|
||||
break;
|
||||
default:
|
||||
dev_err(&hdev->pdev->dev,
|
||||
"fetched unsupported(%d) message from arq\n",
|
||||
|
|
Loading…
Reference in New Issue