Commit 4a61abb1 authored by Xue Chaojing's avatar Xue Chaojing Committed by David S. Miller

net-next/hinic:add rx checksum offload for HiNIC

In order to improve performance, this patch adds rx checksum offload
for the HiNIC driver. Performance test(Iperf) shows more than 80%
improvement in TCP streams.
Signed-off-by: default avatarXue Chaojing <xuechaojing@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ebda9b46
...@@ -50,6 +50,8 @@ enum hinic_port_cmd { ...@@ -50,6 +50,8 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_GET_LINK_STATE = 24, HINIC_PORT_CMD_GET_LINK_STATE = 24,
HINIC_PORT_CMD_SET_RX_CSUM = 26,
HINIC_PORT_CMD_SET_PORT_STATE = 41, HINIC_PORT_CMD_SET_PORT_STATE = 41,
HINIC_PORT_CMD_FWCTXT_INIT = 69, HINIC_PORT_CMD_FWCTXT_INIT = 69,
......
...@@ -170,6 +170,10 @@ ...@@ -170,6 +170,10 @@
#define HINIC_RQ_CQE_STATUS_RXDONE_MASK 0x1 #define HINIC_RQ_CQE_STATUS_RXDONE_MASK 0x1
#define HINIC_RQ_CQE_STATUS_CSUM_ERR_SHIFT 0
#define HINIC_RQ_CQE_STATUS_CSUM_ERR_MASK 0xFFFFU
#define HINIC_RQ_CQE_STATUS_GET(val, member) \ #define HINIC_RQ_CQE_STATUS_GET(val, member) \
(((val) >> HINIC_RQ_CQE_STATUS_##member##_SHIFT) & \ (((val) >> HINIC_RQ_CQE_STATUS_##member##_SHIFT) & \
HINIC_RQ_CQE_STATUS_##member##_MASK) HINIC_RQ_CQE_STATUS_##member##_MASK)
......
...@@ -806,7 +806,8 @@ static const struct net_device_ops hinic_netdev_ops = { ...@@ -806,7 +806,8 @@ static const struct net_device_ops hinic_netdev_ops = {
static void netdev_features_init(struct net_device *netdev) static void netdev_features_init(struct net_device *netdev)
{ {
netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | 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_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_RXCSUM;
netdev->vlan_features = netdev->hw_features; netdev->vlan_features = netdev->hw_features;
...@@ -869,12 +870,16 @@ static int set_features(struct hinic_dev *nic_dev, ...@@ -869,12 +870,16 @@ static int set_features(struct hinic_dev *nic_dev,
netdev_features_t features, bool force_change) netdev_features_t features, bool force_change)
{ {
netdev_features_t changed = force_change ? ~0 : pre_features ^ features; netdev_features_t changed = force_change ? ~0 : pre_features ^ features;
u32 csum_en = HINIC_RX_CSUM_OFFLOAD_EN;
int err = 0; int err = 0;
if (changed & NETIF_F_TSO) if (changed & NETIF_F_TSO)
err = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ? err = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ?
HINIC_TSO_ENABLE : HINIC_TSO_DISABLE); HINIC_TSO_ENABLE : HINIC_TSO_DISABLE);
if (changed & NETIF_F_RXCSUM)
err = hinic_set_rx_csum_offload(nic_dev, csum_en);
return err; return err;
} }
......
...@@ -409,3 +409,31 @@ int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state) ...@@ -409,3 +409,31 @@ int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state)
return 0; return 0;
} }
int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en)
{
struct hinic_checksum_offload rx_csum_cfg = {0};
struct hinic_hwdev *hwdev = nic_dev->hwdev;
struct hinic_hwif *hwif = hwdev->hwif;
struct pci_dev *pdev = hwif->pdev;
u16 out_size;
int err;
if (!hwdev)
return -EINVAL;
rx_csum_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
rx_csum_cfg.rx_csum_offload = en;
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_CSUM,
&rx_csum_cfg, sizeof(rx_csum_cfg),
&rx_csum_cfg, &out_size);
if (err || !out_size || rx_csum_cfg.status) {
dev_err(&pdev->dev,
"Failed to set rx csum offload, ret = %d\n",
rx_csum_cfg.status);
return -EINVAL;
}
return 0;
}
...@@ -183,6 +183,15 @@ struct hinic_tso_config { ...@@ -183,6 +183,15 @@ struct hinic_tso_config {
u8 resv2[3]; u8 resv2[3];
}; };
struct hinic_checksum_offload {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u16 rsvd1;
u32 rx_csum_offload;
};
int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr, int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id); u16 vlan_id);
...@@ -213,4 +222,5 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev, ...@@ -213,4 +222,5 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state); int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state);
int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en);
#endif #endif
...@@ -89,6 +89,28 @@ static void rxq_stats_init(struct hinic_rxq *rxq) ...@@ -89,6 +89,28 @@ static void rxq_stats_init(struct hinic_rxq *rxq)
hinic_rxq_clean_stats(rxq); hinic_rxq_clean_stats(rxq);
} }
static void rx_csum(struct hinic_rxq *rxq, u16 cons_idx,
struct sk_buff *skb)
{
struct net_device *netdev = rxq->netdev;
struct hinic_rq_cqe *cqe;
struct hinic_rq *rq;
u32 csum_err;
u32 status;
rq = rxq->rq;
cqe = rq->cqe[cons_idx];
status = be32_to_cpu(cqe->status);
csum_err = HINIC_RQ_CQE_STATUS_GET(status, CSUM_ERR);
if (!(netdev->features & NETIF_F_RXCSUM))
return;
if (!csum_err)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
}
/** /**
* rx_alloc_skb - allocate skb and map it to dma address * rx_alloc_skb - allocate skb and map it to dma address
* @rxq: rx queue * @rxq: rx queue
...@@ -328,6 +350,8 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget) ...@@ -328,6 +350,8 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
rx_unmap_skb(rxq, hinic_sge_to_dma(&sge)); rx_unmap_skb(rxq, hinic_sge_to_dma(&sge));
rx_csum(rxq, ci, skb);
prefetch(skb->data); prefetch(skb->data);
pkt_len = sge.len; pkt_len = sge.len;
......
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
#include "hinic_hw_qp.h" #include "hinic_hw_qp.h"
#define HINIC_RX_CSUM_OFFLOAD_EN 0xFFF
#define HINIC_RX_CSUM_HW_CHECK_NONE BIT(7)
#define HINIC_RX_CSUM_IPSU_OTHER_ERR BIT(8)
struct hinic_rxq_stats { struct hinic_rxq_stats {
u64 pkts; u64 pkts;
u64 bytes; u64 bytes;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment