Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 846eac3f authored by Ganesh Goudar's avatar Ganesh Goudar Committed by David S. Miller
Browse files

cxgb4: implement udp tunnel callbacks



Implement ndo_udp_tunnel_add and ndo_udp_tunnel_del
to support vxlan tunnelling.

Original work by: Santosh Rastapur <santosh@chelsio.com>
Signed-off-by: default avatarGanesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ef0fd85a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -825,6 +825,10 @@ struct mbox_list {
	struct list_head list;
};

struct mps_encap_entry {
	atomic_t refcnt;
};

struct adapter {
	void __iomem *regs;
	void __iomem *bar2;
@@ -839,6 +843,8 @@ struct adapter {
	enum chip_type chip;

	int msg_enable;
	__be16 vxlan_port;
	u8 vxlan_port_cnt;

	struct adapter_params params;
	struct cxgb4_virt_res vres;
@@ -868,7 +874,10 @@ struct adapter {
	unsigned int clipt_start;
	unsigned int clipt_end;
	struct clip_tbl *clipt;
	unsigned int rawf_start;
	unsigned int rawf_cnt;
	struct smt_data *smt;
	struct mps_encap_entry *mps_encap;
	struct cxgb4_uld_info *uld;
	void *uld_handle[CXGB4_ULD_MAX];
	unsigned int num_uld;
@@ -1637,6 +1646,12 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox,
int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
		int mtu, int promisc, int all_multi, int bcast, int vlanex,
		bool sleep_ok);
int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,
			 const u8 *addr, const u8 *mask, unsigned int idx,
			 u8 lookup_type, u8 port_id, bool sleep_ok);
int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,
			  const u8 *addr, const u8 *mask, unsigned int idx,
			  u8 lookup_type, u8 port_id, bool sleep_ok);
int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
		      unsigned int viid, bool free, unsigned int naddr,
		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok);
+130 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@
#include <net/addrconf.h>
#include <linux/uaccess.h>
#include <linux/crash_dump.h>
#include <net/udp_tunnel.h>

#include "cxgb4.h"
#include "cxgb4_filter.h"
@@ -2987,6 +2988,133 @@ static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
	}
}

static void cxgb_del_udp_tunnel(struct net_device *netdev,
				struct udp_tunnel_info *ti)
{
	struct port_info *pi = netdev_priv(netdev);
	struct adapter *adapter = pi->adapter;
	unsigned int chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip);
	u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 };
	int ret = 0, i;

	if (chip_ver < CHELSIO_T6)
		return;

	switch (ti->type) {
	case UDP_TUNNEL_TYPE_VXLAN:
		if (!adapter->vxlan_port_cnt ||
		    adapter->vxlan_port != ti->port)
			return; /* Invalid VxLAN destination port */

		adapter->vxlan_port_cnt--;
		if (adapter->vxlan_port_cnt)
			return;

		adapter->vxlan_port = 0;
		t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 0);
		break;
	default:
		return;
	}

	/* Matchall mac entries can be deleted only after all tunnel ports
	 * are brought down or removed.
	 */
	if (!adapter->rawf_cnt)
		return;
	for_each_port(adapter, i) {
		pi = adap2pinfo(adapter, i);
		ret = t4_free_raw_mac_filt(adapter, pi->viid,
					   match_all_mac, match_all_mac,
					   adapter->rawf_start +
					    pi->port_id,
					   1, pi->port_id, true);
		if (ret < 0) {
			netdev_info(netdev, "Failed to free mac filter entry, for port %d\n",
				    i);
			return;
		}
		atomic_dec(&adapter->mps_encap[adapter->rawf_start +
			   pi->port_id].refcnt);
	}
}

static void cxgb_add_udp_tunnel(struct net_device *netdev,
				struct udp_tunnel_info *ti)
{
	struct port_info *pi = netdev_priv(netdev);
	struct adapter *adapter = pi->adapter;
	unsigned int chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip);
	u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 };
	int i, ret;

	if (chip_ver < CHELSIO_T6)
		return;

	switch (ti->type) {
	case UDP_TUNNEL_TYPE_VXLAN:
		/* For T6 fw reserves last 2 entries for
		 * storing match all mac filter (config file entry).
		 */
		if (!adapter->rawf_cnt)
			return;

		/* Callback for adding vxlan port can be called with the same
		 * port for both IPv4 and IPv6. We should not disable the
		 * offloading when the same port for both protocols is added
		 * and later one of them is removed.
		 */
		if (adapter->vxlan_port_cnt &&
		    adapter->vxlan_port == ti->port) {
			adapter->vxlan_port_cnt++;
			return;
		}

		/* We will support only one VxLAN port */
		if (adapter->vxlan_port_cnt) {
			netdev_info(netdev, "UDP port %d already offloaded, not adding port %d\n",
				    be16_to_cpu(adapter->vxlan_port),
				    be16_to_cpu(ti->port));
			return;
		}

		adapter->vxlan_port = ti->port;
		adapter->vxlan_port_cnt = 1;

		t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A,
			     VXLAN_V(be16_to_cpu(ti->port)) | VXLAN_EN_F);
		break;
	default:
		return;
	}

	/* Create a 'match all' mac filter entry for inner mac,
	 * if raw mac interface is supported. Once the linux kernel provides
	 * driver entry points for adding/deleting the inner mac addresses,
	 * we will remove this 'match all' entry and fallback to adding
	 * exact match filters.
	 */
	if (adapter->rawf_cnt) {
		for_each_port(adapter, i) {
			pi = adap2pinfo(adapter, i);

			ret = t4_alloc_raw_mac_filt(adapter, pi->viid,
						    match_all_mac,
						    match_all_mac,
						    adapter->rawf_start +
						    pi->port_id,
						    1, pi->port_id, true);
			if (ret < 0) {
				netdev_info(netdev, "Failed to allocate a mac filter entry, not adding port %d\n",
					    be16_to_cpu(ti->port));
				cxgb_del_udp_tunnel(netdev, ti);
				return;
			}
			atomic_inc(&adapter->mps_encap[ret].refcnt);
		}
	}
}

