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

Commit 58d7553d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlx4'



Merge mlx4 bug fixes from Amir Vadai.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1b13c97f 3484aac1
Loading
Loading
Loading
Loading
+103 −44
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/mlx4/driver.h>
#include <linux/in.h>
#include <net/ip.h>

#include "mlx4_en.h"
#include "en_port.h"
@@ -494,7 +496,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
	mutex_lock(&mdev->state_lock);
	if (priv->port_up) {
		port_up = 1;
		mlx4_en_stop_port(dev);
		mlx4_en_stop_port(dev, 1);
	}

	mlx4_en_free_resources(priv);
@@ -589,7 +591,7 @@ static int mlx4_en_set_rxfh_indir(struct net_device *dev,
	mutex_lock(&mdev->state_lock);
	if (priv->port_up) {
		port_up = 1;
		mlx4_en_stop_port(dev);
		mlx4_en_stop_port(dev, 1);
	}

	priv->prof->rss_rings = rss_rings;
@@ -664,27 +666,88 @@ static int mlx4_en_validate_flow(struct net_device *dev,

	if ((cmd->fs.flow_type & FLOW_EXT)) {
		if (cmd->fs.m_ext.vlan_etype ||
		    !(cmd->fs.m_ext.vlan_tci == 0 ||
		      cmd->fs.m_ext.vlan_tci == cpu_to_be16(0xfff)))
		    !((cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
		      0 ||
		      (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
		      cpu_to_be16(VLAN_VID_MASK)))
			return -EINVAL;

		if (cmd->fs.m_ext.vlan_tci) {
			if (be16_to_cpu(cmd->fs.h_ext.vlan_tci) >= VLAN_N_VID)
				return -EINVAL;

		}
	}

	return 0;
}

static int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd,
					struct list_head *rule_list_h,
					struct mlx4_spec_list *spec_l2,
					unsigned char *mac)
{
	int err = 0;
	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);

	spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
	memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
	memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN);

	if ((cmd->fs.flow_type & FLOW_EXT) &&
	    (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK))) {
		spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
		spec_l2->eth.vlan_id_msk = cpu_to_be16(VLAN_VID_MASK);
	}

	list_add_tail(&spec_l2->list, rule_list_h);

	return err;
}

static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
						struct ethtool_rxnfc *cmd,
						struct list_head *rule_list_h,
						struct mlx4_spec_list *spec_l2,
						__be32 ipv4_dst)
{
	__be64 be_mac = 0;
	unsigned char mac[ETH_ALEN];

	if (!ipv4_is_multicast(ipv4_dst)) {
		if (cmd->fs.flow_type & FLOW_MAC_EXT) {
			memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
		} else {
			be_mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
			memcpy(&mac, &be_mac, ETH_ALEN);
		}
	} else {
		ip_eth_mc_map(ipv4_dst, mac);
	}

	return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]);
}

static int add_ip_rule(struct mlx4_en_priv *priv,
		       struct ethtool_rxnfc *cmd,
		       struct list_head *list_h)
{
	struct mlx4_spec_list *spec_l3;
	struct mlx4_spec_list *spec_l2 = NULL;
	struct mlx4_spec_list *spec_l3 = NULL;
	struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;

	spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
	if (!spec_l3) {
	spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
	spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
	if (!spec_l2 || !spec_l3) {
		en_err(priv, "Fail to alloc ethtool rule.\n");
		kfree(spec_l2);
		kfree(spec_l3);
		return -ENOMEM;
	}

	mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2,
					     cmd->fs.h_u.
					     usr_ip4_spec.ip4dst);
	spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
	spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src;
	if (l3_mask->ip4src)
@@ -701,14 +764,17 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
			     struct ethtool_rxnfc *cmd,
			     struct list_head *list_h, int proto)
{
	struct mlx4_spec_list *spec_l3;
	struct mlx4_spec_list *spec_l4;
	struct mlx4_spec_list *spec_l2 = NULL;
	struct mlx4_spec_list *spec_l3 = NULL;
	struct mlx4_spec_list *spec_l4 = NULL;
	struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec;

	spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
	spec_l4 = kzalloc(sizeof *spec_l4, GFP_KERNEL);
	if (!spec_l4 || !spec_l3) {
	spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
	spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
	spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL);
	if (!spec_l2 || !spec_l3 || !spec_l4) {
		en_err(priv, "Fail to alloc ethtool rule.\n");
		kfree(spec_l2);
		kfree(spec_l3);
		kfree(spec_l4);
		return -ENOMEM;
@@ -717,12 +783,20 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
	spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;

	if (proto == TCP_V4_FLOW) {
		mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
						     spec_l2,
						     cmd->fs.h_u.
						     tcp_ip4_spec.ip4dst);
		spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP;
		spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src;
		spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst;
		spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc;
		spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst;
	} else {
		mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
						     spec_l2,
						     cmd->fs.h_u.
						     udp_ip4_spec.ip4dst);
		spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP;
		spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src;
		spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst;
@@ -751,43 +825,23 @@ static int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev,
					     struct list_head *rule_list_h)
{
	int err;
	__be64 be_mac;
	struct ethhdr *eth_spec;
	struct mlx4_en_priv *priv = netdev_priv(dev);
	struct mlx4_spec_list *spec_l2;
	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
	struct mlx4_en_priv *priv = netdev_priv(dev);

