aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c119
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
677static 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
699static 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
675static int add_ip_rule(struct mlx4_en_priv *priv, 722static 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 &eth_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;