Commit 2b3d7b75 authored by Shahed Shaikh's avatar Shahed Shaikh Committed by David S. Miller

qlcnic: Add VXLAN Rx offload support

This patch adds Rx checksum offload support for VXLAN.
Implements .ndo_{add|del}_vxlan_port netdev ops.
Adapter supports only one VXLAN port, so program adapter with
very first UDP port which VXLAN driver is listening to.
Signed-off-by: default avatarShahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 381709de
...@@ -535,6 +535,7 @@ struct qlcnic_hardware_context { ...@@ -535,6 +535,7 @@ struct qlcnic_hardware_context {
u8 extend_lb_time; u8 extend_lb_time;
u8 phys_port_id[ETH_ALEN]; u8 phys_port_id[ETH_ALEN];
u8 lb_mode; u8 lb_mode;
u16 vxlan_port;
}; };
struct qlcnic_adapter_stats { struct qlcnic_adapter_stats {
...@@ -551,6 +552,7 @@ struct qlcnic_adapter_stats { ...@@ -551,6 +552,7 @@ struct qlcnic_adapter_stats {
u64 lso_frames; u64 lso_frames;
u64 encap_lso_frames; u64 encap_lso_frames;
u64 encap_tx_csummed; u64 encap_tx_csummed;
u64 encap_rx_csummed;
u64 xmit_on; u64 xmit_on;
u64 xmit_off; u64 xmit_off;
u64 skb_alloc_failure; u64 skb_alloc_failure;
...@@ -912,6 +914,7 @@ struct qlcnic_mac_vlan_list { ...@@ -912,6 +914,7 @@ struct qlcnic_mac_vlan_list {
#define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7 #define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7
#define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9 #define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9
#define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD BIT_0
#define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD BIT_1 #define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD BIT_1
#define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD BIT_4 #define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD BIT_4
...@@ -1008,6 +1011,8 @@ struct qlcnic_ipaddr { ...@@ -1008,6 +1011,8 @@ struct qlcnic_ipaddr {
#define QLCNIC_APP_CHANGED_FLAGS 0x20000 #define QLCNIC_APP_CHANGED_FLAGS 0x20000
#define QLCNIC_HAS_PHYS_PORT_ID 0x40000 #define QLCNIC_HAS_PHYS_PORT_ID 0x40000
#define QLCNIC_TSS_RSS 0x80000 #define QLCNIC_TSS_RSS 0x80000
#define QLCNIC_ADD_VXLAN_PORT 0x100000
#define QLCNIC_DEL_VXLAN_PORT 0x200000
#define QLCNIC_IS_MSI_FAMILY(adapter) \ #define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
...@@ -1828,6 +1833,12 @@ static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter) ...@@ -1828,6 +1833,12 @@ static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter)
QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD; QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD;
} }
static inline bool qlcnic_encap_rx_offload(struct qlcnic_adapter *adapter)
{
return adapter->ahw->extra_capability[0] &
QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD;
}
static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter) static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
{ {
return adapter->nic_ops->start_firmware(adapter); return adapter->nic_ops->start_firmware(adapter);
......
...@@ -77,7 +77,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { ...@@ -77,7 +77,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_GET_PORT_CONFIG, 2, 2}, {QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
{QLCNIC_CMD_GET_LINK_STATUS, 2, 4}, {QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
{QLCNIC_CMD_IDC_ACK, 5, 1}, {QLCNIC_CMD_IDC_ACK, 5, 1},
{QLCNIC_CMD_INIT_NIC_FUNC, 2, 1}, {QLCNIC_CMD_INIT_NIC_FUNC, 3, 1},
{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1}, {QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
{QLCNIC_CMD_SET_LED_CONFIG, 5, 1}, {QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
{QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
...@@ -87,6 +87,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { ...@@ -87,6 +87,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},
{QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50}, {QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50},
{QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1},
}; };
const u32 qlcnic_83xx_ext_reg_tbl[] = { const u32 qlcnic_83xx_ext_reg_tbl[] = {
......
...@@ -528,8 +528,9 @@ enum qlc_83xx_ext_regs { ...@@ -528,8 +528,9 @@ enum qlc_83xx_ext_regs {
}; };
/* Initialize/Stop NIC command bit definitions */ /* Initialize/Stop NIC command bit definitions */
#define QLC_REGISTER_DCB_AEN BIT_1
#define QLC_REGISTER_LB_IDC BIT_0 #define QLC_REGISTER_LB_IDC BIT_0
#define QLC_REGISTER_DCB_AEN BIT_1
#define QLC_83XX_MULTI_TENANCY_INFO BIT_29
#define QLC_INIT_FW_RESOURCES BIT_31 #define QLC_INIT_FW_RESOURCES BIT_31
/* 83xx funcitons */ /* 83xx funcitons */
......
...@@ -1020,10 +1020,97 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter, ...@@ -1020,10 +1020,97 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
return 0; return 0;
} }
#define QLC_83XX_ENCAP_TYPE_VXLAN BIT_1
#define QLC_83XX_MATCH_ENCAP_ID BIT_2
#define QLC_83XX_SET_VXLAN_UDP_DPORT BIT_3
#define QLC_83XX_VXLAN_UDP_DPORT(PORT) ((PORT & 0xffff) << 16)
#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1
#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0
static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter)
{
u16 port = adapter->ahw->vxlan_port;
struct qlcnic_cmd_args cmd;
int ret = 0;
memset(&cmd, 0, sizeof(cmd));
ret = qlcnic_alloc_mbx_args(&cmd, adapter,
QLCNIC_CMD_INIT_NIC_FUNC);
if (ret)
return ret;
cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO;
cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN |
QLC_83XX_SET_VXLAN_UDP_DPORT |
QLC_83XX_VXLAN_UDP_DPORT(port);
ret = qlcnic_issue_cmd(adapter, &cmd);
if (ret)
netdev_err(adapter->netdev,
"Failed to set VXLAN port %d in adapter\n",
port);
qlcnic_free_mbx_args(&cmd);
return ret;
}
static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter,
bool state)
{
u16 vxlan_port = adapter->ahw->vxlan_port;
struct qlcnic_cmd_args cmd;
int ret = 0;
memset(&cmd, 0, sizeof(cmd));
ret = qlcnic_alloc_mbx_args(&cmd, adapter,
QLCNIC_CMD_SET_INGRESS_ENCAP);
if (ret)
return ret;
cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING :
QLCNIC_DISABLE_INGRESS_ENCAP_PARSING;
ret = qlcnic_issue_cmd(adapter, &cmd);
if (ret)
netdev_err(adapter->netdev,
"Failed to %s VXLAN parsing for port %d\n",
state ? "enable" : "disable", vxlan_port);
else
netdev_info(adapter->netdev,
"%s VXLAN parsing for port %d\n",
state ? "Enabled" : "Disabled", vxlan_port);
qlcnic_free_mbx_args(&cmd);
return ret;
}
static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter) static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
{ {
struct qlcnic_hardware_context *ahw = adapter->ahw;
if (adapter->fhash.fnum) if (adapter->fhash.fnum)
qlcnic_prune_lb_filters(adapter); qlcnic_prune_lb_filters(adapter);
if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) {
if (qlcnic_set_vxlan_port(adapter))
return;
if (qlcnic_set_vxlan_parsing(adapter, true))
return;
adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT;
} else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) {
if (qlcnic_set_vxlan_parsing(adapter, false))
return;
ahw->vxlan_port = 0;
adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT;
}
} }
/** /**
......
...@@ -51,6 +51,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { ...@@ -51,6 +51,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
QLC_OFF(stats.encap_lso_frames)}, QLC_OFF(stats.encap_lso_frames)},
{"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed), {"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed),
QLC_OFF(stats.encap_tx_csummed)}, QLC_OFF(stats.encap_tx_csummed)},
{"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed),
QLC_OFF(stats.encap_rx_csummed)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)}, QLC_OFF(stats.skb_alloc_failure)},
{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun), {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
......
...@@ -98,6 +98,7 @@ enum qlcnic_regs { ...@@ -98,6 +98,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_GET_LINK_EVENT 0x48 #define QLCNIC_CMD_GET_LINK_EVENT 0x48
#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE 0x49 #define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE 0x49
#define QLCNIC_CMD_CONFIGURE_HW_LRO 0x4A #define QLCNIC_CMD_CONFIGURE_HW_LRO 0x4A
#define QLCNIC_CMD_SET_INGRESS_ENCAP 0x4E
#define QLCNIC_CMD_INIT_NIC_FUNC 0x60 #define QLCNIC_CMD_INIT_NIC_FUNC 0x60
#define QLCNIC_CMD_STOP_NIC_FUNC 0x61 #define QLCNIC_CMD_STOP_NIC_FUNC 0x61
#define QLCNIC_CMD_IDC_ACK 0x63 #define QLCNIC_CMD_IDC_ACK 0x63
......
...@@ -1703,6 +1703,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt) ...@@ -1703,6 +1703,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0; return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
} }
#define QLCNIC_ENCAP_LENGTH_MASK 0x7f
static inline u8 qlcnic_encap_length(u64 sts_data)
{
return sts_data & QLCNIC_ENCAP_LENGTH_MASK;
}
static struct qlcnic_rx_buffer * static struct qlcnic_rx_buffer *
qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring, struct qlcnic_host_sds_ring *sds_ring,
...@@ -1753,6 +1760,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, ...@@ -1753,6 +1760,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
if (qlcnic_encap_length(sts_data[1]) &&
skb->ip_summed == CHECKSUM_UNNECESSARY) {
skb->encapsulation = 1;
adapter->stats.encap_rx_csummed++;
}
if (vid != 0xffff) if (vid != 0xffff)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <net/vxlan.h>
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -461,6 +462,35 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev, ...@@ -461,6 +462,35 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev,
return 0; return 0;
} }
static void qlcnic_add_vxlan_port(struct net_device *netdev,
sa_family_t sa_family, __be16 port)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
/* Adapter supports only one VXLAN port. Use very first port
* for enabling offload
*/
if (!qlcnic_encap_rx_offload(adapter) || ahw->vxlan_port)
return;
ahw->vxlan_port = ntohs(port);
adapter->flags |= QLCNIC_ADD_VXLAN_PORT;
}
static void qlcnic_del_vxlan_port(struct net_device *netdev,
sa_family_t sa_family, __be16 port)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
if (!qlcnic_encap_rx_offload(adapter) || !ahw->vxlan_port ||
(ahw->vxlan_port != ntohs(port)))
return;
adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
}
static const struct net_device_ops qlcnic_netdev_ops = { static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open, .ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close, .ndo_stop = qlcnic_close,
...@@ -479,6 +509,8 @@ static const struct net_device_ops qlcnic_netdev_ops = { ...@@ -479,6 +509,8 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_fdb_del = qlcnic_fdb_del, .ndo_fdb_del = qlcnic_fdb_del,
.ndo_fdb_dump = qlcnic_fdb_dump, .ndo_fdb_dump = qlcnic_fdb_dump,
.ndo_get_phys_port_id = qlcnic_get_phys_port_id, .ndo_get_phys_port_id = qlcnic_get_phys_port_id,
.ndo_add_vxlan_port = qlcnic_add_vxlan_port,
.ndo_del_vxlan_port = qlcnic_del_vxlan_port,
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller, .ndo_poll_controller = qlcnic_poll_controller,
#endif #endif
...@@ -1943,6 +1975,9 @@ qlcnic_attach(struct qlcnic_adapter *adapter) ...@@ -1943,6 +1975,9 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
qlcnic_create_sysfs_entries(adapter); qlcnic_create_sysfs_entries(adapter);
if (qlcnic_encap_rx_offload(adapter))
vxlan_get_rx_port(netdev);
adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
return 0; return 0;
...@@ -2215,6 +2250,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, ...@@ -2215,6 +2250,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
NETIF_F_TSO6; NETIF_F_TSO6;
} }
if (qlcnic_encap_rx_offload(adapter))
netdev->hw_enc_features |= NETIF_F_RXCSUM;
netdev->hw_features = netdev->features; netdev->hw_features = netdev->features;
netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector; netdev->irq = adapter->msix_entries[0].vector;
......
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