Commit aa2e259b authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller

net: thunderx: Support for HW VLAN stripping

This patch configures HW to strip 802.1Q header if found in a
receiving packet. The stripped VLAN ID and TCI information is
passed on to software via CQE_RX. Also sets netdev's 'vlan_features'
so that other HW offload features can be used for tagged packets.

This offload feature can be enabled or disabled via ethtool.

Network stack normally ignores RPS for 802.1Q packets and hence low
throughput. With this offload enabled throughput for tagged packets
will be almost same as normal packets.

Note: This patch doesn't enable HW VLAN insertion for transmit packets.
Signed-off-by: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarAleksey Makarov <aleksey.makarov@caviumnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 38bb5d4f
...@@ -329,6 +329,10 @@ static void nic_init_hw(struct nicpf *nic) ...@@ -329,6 +329,10 @@ static void nic_init_hw(struct nicpf *nic)
/* Timer config */ /* Timer config */
nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
/* Enable VLAN ethertype matching and stripping */
nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
(2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q);
} }
/* Channel parse index configuration */ /* Channel parse index configuration */
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/log2.h> #include <linux/log2.h>
...@@ -491,6 +492,11 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, ...@@ -491,6 +492,11 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
/* Check for stripped VLAN */
if (cqe_rx->vlan_found && cqe_rx->vlan_stripped)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
ntohs((__force __be16)cqe_rx->vlan_tci));
if (napi && (netdev->features & NETIF_F_GRO)) if (napi && (netdev->features & NETIF_F_GRO))
napi_gro_receive(napi, skb); napi_gro_receive(napi, skb);
else else
...@@ -1220,6 +1226,18 @@ static void nicvf_reset_task(struct work_struct *work) ...@@ -1220,6 +1226,18 @@ static void nicvf_reset_task(struct work_struct *work)
nic->netdev->trans_start = jiffies; nic->netdev->trans_start = jiffies;
} }
static int nicvf_set_features(struct net_device *netdev,
netdev_features_t features)
{
struct nicvf *nic = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features;
if (changed & NETIF_F_HW_VLAN_CTAG_RX)
nicvf_config_vlan_stripping(nic, features);
return 0;
}
static const struct net_device_ops nicvf_netdev_ops = { static const struct net_device_ops nicvf_netdev_ops = {
.ndo_open = nicvf_open, .ndo_open = nicvf_open,
.ndo_stop = nicvf_stop, .ndo_stop = nicvf_stop,
...@@ -1228,6 +1246,7 @@ static const struct net_device_ops nicvf_netdev_ops = { ...@@ -1228,6 +1246,7 @@ static const struct net_device_ops nicvf_netdev_ops = {
.ndo_set_mac_address = nicvf_set_mac_address, .ndo_set_mac_address = nicvf_set_mac_address,
.ndo_get_stats64 = nicvf_get_stats64, .ndo_get_stats64 = nicvf_get_stats64,
.ndo_tx_timeout = nicvf_tx_timeout, .ndo_tx_timeout = nicvf_tx_timeout,
.ndo_set_features = nicvf_set_features,
}; };
static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...@@ -1301,10 +1320,13 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1301,10 +1320,13 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) if (err)
goto err_free_netdev; goto err_free_netdev;
netdev->features |= (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | netdev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_TSO | NETIF_F_GRO | NETIF_F_RXHASH); NETIF_F_TSO | NETIF_F_GRO |
NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXHASH);
netdev->features |= netdev->hw_features;
netdev->hw_features = netdev->features; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
netdev->netdev_ops = &nicvf_netdev_ops; netdev->netdev_ops = &nicvf_netdev_ops;
netdev->watchdog_timeo = NICVF_TX_TIMEOUT; netdev->watchdog_timeo = NICVF_TX_TIMEOUT;
......
...@@ -475,6 +475,27 @@ static void nicvf_reclaim_rbdr(struct nicvf *nic, ...@@ -475,6 +475,27 @@ static void nicvf_reclaim_rbdr(struct nicvf *nic,
return; return;
} }
void nicvf_config_vlan_stripping(struct nicvf *nic, netdev_features_t features)
{
u64 rq_cfg;
int sqs;
rq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_RQ_GEN_CFG, 0);
/* Enable first VLAN stripping */
if (features & NETIF_F_HW_VLAN_CTAG_RX)
rq_cfg |= (1ULL << 25);
else
rq_cfg &= ~(1ULL << 25);
nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, rq_cfg);
/* Configure Secondary Qsets, if any */
for (sqs = 0; sqs < nic->sqs_count; sqs++)
if (nic->snicvf[sqs])
nicvf_queue_reg_write(nic->snicvf[sqs],
NIC_QSET_RQ_GEN_CFG, 0, rq_cfg);
}
/* Configures receive queue */ /* Configures receive queue */
static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
int qidx, bool enable) int qidx, bool enable)
...@@ -524,7 +545,9 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, ...@@ -524,7 +545,9 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8); mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
nicvf_send_msg_to_pf(nic, &mbx); nicvf_send_msg_to_pf(nic, &mbx);
nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, qidx, 0x00); nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00);
if (!nic->sqs_mode)
nicvf_config_vlan_stripping(nic, nic->netdev->features);
/* Enable Receive queue */ /* Enable Receive queue */
rq_cfg.ena = 1; rq_cfg.ena = 1;
...@@ -961,9 +984,6 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry, ...@@ -961,9 +984,6 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
/* Offload checksum calculation to HW */ /* Offload checksum calculation to HW */
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->protocol != htons(ETH_P_IP))
return;
hdr->csum_l3 = 1; /* Enable IP csum calculation */ hdr->csum_l3 = 1; /* Enable IP csum calculation */
hdr->l3_offset = skb_network_offset(skb); hdr->l3_offset = skb_network_offset(skb);
hdr->l4_offset = skb_transport_offset(skb); hdr->l4_offset = skb_transport_offset(skb);
......
...@@ -306,6 +306,8 @@ struct queue_set { ...@@ -306,6 +306,8 @@ struct queue_set {
#define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT) #define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT)
void nicvf_config_vlan_stripping(struct nicvf *nic,
netdev_features_t features);
int nicvf_set_qset_resources(struct nicvf *nic); int nicvf_set_qset_resources(struct nicvf *nic);
int nicvf_config_data_transfer(struct nicvf *nic, bool enable); int nicvf_config_data_transfer(struct nicvf *nic, bool enable);
void nicvf_qset_config(struct nicvf *nic, bool enable); void nicvf_qset_config(struct nicvf *nic, bool enable);
......
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