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

Commit 16a10ffd authored by Yan Burman's avatar Yan Burman Committed by David S. Miller
Browse files

net/mlx4: Move Ethernet related functionality from mlx4_core to mlx4_en



Move low level code that deals with management of Ethernet MACs and QPs from mlx4_core to mlx4_en.
Also convert the new functions to deal with MACs in form of char array instead of u64.

Actual functions moved:
mlx4_replace_mac
mlx4_get_eth_qp
mlx4_put_eth_qp

To conduct this change, some functionality had to be exported from the core,
the following functions were added:
mlx4_get_base_qp
__mlx4_replace_mac (low level function for CX1/A0 compatibility)

Signed-off-by: default avatarYan Burman <yanb@mellanox.com>
Signed-off-by: default avatarAmir Vadai <amirv@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 48e551ff
Loading
Loading
Loading
Loading
+207 −9
Original line number Diff line number Diff line
@@ -420,6 +420,206 @@ static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
	memset(&dst_mac[ETH_ALEN], 0, 2);
}

static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv,
				unsigned char *mac, int *qpn, u64 *reg_id)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_dev *dev = mdev->dev;
	int err;

	switch (dev->caps.steering_mode) {
	case MLX4_STEERING_MODE_B0: {
		struct mlx4_qp qp;
		u8 gid[16] = {0};

		qp.qpn = *qpn;
		memcpy(&gid[10], mac, ETH_ALEN);
		gid[5] = priv->port;

		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
		break;
	}
	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
		struct mlx4_spec_list spec_eth = { {NULL} };
		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);

		struct mlx4_net_trans_rule rule = {
			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
			.exclusive = 0,
			.allow_loopback = 1,
			.promisc_mode = MLX4_FS_PROMISC_NONE,
			.priority = MLX4_DOMAIN_NIC,
		};

		rule.port = priv->port;
		rule.qpn = *qpn;
		INIT_LIST_HEAD(&rule.list);

		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
		memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN);
		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
		list_add_tail(&spec_eth.list, &rule.list);

		err = mlx4_flow_attach(dev, &rule, reg_id);
		break;
	}
	default:
		return -EINVAL;
	}
	if (err)
		en_warn(priv, "Failed Attaching Unicast\n");

	return err;
}

static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv,
				     unsigned char *mac, int qpn, u64 reg_id)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_dev *dev = mdev->dev;

	switch (dev->caps.steering_mode) {
	case MLX4_STEERING_MODE_B0: {
		struct mlx4_qp qp;
		u8 gid[16] = {0};

		qp.qpn = qpn;
		memcpy(&gid[10], mac, ETH_ALEN);
		gid[5] = priv->port;

		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
		break;
	}
	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
		mlx4_flow_detach(dev, reg_id);
		break;
	}
	default:
		en_err(priv, "Invalid steering mode.\n");
	}
}

static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_dev *dev = mdev->dev;
	struct mlx4_mac_entry *entry;
	int index = 0;
	int err = 0;
	u64 reg_id;
	int *qpn = &priv->base_qpn;
	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);

	en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
	       priv->dev->dev_addr);
	index = mlx4_register_mac(dev, priv->port, mac);
	if (index < 0) {
		err = index;
		en_err(priv, "Failed adding MAC: %pM\n",
		       priv->dev->dev_addr);
		return err;
	}

	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
		int base_qpn = mlx4_get_base_qpn(dev, priv->port);
		*qpn = base_qpn + index;
		return 0;
	}

	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
	en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
	if (err) {
		en_err(priv, "Failed to reserve qp for mac registration\n");
		goto qp_err;
	}

	err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, &reg_id);
	if (err)
		goto steer_err;

	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry) {
		err = -ENOMEM;
		goto alloc_err;
	}
	memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
	entry->reg_id = reg_id;

	err = radix_tree_insert(&priv->mac_tree, *qpn, entry);
	if (err)
		goto insert_err;
	return 0;

insert_err:
	kfree(entry);

alloc_err:
	mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);

steer_err:
	mlx4_qp_release_range(dev, *qpn, 1);

