aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-09-20 04:43:42 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-21 17:58:00 -0400
commitb4187e4277b13d7bc4acc3c953b3cab0137b14b2 (patch)
tree83647558702b6051491f04c029a7eea53147f00b /drivers/net/sfc
parent64eebcfd899a5d2ebe211a593ec13ec24630f1a3 (diff)
sfc: Implement the ethtool RX n-tuple control functions
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/ethtool.c118
-rw-r--r--drivers/net/sfc/falcon.c2
-rw-r--r--drivers/net/sfc/siena.c2
3 files changed, 118 insertions, 4 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 7f735d80480..c95328fa3ee 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -15,6 +15,7 @@
15#include "workarounds.h" 15#include "workarounds.h"
16#include "selftest.h" 16#include "selftest.h"
17#include "efx.h" 17#include "efx.h"
18#include "filter.h"
18#include "nic.h" 19#include "nic.h"
19#include "spi.h" 20#include "spi.h"
20#include "mdio_10g.h" 21#include "mdio_10g.h"
@@ -551,9 +552,22 @@ static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
551static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) 552static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
552{ 553{
553 struct efx_nic *efx = netdev_priv(net_dev); 554 struct efx_nic *efx = netdev_priv(net_dev);
554 u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH; 555 u32 supported = (efx->type->offload_features &
556 (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE));
557 int rc;
558
559 rc = ethtool_op_set_flags(net_dev, data, supported);
560 if (rc)
561 return rc;
562
563 if (!(data & ETH_FLAG_NTUPLE)) {
564 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_IP,
565 EFX_FILTER_PRI_MANUAL);
566 efx_filter_table_clear(efx, EFX_FILTER_TABLE_RX_MAC,
567 EFX_FILTER_PRI_MANUAL);
568 }
555 569
556 return ethtool_op_set_flags(net_dev, data, supported); 570 return 0;
557} 571}
558 572
559static void efx_ethtool_self_test(struct net_device *net_dev, 573static void efx_ethtool_self_test(struct net_device *net_dev,
@@ -955,6 +969,105 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
955 } 969 }
956} 970}
957 971
972static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
973 struct ethtool_rx_ntuple *ntuple)
974{
975 struct efx_nic *efx = netdev_priv(net_dev);
976 struct ethtool_tcpip4_spec *ip_entry = &ntuple->fs.h_u.tcp_ip4_spec;
977 struct ethtool_tcpip4_spec *ip_mask = &ntuple->fs.m_u.tcp_ip4_spec;
978 struct ethhdr *mac_entry = &ntuple->fs.h_u.ether_spec;
979 struct ethhdr *mac_mask = &ntuple->fs.m_u.ether_spec;
980 struct efx_filter_spec filter;
981
982 /* Range-check action */
983 if (ntuple->fs.action < ETHTOOL_RXNTUPLE_ACTION_CLEAR ||
984 ntuple->fs.action >= (s32)efx->n_rx_channels)
985 return -EINVAL;
986
987 if (~ntuple->fs.data_mask)
988 return -EINVAL;
989
990 switch (ntuple->fs.flow_type) {
991 case TCP_V4_FLOW:
992 case UDP_V4_FLOW:
993 /* Must match all of destination, */
994 if (ip_mask->ip4dst | ip_mask->pdst)
995 return -EINVAL;
996 /* all or none of source, */
997 if ((ip_mask->ip4src | ip_mask->psrc) &&
998 ((__force u32)~ip_mask->ip4src |
999 (__force u16)~ip_mask->psrc))
1000 return -EINVAL;
1001 /* and nothing else */
1002 if ((u8)~ip_mask->tos | (u16)~ntuple->fs.vlan_tag_mask)
1003 return -EINVAL;
1004 break;
1005 case ETHER_FLOW:
1006 /* Must match all of destination, */
1007 if (!is_zero_ether_addr(mac_mask->h_dest))
1008 return -EINVAL;
1009 /* all or none of VID, */
1010 if (ntuple->fs.vlan_tag_mask != 0xf000 &&
1011 ntuple->fs.vlan_tag_mask != 0xffff)
1012 return -EINVAL;
1013 /* and nothing else */
1014 if (!is_broadcast_ether_addr(mac_mask->h_source) ||
1015 mac_mask->h_proto != htons(0xffff))
1016 return -EINVAL;
1017 break;
1018 default:
1019 return -EINVAL;
1020 }
1021
1022 filter.priority = EFX_FILTER_PRI_MANUAL;
1023 filter.flags = 0;
1024
1025 switch (ntuple->fs.flow_type) {
1026 case TCP_V4_FLOW:
1027 if (!ip_mask->ip4src)
1028 efx_filter_set_rx_tcp_full(&filter,
1029 htonl(ip_entry->ip4src),
1030 htons(ip_entry->psrc),
1031 htonl(ip_entry->ip4dst),
1032 htons(ip_entry->pdst));
1033 else
1034 efx_filter_set_rx_tcp_wild(&filter,
1035 htonl(ip_entry->ip4dst),
1036 htons(ip_entry->pdst));
1037 break;
1038 case UDP_V4_FLOW:
1039 if (!ip_mask->ip4src)
1040 efx_filter_set_rx_udp_full(&filter,
1041 htonl(ip_entry->ip4src),
1042 htons(ip_entry->psrc),
1043 htonl(ip_entry->ip4dst),
1044 htons(ip_entry->pdst));
1045 else
1046 efx_filter_set_rx_udp_wild(&filter,
1047 htonl(ip_entry->ip4dst),
1048 htons(ip_entry->pdst));
1049 break;
1050 case ETHER_FLOW:
1051 if (ntuple->fs.vlan_tag_mask == 0xf000)
1052 efx_filter_set_rx_mac_full(&filter,
1053 ntuple->fs.vlan_tag & 0xfff,
1054 mac_entry->h_dest);
1055 else
1056 efx_filter_set_rx_mac_wild(&filter, mac_entry->h_dest);
1057 break;
1058 }
1059
1060 if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) {
1061 return efx_filter_remove_filter(efx, &filter);
1062 } else {
1063 if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
1064 filter.dmaq_id = 0xfff;
1065 else
1066 filter.dmaq_id = ntuple->fs.action;
1067 return efx_filter_insert_filter(efx, &filter, true);
1068 }
1069}
1070
958static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, 1071static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
959 struct ethtool_rxfh_indir *indir) 1072 struct ethtool_rxfh_indir *indir)
960{ 1073{
@@ -1033,6 +1146,7 @@ const struct ethtool_ops efx_ethtool_ops = {
1033 .set_wol = efx_ethtool_set_wol, 1146 .set_wol = efx_ethtool_set_wol,
1034 .reset = efx_ethtool_reset, 1147 .reset = efx_ethtool_reset,
1035 .get_rxnfc = efx_ethtool_get_rxnfc, 1148 .get_rxnfc = efx_ethtool_get_rxnfc,
1149 .set_rx_ntuple = efx_ethtool_set_rx_ntuple,
1036 .get_rxfh_indir = efx_ethtool_get_rxfh_indir, 1150 .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
1037 .set_rxfh_indir = efx_ethtool_set_rxfh_indir, 1151 .set_rxfh_indir = efx_ethtool_set_rxfh_indir,
1038}; 1152};
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index b4d8efe6777..b398a419804 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1874,7 +1874,7 @@ struct efx_nic_type falcon_b0_nic_type = {
1874 * channels */ 1874 * channels */
1875 .tx_dc_base = 0x130000, 1875 .tx_dc_base = 0x130000,
1876 .rx_dc_base = 0x100000, 1876 .rx_dc_base = 0x100000,
1877 .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH, 1877 .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
1878 .reset_world_flags = ETH_RESET_IRQ, 1878 .reset_world_flags = ETH_RESET_IRQ,
1879}; 1879};
1880 1880
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 9f536804969..2115f95ddc8 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -651,6 +651,6 @@ struct efx_nic_type siena_a0_nic_type = {
651 .tx_dc_base = 0x88000, 651 .tx_dc_base = 0x88000,
652 .rx_dc_base = 0x68000, 652 .rx_dc_base = 0x68000,
653 .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 653 .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
654 NETIF_F_RXHASH), 654 NETIF_F_RXHASH | NETIF_F_NTUPLE),
655 .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, 655 .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
656}; 656};