Browse Source

qed/qede: Add VXLAN tunnel slowpath configuration support

This patch enables VXLAN tunnel on the adapter and
add support for driver hooks to configure UDP ports
for VXLAN tunnel offload to be performed by the adapter.

Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Manish Chopra 9 years ago
parent
commit
b18e170cac

+ 11 - 0
drivers/net/ethernet/qlogic/Kconfig

@@ -103,4 +103,15 @@ config QEDE
 	depends on QED
 	depends on QED
 	---help---
 	---help---
 	  This enables the support for ...
 	  This enables the support for ...
+
+config QEDE_VXLAN
+	bool "Virtual eXtensible Local Area Network support"
+	default n
+	depends on QEDE && VXLAN && !(QEDE=y && VXLAN=m)
+	---help---
+	  This enables hardware offload support for VXLAN protocol over
+	  qede module. Say Y here if you want to enable hardware offload
+	  support for Virtual eXtensible Local Area Network (VXLAN)
+	  in the driver.
+
 endif # NET_VENDOR_QLOGIC
 endif # NET_VENDOR_QLOGIC

+ 7 - 1
drivers/net/ethernet/qlogic/qed/qed_main.c

@@ -744,6 +744,7 @@ static void qed_update_pf_params(struct qed_dev *cdev,
 static int qed_slowpath_start(struct qed_dev *cdev,
 static int qed_slowpath_start(struct qed_dev *cdev,
 			      struct qed_slowpath_params *params)
 			      struct qed_slowpath_params *params)
 {
 {
+	struct qed_tunn_start_params tunn_info;
 	struct qed_mcp_drv_version drv_version;
 	struct qed_mcp_drv_version drv_version;
 	const u8 *data = NULL;
 	const u8 *data = NULL;
 	struct qed_hwfn *hwfn;
 	struct qed_hwfn *hwfn;
@@ -776,7 +777,12 @@ static int qed_slowpath_start(struct qed_dev *cdev,
 	/* Start the slowpath */
 	/* Start the slowpath */
 	data = cdev->firmware->data;
 	data = cdev->firmware->data;
 
 
-	rc = qed_hw_init(cdev, NULL, true, cdev->int_params.out.int_mode,
+	memset(&tunn_info, 0, sizeof(tunn_info));
+	tunn_info.tunn_mode |=  1 << QED_MODE_VXLAN_TUNN;
+	tunn_info.tunn_clss_vxlan = QED_TUNN_CLSS_MAC_VLAN;
+
+	rc = qed_hw_init(cdev, &tunn_info, true,
+			 cdev->int_params.out.int_mode,
 			 true, data);
 			 true, data);
 	if (rc)
 	if (rc)
 		goto err2;
 		goto err2;

+ 2 - 1
drivers/net/ethernet/qlogic/qed/qed_sp_commands.c

@@ -353,7 +353,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
 	DMA_REGPAIR_LE(p_ramrod->consolid_q_pbl_addr,
 	DMA_REGPAIR_LE(p_ramrod->consolid_q_pbl_addr,
 		       p_hwfn->p_consq->chain.pbl.p_phys_table);
 		       p_hwfn->p_consq->chain.pbl.p_phys_table);
 
 
-	qed_tunn_set_pf_start_params(p_hwfn, NULL, NULL);
+	qed_tunn_set_pf_start_params(p_hwfn, p_tunn,
+				     &p_ramrod->tunnel_config);
 	p_hwfn->hw_info.personality = PERSONALITY_ETH;
 	p_hwfn->hw_info.personality = PERSONALITY_ETH;
 
 
 	DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
 	DP_VERBOSE(p_hwfn, QED_MSG_SPQ,

+ 3 - 1
drivers/net/ethernet/qlogic/qede/qede.h

@@ -169,6 +169,7 @@ struct qede_dev {
 	bool accept_any_vlan;
 	bool accept_any_vlan;
 	struct delayed_work		sp_task;
 	struct delayed_work		sp_task;
 	unsigned long			sp_flags;
 	unsigned long			sp_flags;
+	u16				vxlan_dst_port;
 };
 };
 
 
 enum QEDE_STATE {
 enum QEDE_STATE {
@@ -289,7 +290,8 @@ struct qede_fastpath {
 #define QEDE_CSUM_ERROR			BIT(0)
 #define QEDE_CSUM_ERROR			BIT(0)
 #define QEDE_CSUM_UNNECESSARY		BIT(1)
 #define QEDE_CSUM_UNNECESSARY		BIT(1)
 
 
-#define QEDE_SP_RX_MODE		1
+#define QEDE_SP_RX_MODE			1
+#define QEDE_SP_VXLAN_PORT_CONFIG	2
 
 
 union qede_reload_args {
 union qede_reload_args {
 	u16 mtu;
 	u16 mtu;

+ 63 - 1
drivers/net/ethernet/qlogic/qede/qede_main.c

@@ -24,7 +24,9 @@
 #include <linux/netdev_features.h>
 #include <linux/netdev_features.h>
 #include <linux/udp.h>
 #include <linux/udp.h>
 #include <linux/tcp.h>
 #include <linux/tcp.h>
+#ifdef CONFIG_QEDE_VXLAN
 #include <net/vxlan.h>
 #include <net/vxlan.h>
+#endif
 #include <linux/ip.h>
 #include <linux/ip.h>
 #include <net/ipv6.h>
 #include <net/ipv6.h>
 #include <net/tcp.h>
 #include <net/tcp.h>
@@ -1821,6 +1823,42 @@ static void qede_vlan_mark_nonconfigured(struct qede_dev *edev)
 	edev->accept_any_vlan = false;
 	edev->accept_any_vlan = false;
 }
 }
 
 
+#ifdef CONFIG_QEDE_VXLAN
+static void qede_add_vxlan_port(struct net_device *dev,
+				sa_family_t sa_family, __be16 port)
+{
+	struct qede_dev *edev = netdev_priv(dev);
+	u16 t_port = ntohs(port);
+
+	if (edev->vxlan_dst_port)
+		return;
+
+	edev->vxlan_dst_port = t_port;
+
+	DP_VERBOSE(edev, QED_MSG_DEBUG, "Added vxlan port=%d", t_port);
+
+	set_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags);
+	schedule_delayed_work(&edev->sp_task, 0);
+}
+
+static void qede_del_vxlan_port(struct net_device *dev,
+				sa_family_t sa_family, __be16 port)
+{
+	struct qede_dev *edev = netdev_priv(dev);
+	u16 t_port = ntohs(port);
+
+	if (t_port != edev->vxlan_dst_port)
+		return;
+
+	edev->vxlan_dst_port = 0;
+
+	DP_VERBOSE(edev, QED_MSG_DEBUG, "Deleted vxlan port=%d", t_port);
+
+	set_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags);
+	schedule_delayed_work(&edev->sp_task, 0);
+}
+#endif
+
 static const struct net_device_ops qede_netdev_ops = {
 static const struct net_device_ops qede_netdev_ops = {
 	.ndo_open = qede_open,
 	.ndo_open = qede_open,
 	.ndo_stop = qede_close,
 	.ndo_stop = qede_close,
@@ -1832,6 +1870,10 @@ static const struct net_device_ops qede_netdev_ops = {
 	.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
 	.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
 	.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
 	.ndo_get_stats64 = qede_get_stats64,
 	.ndo_get_stats64 = qede_get_stats64,
+#ifdef CONFIG_QEDE_VXLAN
+	.ndo_add_vxlan_port = qede_add_vxlan_port,
+	.ndo_del_vxlan_port = qede_del_vxlan_port,
+#endif
 };
 };
 
 
 /* -------------------------------------------------------------------------
 /* -------------------------------------------------------------------------
@@ -2004,6 +2046,8 @@ static void qede_sp_task(struct work_struct *work)
 {
 {
 	struct qede_dev *edev = container_of(work, struct qede_dev,
 	struct qede_dev *edev = container_of(work, struct qede_dev,
 					     sp_task.work);
 					     sp_task.work);
+	struct qed_dev *cdev = edev->cdev;
+
 	mutex_lock(&edev->qede_lock);
 	mutex_lock(&edev->qede_lock);
 
 
 	if (edev->state == QEDE_STATE_OPEN) {
 	if (edev->state == QEDE_STATE_OPEN) {
@@ -2011,6 +2055,15 @@ static void qede_sp_task(struct work_struct *work)
 			qede_config_rx_mode(edev->ndev);
 			qede_config_rx_mode(edev->ndev);
 	}
 	}
 
 
+	if (test_and_clear_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags)) {
+		struct qed_tunn_params tunn_params;
+
+		memset(&tunn_params, 0, sizeof(tunn_params));
+		tunn_params.update_vxlan_port = 1;
+		tunn_params.vxlan_port = edev->vxlan_dst_port;
+		qed_ops->tunn_config(cdev, &tunn_params);
+	}
+
 	mutex_unlock(&edev->qede_lock);
 	mutex_unlock(&edev->qede_lock);
 }
 }
 
 
@@ -3149,12 +3202,21 @@ void qede_reload(struct qede_dev *edev,
 static int qede_open(struct net_device *ndev)
 static int qede_open(struct net_device *ndev)
 {
 {
 	struct qede_dev *edev = netdev_priv(ndev);
 	struct qede_dev *edev = netdev_priv(ndev);
+	int rc;
 
 
 	netif_carrier_off(ndev);
 	netif_carrier_off(ndev);
 
 
 	edev->ops->common->set_power_state(edev->cdev, PCI_D0);
 	edev->ops->common->set_power_state(edev->cdev, PCI_D0);
 
 
-	return qede_load(edev, QEDE_LOAD_NORMAL);
+	rc = qede_load(edev, QEDE_LOAD_NORMAL);
+
+	if (rc)
+		return rc;
+
+#ifdef CONFIG_QEDE_VXLAN
+	vxlan_get_rx_port(ndev);
+#endif
+	return 0;
 }
 }
 
 
 static int qede_close(struct net_device *ndev)
 static int qede_close(struct net_device *ndev)