qp_err:
	mlx4_unregister_mac(dev, priv->port, mac);
	return err;
}

static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_dev *dev = mdev->dev;
	struct mlx4_mac_entry *entry;
	int qpn = priv->base_qpn;
	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);

	en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
	       priv->dev->dev_addr);
	mlx4_unregister_mac(dev, priv->port, mac);

	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
		entry = radix_tree_lookup(&priv->mac_tree, qpn);
		if (entry) {
			en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
			       priv->port, entry->mac, qpn);
			mlx4_en_uc_steer_release(priv, entry->mac,
						 qpn, entry->reg_id);
			mlx4_qp_release_range(dev, qpn, 1);
			radix_tree_delete(&priv->mac_tree, qpn);
			kfree(entry);
		}
	}
}

static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
			       unsigned char *new_mac)
{
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_dev *dev = mdev->dev;
	struct mlx4_mac_entry *entry;
	int err = 0;
	u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);

	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
		u64 prev_mac_u64;

		entry = radix_tree_lookup(&priv->mac_tree, qpn);
		if (!entry)
			return -EINVAL;
		prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac);
		mlx4_en_uc_steer_release(priv, entry->mac,
					 qpn, entry->reg_id);
		mlx4_unregister_mac(dev, priv->port, prev_mac_u64);
		memcpy(entry->mac, new_mac, ETH_ALEN);
		entry->reg_id = 0;
		mlx4_register_mac(dev, priv->port, new_mac_u64);
		err = mlx4_en_uc_steer_add(priv, new_mac,
					   &qpn, &entry->reg_id);
		return err;
	}

	return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
}

