diff options
| author | Ben Hutchings <bhutchings@solarflare.com> | 2010-09-20 04:43:42 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-09-21 17:58:00 -0400 |
| commit | b4187e4277b13d7bc4acc3c953b3cab0137b14b2 (patch) | |
| tree | 83647558702b6051491f04c029a7eea53147f00b | |
| parent | 64eebcfd899a5d2ebe211a593ec13ec24630f1a3 (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>
| -rw-r--r-- | drivers/net/sfc/ethtool.c | 118 | ||||
| -rw-r--r-- | drivers/net/sfc/falcon.c | 2 | ||||
| -rw-r--r-- | drivers/net/sfc/siena.c | 2 |
3 files changed, 118 insertions, 4 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 7f735d804801..c95328fa3ee8 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) | |||
| 551 | static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) | 552 | static 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 | ||
| 559 | static void efx_ethtool_self_test(struct net_device *net_dev, | 573 | static 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 | ||
| 972 | static 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 | |||
| 958 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, | 1071 | static 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 b4d8efe67772..b398a4198042 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 9f5368049694..2115f95ddc88 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 | }; |
