diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 119 |
1 files changed, 82 insertions, 37 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 03447dad07e9..86afb5b0e0fa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | #include <linux/ethtool.h> | 35 | #include <linux/ethtool.h> |
| 36 | #include <linux/netdevice.h> | 36 | #include <linux/netdevice.h> |
| 37 | #include <linux/mlx4/driver.h> | 37 | #include <linux/mlx4/driver.h> |
| 38 | #include <linux/in.h> | ||
| 39 | #include <net/ip.h> | ||
| 38 | 40 | ||
| 39 | #include "mlx4_en.h" | 41 | #include "mlx4_en.h" |
| 40 | #include "en_port.h" | 42 | #include "en_port.h" |
| @@ -672,19 +674,71 @@ static int mlx4_en_validate_flow(struct net_device *dev, | |||
| 672 | return 0; | 674 | return 0; |
| 673 | } | 675 | } |
| 674 | 676 | ||
| 677 | static int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd, | ||
| 678 | struct list_head *rule_list_h, | ||
| 679 | struct mlx4_spec_list *spec_l2, | ||
| 680 | unsigned char *mac) | ||
| 681 | { | ||
| 682 | int err = 0; | ||
| 683 | __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); | ||
| 684 | |||
| 685 | spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH; | ||
| 686 | memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN); | ||
| 687 | memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN); | ||
| 688 | |||
| 689 | if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) { | ||
| 690 | spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci; | ||
| 691 | spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff); | ||
| 692 | } | ||
| 693 | |||
| 694 | list_add_tail(&spec_l2->list, rule_list_h); | ||
| 695 | |||
| 696 | return err; | ||
| 697 | } | ||
| 698 | |||
| 699 | static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv, | ||
| 700 | struct ethtool_rxnfc *cmd, | ||
| 701 | struct list_head *rule_list_h, | ||
| 702 | struct mlx4_spec_list *spec_l2, | ||
| 703 | __be32 ipv4_dst) | ||
| 704 | { | ||
| 705 | __be64 be_mac = 0; | ||
| 706 | unsigned char mac[ETH_ALEN]; | ||
| 707 | |||
| 708 | if (!ipv4_is_multicast(ipv4_dst)) { | ||
| 709 | if (cmd->fs.flow_type & FLOW_MAC_EXT) { | ||
| 710 | memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN); | ||
| 711 | } else { | ||
| 712 | be_mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16); | ||
| 713 | memcpy(&mac, &be_mac, ETH_ALEN); | ||
| 714 | } | ||
| 715 | } else { | ||
| 716 | ip_eth_mc_map(ipv4_dst, mac); | ||
| 717 | } | ||
| 718 | |||
| 719 | return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]); | ||
| 720 | } | ||
| 721 | |||
| 675 | static int add_ip_rule(struct mlx4_en_priv *priv, | 722 | static int add_ip_rule(struct mlx4_en_priv *priv, |
| 676 | struct ethtool_rxnfc *cmd, | 723 | struct ethtool_rxnfc *cmd, |
| 677 | struct list_head *list_h) | 724 | struct list_head *list_h) |
| 678 | { | 725 | { |
| 679 | struct mlx4_spec_list *spec_l3; | 726 | struct mlx4_spec_list *spec_l2 = NULL; |
| 727 | struct mlx4_spec_list *spec_l3 = NULL; | ||
| 680 | struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec; | 728 | struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec; |
| 681 | 729 | ||
| 682 | spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL); | 730 | spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL); |
| 683 | if (!spec_l3) { | 731 | spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); |
| 732 | if (!spec_l2 || !spec_l3) { | ||
| 684 | en_err(priv, "Fail to alloc ethtool rule.\n"); | 733 | en_err(priv, "Fail to alloc ethtool rule.\n"); |
| 734 | kfree(spec_l2); | ||
| 735 | kfree(spec_l3); | ||
| 685 | return -ENOMEM; | 736 | return -ENOMEM; |
| 686 | } | 737 | } |
| 687 | 738 | ||
| 739 | mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2, | ||
| 740 | cmd->fs.h_u. | ||
| 741 | usr_ip4_spec.ip4dst); | ||
| 688 | spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; | 742 | spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; |
| 689 | spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src; | 743 | spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src; |
| 690 | if (l3_mask->ip4src) | 744 | if (l3_mask->ip4src) |
| @@ -701,14 +755,17 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv, | |||
| 701 | struct ethtool_rxnfc *cmd, | 755 | struct ethtool_rxnfc *cmd, |
| 702 | struct list_head *list_h, int proto) | 756 | struct list_head *list_h, int proto) |
| 703 | { | 757 | { |
| 704 | struct mlx4_spec_list *spec_l3; | 758 | struct mlx4_spec_list *spec_l2 = NULL; |
| 705 | struct mlx4_spec_list *spec_l4; | 759 | struct mlx4_spec_list *spec_l3 = NULL; |
| 760 | struct mlx4_spec_list *spec_l4 = NULL; | ||
| 706 | struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec; | 761 | struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec; |
| 707 | 762 | ||
| 708 | spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL); | 763 | spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); |
| 709 | spec_l4 = kzalloc(sizeof *spec_l4, GFP_KERNEL); | 764 | spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL); |
| 710 | if (!spec_l4 || !spec_l3) { | 765 | spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL); |
| 766 | if (!spec_l2 || !spec_l3 || !spec_l4) { | ||
| 711 | en_err(priv, "Fail to alloc ethtool rule.\n"); | 767 | en_err(priv, "Fail to alloc ethtool rule.\n"); |
| 768 | kfree(spec_l2); | ||
| 712 | kfree(spec_l3); | 769 | kfree(spec_l3); |
| 713 | kfree(spec_l4); | 770 | kfree(spec_l4); |
| 714 | return -ENOMEM; | 771 | return -ENOMEM; |
| @@ -717,12 +774,20 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv, | |||
| 717 | spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; | 774 | spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4; |
| 718 | 775 | ||
| 719 | if (proto == TCP_V4_FLOW) { | 776 | if (proto == TCP_V4_FLOW) { |
| 777 | mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, | ||
| 778 | spec_l2, | ||
| 779 | cmd->fs.h_u. | ||
| 780 | tcp_ip4_spec.ip4dst); | ||
| 720 | spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP; | 781 | spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP; |
| 721 | spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src; | 782 | spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src; |
| 722 | spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst; | 783 | spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst; |
| 723 | spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc; | 784 | spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc; |
| 724 | spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst; | 785 | spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst; |
| 725 | } else { | 786 | } else { |
| 787 | mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, | ||
| 788 | spec_l2, | ||
| 789 | cmd->fs.h_u. | ||
| 790 | udp_ip4_spec.ip4dst); | ||
| 726 | spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP; | 791 | spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP; |
| 727 | spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src; | 792 | spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src; |
| 728 | spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst; | 793 | 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, | |||
| 751 | struct list_head *rule_list_h) | 816 | struct list_head *rule_list_h) |
| 752 | { | 817 | { |
| 753 | int err; | 818 | int err; |
| 754 | __be64 be_mac; | ||
| 755 | struct ethhdr *eth_spec; | 819 | struct ethhdr *eth_spec; |
| 756 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
| 757 | struct mlx4_spec_list *spec_l2; | 820 | struct mlx4_spec_list *spec_l2; |
| 758 | __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16); | 821 | struct mlx4_en_priv *priv = netdev_priv(dev); |
| 759 | 822 | ||
| 760 | err = mlx4_en_validate_flow(dev, cmd); | 823 | err = mlx4_en_validate_flow(dev, cmd); |
| 761 | if (err) | 824 | if (err) |
| 762 | return err; | 825 | return err; |
| 763 | 826 | ||
| 764 | spec_l2 = kzalloc(sizeof *spec_l2, GFP_KERNEL); | ||
| 765 | if (!spec_l2) | ||
| 766 | return -ENOMEM; | ||
| 767 | |||
| 768 | if (cmd->fs.flow_type & FLOW_MAC_EXT) { | ||
| 769 | memcpy(&be_mac, cmd->fs.h_ext.h_dest, ETH_ALEN); | ||
| 770 | } else { | ||
| 771 | u64 mac = priv->mac & MLX4_MAC_MASK; | ||
| 772 | be_mac = cpu_to_be64(mac << 16); | ||
| 773 | } | ||
| 774 | |||
| 775 | spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH; | ||
| 776 | memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN); | ||
| 777 | if ((cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) != ETHER_FLOW) | ||
| 778 | memcpy(spec_l2->eth.dst_mac, &be_mac, ETH_ALEN); | ||
| 779 | |||
| 780 | if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) { | ||
| 781 | spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci; | ||
| 782 | spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff); | ||
| 783 | } | ||
| 784 | |||
| 785 | list_add_tail(&spec_l2->list, rule_list_h); | ||
| 786 | |||
| 787 | switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { | 827 | switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { |
| 788 | case ETHER_FLOW: | 828 | case ETHER_FLOW: |
| 829 | spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL); | ||
| 830 | if (!spec_l2) | ||
| 831 | return -ENOMEM; | ||
| 832 | |||
| 789 | eth_spec = &cmd->fs.h_u.ether_spec; | 833 | eth_spec = &cmd->fs.h_u.ether_spec; |
| 790 | memcpy(&spec_l2->eth.dst_mac, eth_spec->h_dest, ETH_ALEN); | 834 | mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, |
| 835 | ð_spec->h_dest[0]); | ||
| 791 | spec_l2->eth.ether_type = eth_spec->h_proto; | 836 | spec_l2->eth.ether_type = eth_spec->h_proto; |
| 792 | if (eth_spec->h_proto) | 837 | if (eth_spec->h_proto) |
| 793 | spec_l2->eth.ether_type_enable = 1; | 838 | spec_l2->eth.ether_type_enable = 1; |