u64 mlx4_en_mac_to_u64(u8 *addr)
{
	u64 mac = 0;
@@ -456,9 +656,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
	mutex_lock(&mdev->state_lock);
	if (priv->port_up) {
		/* Remove old MAC and insert the new one */
		u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
		err = mlx4_replace_mac(mdev->dev, priv->port,
				       priv->base_qpn, mac);
		err = mlx4_en_replace_mac(priv, priv->base_qpn,
					  priv->dev->dev_addr);
		if (err)
			en_err(priv, "Failed changing HW MAC address\n");
		memcpy(priv->prev_mac, priv->dev->dev_addr,
@@ -1035,7 +1234,6 @@ int mlx4_en_start_port(struct net_device *dev)
	int i;
	int j;
	u8 mc_list[16] = {0};
	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);

	if (priv->port_up) {
		en_dbg(DRV, priv, "start port called while port already up\n");
@@ -1082,8 +1280,7 @@ int mlx4_en_start_port(struct net_device *dev)

	/* Set qp number */
	en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port);
	err = mlx4_get_eth_qp(mdev->dev, priv->port,
			      mac, &priv->base_qpn);
	err = mlx4_en_get_qp(priv);
	if (err) {
		en_err(priv, "Failed getting eth qp\n");
		goto cq_err;
@@ -1196,7 +1393,7 @@ int mlx4_en_start_port(struct net_device *dev)
rss_err:
	mlx4_en_release_rss_steer(priv);
mac_err:
	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
	mlx4_en_put_qp(priv);
cq_err:
	while (rx_index--)
		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -1215,7 +1412,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
	struct ethtool_flow_id *flow, *tmp_flow;
	int i;
	u8 mc_list[16] = {0};
	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);

	if (!priv->port_up) {
		en_dbg(DRV, priv, "stop port called while port already down\n");
@@ -1296,7 +1492,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
	mlx4_en_release_rss_steer(priv);

	/* Unregister Mac address for the port */
	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
	mlx4_en_put_qp(priv);
	if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
		mdev->mac_removed[priv->port] = 1;

@@ -1661,6 +1857,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
		dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
#endif

	INIT_RADIX_TREE(&priv->mac_tree, GFP_KERNEL);

	/* Query for default mac and max mtu */
	priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];

+1 −4
Original line number Diff line number Diff line
@@ -1833,12 +1833,9 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
	info->dev = dev;
	info->port = port;
	if (!mlx4_is_slave(dev)) {
		INIT_RADIX_TREE(&info->mac_tree, GFP_KERNEL);
		mlx4_init_mac_table(dev, &info->mac_table);
		mlx4_init_vlan_table(dev, &info->vlan_table);
		info->base_qpn =
			dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
			(port - 1) * (1 << log_num_mac);
		info->base_qpn = mlx4_get_base_qpn(dev, port);
	}

	sprintf(info->dev_name, "mlx4_port%d", port);
+0 −7
Original line number Diff line number Diff line
@@ -653,11 +653,6 @@ struct mlx4_set_port_rqp_calc_context {
	__be32 mcast;
};

struct mlx4_mac_entry {
	u64 mac;
	u64 reg_id;
};

struct mlx4_port_info {
	struct mlx4_dev	       *dev;
	int			port;
@@ -667,7 +662,6 @@ struct mlx4_port_info {
	char			dev_mtu_name[16];
	struct device_attribute port_mtu_attr;
	struct mlx4_mac_table	mac_table;
	struct radix_tree_root	mac_tree;
	struct mlx4_vlan_table	vlan_table;
	int			base_qpn;
};
@@ -916,7 +910,6 @@ int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
		     int start_index, int npages, u64 *page_list);
int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
+6 −0
Original line number Diff line number Diff line
@@ -521,6 +521,7 @@ struct mlx4_en_priv {
	bool wol;
	struct device *ddev;
	int base_tx_qpn;
	struct radix_tree_root mac_tree;

#ifdef CONFIG_MLX4_EN_DCB
	struct ieee_ets ets;
@@ -540,6 +541,11 @@ enum mlx4_en_wol {
	MLX4_EN_WOL_ENABLED = (1ULL << 62),
};

struct mlx4_mac_entry {
	unsigned char mac[ETH_ALEN + 2];
	u64 reg_id;
};

#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)

void mlx4_en_update_loopback_state(struct net_device *dev,
+8 −185
Original line number Diff line number Diff line
@@ -74,87 +74,6 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
	table->total = 0;
}

static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
			     u64 mac, int *qpn, u64 *reg_id)
{
	__be64 be_mac;
	int err;

	mac &= MLX4_MAC_MASK;
	be_mac = cpu_to_be64(mac << 16);

	switch (dev->caps.steering_mode) {
	case MLX4_STEERING_MODE_B0: {
		struct mlx4_qp qp;
		u8 gid[16] = {0};

		qp.qpn = *qpn;
		memcpy(&gid[10], &be_mac, ETH_ALEN);
		gid[5] = port;

		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
		break;
	}
	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
		struct mlx4_spec_list spec_eth = { {NULL} };
		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);

		struct mlx4_net_trans_rule rule = {
			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
			.exclusive = 0,
			.allow_loopback = 1,
			.promisc_mode = MLX4_FS_PROMISC_NONE,
			.priority = MLX4_DOMAIN_NIC,
		};

		rule.port = port;
		rule.qpn = *qpn;
		INIT_LIST_HEAD(&rule.list);

		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
		memcpy(spec_eth.eth.dst_mac, &be_mac, ETH_ALEN);
		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
		list_add_tail(&spec_eth.list, &rule.list);

		err = mlx4_flow_attach(dev, &rule, reg_id);
		break;
	}
	default:
		return -EINVAL;
	}
	if (err)
		mlx4_warn(dev, "Failed Attaching Unicast\n");

	return err;
}

static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
				  u64 mac, int qpn, u64 reg_id)
{
	switch (dev->caps.steering_mode) {
	case MLX4_STEERING_MODE_B0: {
		struct mlx4_qp qp;
		u8 gid[16] = {0};
		__be64 be_mac;

		qp.qpn = qpn;
		mac &= MLX4_MAC_MASK;
		be_mac = cpu_to_be64(mac << 16);
		memcpy(&gid[10], &be_mac, ETH_ALEN);
		gid[5] = port;

		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
		break;
	}
	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
		mlx4_flow_detach(dev, reg_id);
		break;
	}
	default:
		mlx4_err(dev, "Invalid steering mode.\n");
	}
}