	err = mlx4_en_validate_flow(dev, cmd);
	if (err)
		return err;

	spec_l2 = kzalloc(sizeof *spec_l2, GFP_KERNEL);
	switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
	case ETHER_FLOW:
		spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
		if (!spec_l2)
			return -ENOMEM;

	if (cmd->fs.flow_type & FLOW_MAC_EXT) {
		memcpy(&be_mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
	} else {
		u64 mac = priv->mac & MLX4_MAC_MASK;
		be_mac = cpu_to_be64(mac << 16);
	}

	spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
	memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
	if ((cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) != ETHER_FLOW)
		memcpy(spec_l2->eth.dst_mac, &be_mac, ETH_ALEN);

	if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) {
		spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
		spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff);
	}

	list_add_tail(&spec_l2->list, rule_list_h);

	switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
	case ETHER_FLOW:
		eth_spec = &cmd->fs.h_u.ether_spec;
		memcpy(&spec_l2->eth.dst_mac, eth_spec->h_dest, ETH_ALEN);
		mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2,
					     &eth_spec->h_dest[0]);
		spec_l2->eth.ether_type = eth_spec->h_proto;
		if (eth_spec->h_proto)
			spec_l2->eth.ether_type_enable = 1;
@@ -861,6 +915,7 @@ static int mlx4_en_flow_replace(struct net_device *dev,
		loc_rule->id = 0;
		memset(&loc_rule->flow_spec, 0,
		       sizeof(struct ethtool_rx_flow_spec));
		list_del(&loc_rule->list);
	}
	err = mlx4_flow_attach(priv->mdev->dev, &rule, &reg_id);
	if (err) {
@@ -871,6 +926,7 @@ static int mlx4_en_flow_replace(struct net_device *dev,
	loc_rule->id = reg_id;
	memcpy(&loc_rule->flow_spec, &cmd->fs,
	       sizeof(struct ethtool_rx_flow_spec));
	list_add_tail(&loc_rule->list, &priv->ethtool_list);

out_free_list:
	list_for_each_entry_safe(spec, tmp_spec, &rule.list, list) {
@@ -904,6 +960,7 @@ static int mlx4_en_flow_detach(struct net_device *dev,
	}
	rule->id = 0;
	memset(&rule->flow_spec, 0, sizeof(struct ethtool_rx_flow_spec));
	list_del(&rule->list);
out:
	return err;

@@ -952,7 +1009,8 @@ static int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
	if ((cmd->cmd == ETHTOOL_GRXCLSRLCNT ||
	     cmd->cmd == ETHTOOL_GRXCLSRULE ||
	     cmd->cmd == ETHTOOL_GRXCLSRLALL) &&
	    mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
	    (mdev->dev->caps.steering_mode !=
	     MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up))
		return -EINVAL;

	switch (cmd->cmd) {
@@ -988,7 +1046,8 @@ static int mlx4_en_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
	struct mlx4_en_priv *priv = netdev_priv(dev);
	struct mlx4_en_dev *mdev = priv->mdev;

	if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
	if (mdev->dev->caps.steering_mode !=
	    MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up)
		return -EINVAL;

	switch (cmd->cmd) {
@@ -1037,7 +1096,7 @@ static int mlx4_en_set_channels(struct net_device *dev,
	mutex_lock(&mdev->state_lock);
	if (priv->port_up) {
		port_up = 1;
		mlx4_en_stop_port(dev);
		mlx4_en_stop_port(dev, 1);
	}

	mlx4_en_free_resources(priv);
+27 −5
Original line number Diff line number Diff line
@@ -1039,6 +1039,9 @@ int mlx4_en_start_port(struct net_device *dev)

	INIT_LIST_HEAD(&priv->mc_list);
	INIT_LIST_HEAD(&priv->curr_list);
	INIT_LIST_HEAD(&priv->ethtool_list);
	memset(&priv->ethtool_rules[0], 0,
	       sizeof(struct ethtool_flow_id) * MAX_NUM_OF_FS_RULES);

	/* Calculate Rx buf size */
	dev->mtu = min(dev->mtu, priv->max_mtu);
@@ -1175,6 +1178,8 @@ int mlx4_en_start_port(struct net_device *dev)

	priv->port_up = true;
	netif_tx_start_all_queues(dev);
	netif_device_attach(dev);

	return 0;

tx_err:
@@ -1197,11 +1202,12 @@ cq_err:
}


void mlx4_en_stop_port(struct net_device *dev)
void mlx4_en_stop_port(struct net_device *dev, int detach)
{
	struct mlx4_en_priv *priv = netdev_priv(dev);
	struct mlx4_en_dev *mdev = priv->mdev;
	struct mlx4_en_mc_list *mclist, *tmp;
	struct ethtool_flow_id *flow, *tmp_flow;
	int i;
	u8 mc_list[16] = {0};

@@ -1212,9 +1218,13 @@ void mlx4_en_stop_port(struct net_device *dev)

	/* Synchronize with tx routine */
	netif_tx_lock_bh(dev);
	if (detach)
		netif_device_detach(dev);
	netif_tx_stop_all_queues(dev);
	netif_tx_unlock_bh(dev);

	netif_tx_disable(dev);

	/* Set port as not active */
	priv->port_up = false;

@@ -1281,8 +1291,20 @@ void mlx4_en_stop_port(struct net_device *dev)

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

	/* Remove flow steering rules for the port*/
	if (mdev->dev->caps.steering_mode ==
	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
		ASSERT_RTNL();
		list_for_each_entry_safe(flow, tmp_flow,
					 &priv->ethtool_list, list) {
			mlx4_flow_detach(mdev->dev, flow->id);
			list_del(&flow->list);
		}
	}

	/* Free RX Rings */
	for (i = 0; i < priv->rx_ring_num; i++) {
		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
@@ -1307,7 +1329,7 @@ static void mlx4_en_restart(struct work_struct *work)

	mutex_lock(&mdev->state_lock);
	if (priv->port_up) {
		mlx4_en_stop_port(dev);
		mlx4_en_stop_port(dev, 1);
		for (i = 0; i < priv->tx_ring_num; i++)
			netdev_tx_reset_queue(priv->tx_ring[i].tx_queue);
		if (mlx4_en_start_port(dev))
@@ -1379,7 +1401,7 @@ static int mlx4_en_close(struct net_device *dev)

	mutex_lock(&mdev->state_lock);

	mlx4_en_stop_port(dev);
	mlx4_en_stop_port(dev, 0);
	netif_carrier_off(dev);

	mutex_unlock(&mdev->state_lock);
@@ -1517,7 +1539,7 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
			 * the port */
			en_dbg(DRV, priv, "Change MTU called with card down!?\n");
		} else {
			mlx4_en_stop_port(dev);
			mlx4_en_stop_port(dev, 1);
			err = mlx4_en_start_port(dev);
			if (err) {
				en_err(priv, "Failed restarting port:%d\n",
+8 −3
Original line number Diff line number Diff line
@@ -127,7 +127,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
		[0] = "RSS support",
		[1] = "RSS Toeplitz Hash Function support",
		[2] = "RSS XOR Hash Function support",
		[3] = "Device manage flow steering support"
		[3] = "Device manage flow steering support",
		[4] = "Automatic mac reassignment support"
	};
	int i;

@@ -478,6 +479,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET		0x94
#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET		0x98
#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET		0xa0
#define QUERY_DEV_CAP_FW_REASSIGN_MAC		0x9d

	dev_cap->flags2 = 0;
	mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -637,6 +639,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
		 QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
	MLX4_GET(dev_cap->reserved_lkey, outbox,
		 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
	MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
	if (field & 1<<6)
		dev_cap->flags2 |= MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN;
	MLX4_GET(dev_cap->max_icm_sz, outbox,
		 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
	if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
@@ -1287,14 +1292,14 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
		/* Enable Ethernet flow steering
		 * with udp unicast and tcp unicast
		 */
		MLX4_PUT(inbox, param->fs_hash_enable_bits,
		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
			 INIT_HCA_FS_ETH_BITS_OFFSET);
		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
			 INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
		/* Enable IPoIB flow steering
		 * with udp unicast and tcp unicast
		 */
		MLX4_PUT(inbox, param->fs_hash_enable_bits,
		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
			 INIT_HCA_FS_IB_BITS_OFFSET);
		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
			 INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
+0 −1
Original line number Diff line number Diff line
@@ -171,7 +171,6 @@ struct mlx4_init_hca_param {
	u8  log_mpt_sz;
	u8  log_uar_sz;
	u8  uar_page_sz; /* log pg sz in 4k chunks */
	u8  fs_hash_enable_bits;
	u8  steering_mode; /* for QUERY_HCA */
	u64 dev_cap_enabled;
};
+0 −16
Original line number Diff line number Diff line
@@ -1415,22 +1415,6 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
		if (mlx4_is_master(dev))
			mlx4_parav_master_pf_caps(dev);

		priv->fs_hash_mode = MLX4_FS_L2_HASH;

		switch (priv->fs_hash_mode) {
		case MLX4_FS_L2_HASH:
			init_hca.fs_hash_enable_bits = 0;
			break;

		case MLX4_FS_L2_L3_L4_HASH:
			/* Enable flow steering with
			 * udp unicast and tcp unicast
			 */
			init_hca.fs_hash_enable_bits =
				MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN;
			break;
		}

		profile = default_profile;
		if (dev->caps.steering_mode ==
		    MLX4_STEERING_MODE_DEVICE_MANAGED)
Loading