From 015465f85193fdc3a0debb1c9176433ba19140b2 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:02 +0000 Subject: net/mlx4_core: Directly expose fields of HW flow steering rule control segment Some of the fields for struct mlx4_net_trans_rule_hw_ctrl were packed into u32 and accessed through bit field operations. Expose and access them directly as u8. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 1ee4db3..d7c0704 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -664,7 +664,7 @@ static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl, dw |= ctrl->priority << 16; hw->ctrl = cpu_to_be32(dw); - hw->vf_vep_port = cpu_to_be32(ctrl->port); + hw->port = ctrl->port; hw->qpn = cpu_to_be32(ctrl->qpn); } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 116c5c2..3263848 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -696,9 +696,12 @@ struct mlx4_steer { struct mlx4_net_trans_rule_hw_ctrl { __be32 ctrl; - __be32 vf_vep_port; + u8 rsvd1; + u8 funcid; + u8 vep; + u8 port; __be32 qpn; - __be32 reserved; + __be32 rsvd2; }; struct mlx4_net_trans_rule_hw_ib { diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 561ed2a..5997adc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -3018,7 +3018,7 @@ static int add_eth_header(struct mlx4_dev *dev, int slave, __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf; - port = be32_to_cpu(ctrl->vf_vep_port) & 0xff; + port = ctrl->port; eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1); /* Clear a space in the inbox for eth header */ -- cgit v0.10.2 From 248c62aa12a318fe53bf4f530b69b150c34416e7 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:03 +0000 Subject: net/mlx4_core: Set correctly allow_loopback flag The allow_loopback flag was wrongly set using arithmetic bit operation, change the code to use logical bit operation. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index d7c0704..5268552 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -1157,7 +1157,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], .priority = MLX4_DOMAIN_NIC, }; - rule.allow_loopback = ~block_mcast_loopback; + rule.allow_loopback = !block_mcast_loopback; rule.port = port; rule.qpn = qp->qpn; INIT_LIST_HEAD(&rule.list); -- cgit v0.10.2 From f90a36734a6a0d843baa37b7caa1ef020f799d47 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:04 +0000 Subject: net/mlx4_en: Fix ip/udp steering rules multicast mac when attached via ethtool Destination mac is a mandatory specification for ip/udp steering rules. When attaching multicast steering rules via ethtool the unicast mac of the interface was added to the rule specification instead of the multicast mac. The following commit sets the corresponding multicast mac for the rule multicast ip. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 03447da..86afb5b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "mlx4_en.h" #include "en_port.h" @@ -672,19 +674,71 @@ static int mlx4_en_validate_flow(struct net_device *dev, 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) { + 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); + + 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) @@ -701,14 +755,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 +774,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 +816,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, + ð_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; -- cgit v0.10.2 From 69d7126b7fef09beaa4b7c103ec2a5bd8c8b2666 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:05 +0000 Subject: net/mlx4_en: Validate VLAN IDs provided in ethtool flow steering rules When attaching flow steering rules via Ethtool accept only valid vlans IDs e.g in the range: [0,4095]. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 86afb5b..f33049f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -669,6 +669,10 @@ static int mlx4_en_validate_flow(struct net_device *dev, !(cmd->fs.m_ext.vlan_tci == 0 || cmd->fs.m_ext.vlan_tci == cpu_to_be16(0xfff))) 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; -- cgit v0.10.2 From 8258bd2713c3e42bc0e5664cbede0e07587c125f Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:06 +0000 Subject: net/mlx4_en: Fix vlan mask for ethtool steering rules The vlan mask field should be validated and assigned according to the field size which is 12 bits. Also replace the numeric 0xfff mask with existing kernel macro. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index f33049f..f36c219 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -666,12 +666,16 @@ 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; + } } @@ -690,9 +694,10 @@ static int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd, 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) { + 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(0xfff); + spec_l2->eth.vlan_id_msk = cpu_to_be16(VLAN_VID_MASK); } list_add_tail(&spec_l2->list, rule_list_h); -- cgit v0.10.2 From 280fce1e3ef85ff7f90a9d7e8c8a0d71bbf5a9a4 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:07 +0000 Subject: net/mlx4_en: Block insertion of ethtool steering rules while the interface is down Attaching steering rules while the interface is down is an invalid operation, block it. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index f36c219..6f8044d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1006,7 +1006,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) { @@ -1042,7 +1043,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) { -- cgit v0.10.2 From 0d256c0e93916f416f46d2ec235ea05fca202ede Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:08 +0000 Subject: net/mlx4_en: Fix ethtool rules leftovers after module unloaded As part of the driver unload flow, all steering rules must be deleted, make sure to remove the rules that were set through ethtool. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 6f8044d..738e95d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -915,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, ®_id); if (err) { @@ -925,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) { @@ -958,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; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 9c42812..333a7a0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -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); @@ -1202,6 +1205,7 @@ void mlx4_en_stop_port(struct net_device *dev) 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}; @@ -1283,6 +1287,17 @@ void mlx4_en_stop_port(struct net_device *dev) mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn); 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]); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 8d54412..4fb4a3e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -427,6 +427,7 @@ struct mlx4_en_frag_info { #endif struct ethtool_flow_id { + struct list_head list; struct ethtool_rx_flow_spec flow_spec; u64 id; }; @@ -441,6 +442,8 @@ struct mlx4_en_priv { struct mlx4_en_port_state port_state; spinlock_t stats_lock; struct ethtool_flow_id ethtool_rules[MAX_NUM_OF_FS_RULES]; + /* To allow rules removal while port is going down */ + struct list_head ethtool_list; unsigned long last_moder_packets[MAX_RX_RINGS]; unsigned long last_moder_tx_packets; -- cgit v0.10.2 From 23537b732f5dd9c917767419272aeb65cc4b8cfd Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Wed, 30 Jan 2013 23:07:09 +0000 Subject: net/mlx4_core: Use firmware driven flow steering hash mode The Firmware dynamically changes flow steering hash configuration from covering L2 only to "full" L2/L3/L4 mode needed. The dynamic change allows the driver to set hard coded hash configuration which is changed by the firmware from L2 to L2/L3/L4 when attaching the first L3/L4 flow steering rule and back to L2 when there are no more such rules. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 8b3d051..91acf71 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -1287,14 +1287,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); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index dbf2f69..3af33ff 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -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; }; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f1ee52d..e38c6b2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -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) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 3263848..172daaa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -60,11 +60,6 @@ #define MLX4_FS_MGM_LOG_ENTRY_SIZE 7 #define MLX4_FS_NUM_MCG (1 << 17) -enum { - MLX4_FS_L2_HASH = 0, - MLX4_FS_L2_L3_L4_HASH, -}; - #define MLX4_NUM_UP 8 #define MLX4_NUM_TC 8 #define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */ -- cgit v0.10.2 From 955154fa33df2b74f0fea8e7c84df6dfd954dab2 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Wed, 30 Jan 2013 23:07:10 +0000 Subject: net/mlx4_en: Don't reassign port mac address on firmware that supports it Mac reassignments should only be done when not supported by the firmware. To accomplish that, checking firmware capability bit to know whether we should reassign macs in the driver. Signed-off-by: Matan Barak Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 333a7a0..7b513e9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1285,7 +1285,8 @@ 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 == diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 91acf71..38b62c7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -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) diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 20ea939..1883e8e 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -150,7 +150,8 @@ enum { MLX4_DEV_CAP_FLAG2_RSS = 1LL << 0, MLX4_DEV_CAP_FLAG2_RSS_TOP = 1LL << 1, MLX4_DEV_CAP_FLAG2_RSS_XOR = 1LL << 2, - MLX4_DEV_CAP_FLAG2_FS_EN = 1LL << 3 + MLX4_DEV_CAP_FLAG2_FS_EN = 1LL << 3, + MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN = 1LL << 4 }; enum { -- cgit v0.10.2 From 3484aac16149636f0ba5b5b0789a2918c682db7e Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Wed, 30 Jan 2013 23:07:11 +0000 Subject: net/mlx4_en: Fix transmit timeout when driver restarts port Under heavy CPU load, changing, ring size/mtu/etc. could result in transmit timeout, since stop-start port might take more than 10 seconds. Calling netif_detach_device to prevent tx queue transmit timeout. netif_detach_device() is not called under ndo_stop, because netif_carrier_off will prevent the timeout, and device should not be marked as not present, or else user won't be able to start it later on. CC: Ben Hutchings Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 738e95d..911d488 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -496,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); @@ -591,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; @@ -1096,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); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 7b513e9..ac1c14f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1178,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: @@ -1200,7 +1202,7 @@ 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; @@ -1216,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; @@ -1323,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)) @@ -1395,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); @@ -1533,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", diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 4fb4a3e..43f0165 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -539,7 +539,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_port_profile *prof); 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); void mlx4_en_free_resources(struct mlx4_en_priv *priv); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); -- cgit v0.10.2