hinic: add vlan offload support
This patch adds vlan offload support for the HINIC driver. Signed-off-by: Xue Chaojing <xuechaojing@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0a7960c792
commit
aebd17b768
|
@ -45,6 +45,8 @@ enum hinic_port_cmd {
|
|||
|
||||
HINIC_PORT_CMD_SET_RX_CSUM = 26,
|
||||
|
||||
HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD = 27,
|
||||
|
||||
HINIC_PORT_CMD_GET_PORT_STATISTICS = 28,
|
||||
|
||||
HINIC_PORT_CMD_CLEAR_PORT_STATISTICS = 29,
|
||||
|
|
|
@ -222,6 +222,8 @@
|
|||
|
||||
#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT 0
|
||||
#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK 0xFFFU
|
||||
#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT 21
|
||||
#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK 0x1U
|
||||
|
||||
#define RQ_CQE_OFFOLAD_TYPE_GET(val, member) (((val) >> \
|
||||
RQ_CQE_OFFOLAD_TYPE_##member##_SHIFT) & \
|
||||
|
@ -230,6 +232,19 @@
|
|||
#define HINIC_GET_RX_PKT_TYPE(offload_type) \
|
||||
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
|
||||
|
||||
#define HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) \
|
||||
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN)
|
||||
|
||||
#define RQ_CQE_SGE_VLAN_MASK 0xFFFFU
|
||||
#define RQ_CQE_SGE_VLAN_SHIFT 0
|
||||
|
||||
#define RQ_CQE_SGE_GET(val, member) (((val) >> \
|
||||
RQ_CQE_SGE_##member##_SHIFT) & \
|
||||
RQ_CQE_SGE_##member##_MASK)
|
||||
|
||||
#define HINIC_GET_RX_VLAN_TAG(vlan_len) \
|
||||
RQ_CQE_SGE_GET(vlan_len, VLAN)
|
||||
|
||||
#define HINIC_RSS_TYPE_VALID_SHIFT 23
|
||||
#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
|
||||
#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT 25
|
||||
|
|
|
@ -836,14 +836,14 @@ static const struct net_device_ops hinic_netdev_ops = {
|
|||
.ndo_get_stats64 = hinic_get_stats64,
|
||||
.ndo_fix_features = hinic_fix_features,
|
||||
.ndo_set_features = hinic_set_features,
|
||||
|
||||
};
|
||||
|
||||
static void netdev_features_init(struct net_device *netdev)
|
||||
{
|
||||
netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
|
||||
NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
|
||||
NETIF_F_RXCSUM | NETIF_F_LRO;
|
||||
NETIF_F_RXCSUM | NETIF_F_LRO |
|
||||
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
|
||||
|
||||
netdev->vlan_features = netdev->hw_features;
|
||||
|
||||
|
@ -923,6 +923,11 @@ static int set_features(struct hinic_dev *nic_dev,
|
|||
HINIC_LRO_MAX_WQE_NUM_DEFAULT);
|
||||
}
|
||||
|
||||
if (changed & NETIF_F_HW_VLAN_CTAG_RX)
|
||||
err = hinic_set_rx_vlan_offload(nic_dev,
|
||||
!!(features &
|
||||
NETIF_F_HW_VLAN_CTAG_RX));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -431,6 +431,36 @@ int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hinic_set_rx_vlan_offload(struct hinic_dev *nic_dev, u8 en)
|
||||
{
|
||||
struct hinic_hwdev *hwdev = nic_dev->hwdev;
|
||||
struct hinic_vlan_cfg vlan_cfg;
|
||||
struct hinic_hwif *hwif;
|
||||
struct pci_dev *pdev;
|
||||
u16 out_size;
|
||||
int err;
|
||||
|
||||
if (!hwdev)
|
||||
return -EINVAL;
|
||||
|
||||
hwif = hwdev->hwif;
|
||||
pdev = hwif->pdev;
|
||||
vlan_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
|
||||
vlan_cfg.vlan_rx_offload = en;
|
||||
|
||||
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD,
|
||||
&vlan_cfg, sizeof(vlan_cfg),
|
||||
&vlan_cfg, &out_size);
|
||||
if (err || !out_size || vlan_cfg.status) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to set rx vlan offload, err: %d, status: 0x%x, out size: 0x%x\n",
|
||||
err, vlan_cfg.status, out_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hinic_set_max_qnum(struct hinic_dev *nic_dev, u8 num_rqs)
|
||||
{
|
||||
struct hinic_hwdev *hwdev = nic_dev->hwdev;
|
||||
|
|
|
@ -223,6 +223,16 @@ struct hinic_lro_timer {
|
|||
u32 timer;
|
||||
};
|
||||
|
||||
struct hinic_vlan_cfg {
|
||||
u8 status;
|
||||
u8 version;
|
||||
u8 rsvd0[6];
|
||||
|
||||
u16 func_id;
|
||||
u8 vlan_rx_offload;
|
||||
u8 rsvd1[5];
|
||||
};
|
||||
|
||||
struct hinic_rss_template_mgmt {
|
||||
u8 status;
|
||||
u8 version;
|
||||
|
@ -558,4 +568,7 @@ int hinic_get_phy_port_stats(struct hinic_dev *nic_dev,
|
|||
|
||||
int hinic_get_vport_stats(struct hinic_dev *nic_dev,
|
||||
struct hinic_vport_stats *stats);
|
||||
|
||||
int hinic_set_rx_vlan_offload(struct hinic_dev *nic_dev, u8 en);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#include "hinic_common.h"
|
||||
|
@ -325,6 +326,7 @@ static int rx_recv_jumbo_pkt(struct hinic_rxq *rxq, struct sk_buff *head_skb,
|
|||
static int rxq_recv(struct hinic_rxq *rxq, int budget)
|
||||
{
|
||||
struct hinic_qp *qp = container_of(rxq->rq, struct hinic_qp, rq);
|
||||
struct net_device *netdev = rxq->netdev;
|
||||
u64 pkt_len = 0, rx_bytes = 0;
|
||||
struct hinic_rq *rq = rxq->rq;
|
||||
struct hinic_rq_wqe *rq_wqe;
|
||||
|
@ -334,8 +336,11 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
|
|||
struct hinic_sge sge;
|
||||
unsigned int status;
|
||||
struct sk_buff *skb;
|
||||
u32 offload_type;
|
||||
u16 ci, num_lro;
|
||||
u16 num_wqe = 0;
|
||||
u32 vlan_len;
|
||||
u16 vid;
|
||||
|
||||
while (pkts < budget) {
|
||||
num_wqes = 0;
|
||||
|
@ -368,6 +373,14 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
|
|||
hinic_rq_put_wqe(rq, ci,
|
||||
(num_wqes + 1) * HINIC_RQ_WQE_SIZE);
|
||||
|
||||
offload_type = be32_to_cpu(cqe->offload_type);
|
||||
vlan_len = be32_to_cpu(cqe->len);
|
||||
if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
|
||||
HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)) {
|
||||
vid = HINIC_GET_RX_VLAN_TAG(vlan_len);
|
||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
|
||||
}
|
||||
|
||||
skb_record_rx_queue(skb, qp->q_id);
|
||||
skb->protocol = eth_type_trans(skb, rxq->netdev);
|
||||
|
||||
|
|
|
@ -407,10 +407,20 @@ static int offload_csum(struct hinic_sq_task *task, u32 *queue_info,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void offload_vlan(struct hinic_sq_task *task, u32 *queue_info,
|
||||
u16 vlan_tag, u16 vlan_pri)
|
||||
{
|
||||
task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(vlan_tag, VLAN_TAG) |
|
||||
HINIC_SQ_TASK_INFO0_SET(1U, VLAN_OFFLOAD);
|
||||
|
||||
*queue_info |= HINIC_SQ_CTRL_SET(vlan_pri, QUEUE_INFO_PRI);
|
||||
}
|
||||
|
||||
static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
|
||||
u32 *queue_info)
|
||||
{
|
||||
enum hinic_offload_type offload = 0;
|
||||
u16 vlan_tag;
|
||||
int enabled;
|
||||
|
||||
enabled = offload_tso(task, queue_info, skb);
|
||||
|
@ -424,6 +434,13 @@ static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
|
|||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
if (unlikely(skb_vlan_tag_present(skb))) {
|
||||
vlan_tag = skb_vlan_tag_get(skb);
|
||||
offload_vlan(task, queue_info, vlan_tag,
|
||||
vlan_tag >> VLAN_PRIO_SHIFT);
|
||||
offload |= TX_OFFLOAD_VLAN;
|
||||
}
|
||||
|
||||
if (offload)
|
||||
hinic_task_set_l2hdr(task, skb_network_offset(skb));
|
||||
|
||||
|
|
Loading…
Reference in New Issue