static netdev_features_t cxgb_fix_features(struct net_device *dev,
					   netdev_features_t features)
{
@@ -3018,6 +3146,8 @@ static const struct net_device_ops cxgb4_netdev_ops = {
#endif /* CONFIG_CHELSIO_T4_FCOE */
	.ndo_set_tx_maxrate   = cxgb_set_tx_maxrate,
	.ndo_setup_tc         = cxgb_setup_tc,
	.ndo_udp_tunnel_add   = cxgb_add_udp_tunnel,
	.ndo_udp_tunnel_del   = cxgb_del_udp_tunnel,
	.ndo_fix_features     = cxgb_fix_features,
};

+106 −0
Original line number Diff line number Diff line
@@ -7466,6 +7466,112 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}

/**
 *	t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam
 *	@adap: the adapter
 *	@viid: the VI id
 *	@addr: the MAC address
 *	@mask: the mask
 *	@idx: index of the entry in mps tcam
 *	@lookup_type: MAC address for inner (1) or outer (0) header
 *	@port_id: the port index
 *	@sleep_ok: call is allowed to sleep
 *
 *	Removes the mac entry at the specified index using raw mac interface.
 *
 *	Returns a negative error number on failure.
 */
int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,
			 const u8 *addr, const u8 *mask, unsigned int idx,
			 u8 lookup_type, u8 port_id, bool sleep_ok)
{
	struct fw_vi_mac_cmd c;
	struct fw_vi_mac_raw *p = &c.u.raw;
	u32 val;

	memset(&c, 0, sizeof(c));
	c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
				   FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
				   FW_CMD_EXEC_V(0) |
				   FW_VI_MAC_CMD_VIID_V(viid));
	val = FW_CMD_LEN16_V(1) |
	      FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_RAW);
	c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) |
					  FW_CMD_LEN16_V(val));

	p->raw_idx_pkd = cpu_to_be32(FW_VI_MAC_CMD_RAW_IDX_V(idx) |
				     FW_VI_MAC_ID_BASED_FREE);

	/* Lookup Type. Outer header: 0, Inner header: 1 */
	p->data0_pkd = cpu_to_be32(DATALKPTYPE_V(lookup_type) |
				   DATAPORTNUM_V(port_id));
	/* Lookup mask and port mask */
	p->data0m_pkd = cpu_to_be64(DATALKPTYPE_V(DATALKPTYPE_M) |
				    DATAPORTNUM_V(DATAPORTNUM_M));

	/* Copy the address and the mask */
	memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN);
	memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN);

	return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);
}

/**
 *	t4_alloc_raw_mac_filt - Adds a mac entry in mps tcam
 *	@adap: the adapter
 *	@viid: the VI id
 *	@mac: the MAC address
 *	@mask: the mask
 *	@idx: index at which to add this entry
 *	@port_id: the port index
 *	@lookup_type: MAC address for inner (1) or outer (0) header
 *	@sleep_ok: call is allowed to sleep
 *
 *	Adds the mac entry at the specified index using raw mac interface.
 *
 *	Returns a negative error number or the allocated index for this mac.
 */
int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,
			  const u8 *addr, const u8 *mask, unsigned int idx,
			  u8 lookup_type, u8 port_id, bool sleep_ok)
{
	int ret = 0;
	struct fw_vi_mac_cmd c;
	struct fw_vi_mac_raw *p = &c.u.raw;
	u32 val;

	memset(&c, 0, sizeof(c));
	c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
				   FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
				   FW_VI_MAC_CMD_VIID_V(viid));
	val = FW_CMD_LEN16_V(1) |
	      FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_RAW);
	c.freemacs_to_len16 = cpu_to_be32(val);

	/* Specify that this is an inner mac address */
	p->raw_idx_pkd = cpu_to_be32(FW_VI_MAC_CMD_RAW_IDX_V(idx));

	/* Lookup Type. Outer header: 0, Inner header: 1 */
	p->data0_pkd = cpu_to_be32(DATALKPTYPE_V(lookup_type) |
				   DATAPORTNUM_V(port_id));
	/* Lookup mask and port mask */
	p->data0m_pkd = cpu_to_be64(DATALKPTYPE_V(DATALKPTYPE_M) |
				    DATAPORTNUM_V(DATAPORTNUM_M));

	/* Copy the address and the mask */
	memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN);
	memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN);

	ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);
	if (ret == 0) {
		ret = FW_VI_MAC_CMD_RAW_IDX_G(be32_to_cpu(p->raw_idx_pkd));
		if (ret != idx)
			ret = -ENOMEM;
	}

	return ret;
}

/**
 *	t4_alloc_mac_filt - allocates exact-match filters for MAC addresses
 *	@adap: the adapter