Skip to content

Commit

Permalink
Merge branch 'mlx4'
Browse files Browse the repository at this point in the history
Merge mlx4 bug fixes from Amir Vadai.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 31, 2013
2 parents 1b13c97 + 3484aac commit 58d7553
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 81 deletions.
147 changes: 103 additions & 44 deletions drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 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)
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
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:
spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
if (!spec_l2)
return -ENOMEM;

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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
32 changes: 27 additions & 5 deletions drivers/net/ethernet/mellanox/mlx4/en_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -1197,11 +1202,12 @@ int mlx4_en_start_port(struct net_device *dev)
}


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};

Expand All @@ -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;

Expand Down Expand Up @@ -1281,7 +1291,19 @@ 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);
mdev->mac_removed[priv->port] = 1;
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++) {
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 58d7553

Please sign in to comment.