static int validate_index(struct mlx4_dev *dev,
			  struct mlx4_mac_table *table, int index)
{
@@ -181,92 +100,6 @@ static int find_index(struct mlx4_dev *dev,
	return -EINVAL;
}

int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn)
{
	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
	struct mlx4_mac_entry *entry;
	int index = 0;
	int err = 0;
	u64 reg_id;

	mlx4_dbg(dev, "Registering MAC: 0x%llx for adding\n",
			(unsigned long long) mac);
	index = mlx4_register_mac(dev, port, mac);
	if (index < 0) {
		err = index;
		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
			 (unsigned long long) mac);
		return err;
	}

	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
		*qpn = info->base_qpn + index;
		return 0;
	}

	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
	mlx4_dbg(dev, "Reserved qp %d\n", *qpn);
	if (err) {
		mlx4_err(dev, "Failed to reserve qp for mac registration\n");
		goto qp_err;
	}

	err = mlx4_uc_steer_add(dev, port, mac, qpn, &reg_id);
	if (err)
		goto steer_err;

	entry = kmalloc(sizeof *entry, GFP_KERNEL);
	if (!entry) {
		err = -ENOMEM;
		goto alloc_err;
	}
	entry->mac = mac;
	entry->reg_id = reg_id;
	err = radix_tree_insert(&info->mac_tree, *qpn, entry);
	if (err)
		goto insert_err;
	return 0;

insert_err:
	kfree(entry);

alloc_err:
	mlx4_uc_steer_release(dev, port, mac, *qpn, reg_id);

steer_err:
	mlx4_qp_release_range(dev, *qpn, 1);

qp_err:
	mlx4_unregister_mac(dev, port, mac);
	return err;
}
EXPORT_SYMBOL_GPL(mlx4_get_eth_qp);

void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn)
{
	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
	struct mlx4_mac_entry *entry;

	mlx4_dbg(dev, "Registering MAC: 0x%llx for deleting\n",
		 (unsigned long long) mac);
	mlx4_unregister_mac(dev, port, mac);

	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
		entry = radix_tree_lookup(&info->mac_tree, qpn);
		if (entry) {
			mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx,"
				 " qpn %d\n", port,
				 (unsigned long long) mac, qpn);
			mlx4_uc_steer_release(dev, port, entry->mac,
					      qpn, entry->reg_id);
			mlx4_qp_release_range(dev, qpn, 1);
			radix_tree_delete(&info->mac_tree, qpn);
			kfree(entry);
		}
	}
}
EXPORT_SYMBOL_GPL(mlx4_put_eth_qp);

static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
				   __be64 *entries)
{
@@ -359,6 +192,12 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
EXPORT_SYMBOL_GPL(mlx4_register_mac);

int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
{
	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
			(port - 1) * (1 << dev->caps.log_num_macs);
}
EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);

void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
{
@@ -397,29 +236,13 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
EXPORT_SYMBOL_GPL(mlx4_unregister_mac);

int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
{
	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
	struct mlx4_mac_table *table = &info->mac_table;
	struct mlx4_mac_entry *entry;
	int index = qpn - info->base_qpn;
	int err = 0;

	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
		entry = radix_tree_lookup(&info->mac_tree, qpn);
		if (!entry)
			return -EINVAL;
		mlx4_uc_steer_release(dev, port, entry->mac,
				      qpn, entry->reg_id);
		mlx4_unregister_mac(dev, port, entry->mac);
		entry->mac = new_mac;
		entry->reg_id = 0;
		mlx4_register_mac(dev, port, new_mac);
		err = mlx4_uc_steer_add(dev, port, entry->mac,
					&qpn, &entry->reg_id);
		return err;
	}

	/* CX1 doesn't support multi-functions */
	mutex_lock(&table->mutex);

@@ -439,7 +262,7 @@ int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
	mutex_unlock(&table->mutex);
	return err;
}
EXPORT_SYMBOL_GPL(mlx4_replace_mac);
EXPORT_SYMBOL_GPL(__mlx4_replace_mac);

static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
				    __be32 *entries)
Loading