aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/ethtool.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-02-02 17:41:49 -0500
committerBen Hutchings <bhutchings@solarflare.com>2012-02-15 19:11:24 -0500
commitc274d65c949d0909fc8f4f19561ecb7c1d3d1559 (patch)
treea30ae1b9657f498a582f025b43d9db203d23965a /drivers/net/ethernet/sfc/ethtool.c
parent7c43161c11d7f40e38db9a1adb61347f06127796 (diff)
sfc: Add support for configuring RX unicast/multicast default filters
On Siena all received packets that don't match a more specific filter will match the unicast or multicast default filter. Currently we leave these set to the default values (RSS with base queue number of 0). Allow them to be reconfigured to select a single RX queue. These default filters are programmed through the FILTER_CTL register, but we represent them internally as an additional table of size 2. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/ethtool.c')
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c59
1 files changed, 42 insertions, 17 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index f887f65e4189..83191151b650 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -808,11 +808,16 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
808 return efx_reset(efx, rc); 808 return efx_reset(efx, rc);
809} 809}
810 810
811/* MAC address mask including only MC flag */
812static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
813
811static int efx_ethtool_get_class_rule(struct efx_nic *efx, 814static int efx_ethtool_get_class_rule(struct efx_nic *efx,
812 struct ethtool_rx_flow_spec *rule) 815 struct ethtool_rx_flow_spec *rule)
813{ 816{
814 struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 817 struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
815 struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; 818 struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
819 struct ethhdr *mac_entry = &rule->h_u.ether_spec;
820 struct ethhdr *mac_mask = &rule->m_u.ether_spec;
816 struct efx_filter_spec spec; 821 struct efx_filter_spec spec;
817 u16 vid; 822 u16 vid;
818 u8 proto; 823 u8 proto;
@@ -828,11 +833,18 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
828 else 833 else
829 rule->ring_cookie = spec.dmaq_id; 834 rule->ring_cookie = spec.dmaq_id;
830 835
831 rc = efx_filter_get_eth_local(&spec, &vid, 836 if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) {
832 rule->h_u.ether_spec.h_dest); 837 rule->flow_type = ETHER_FLOW;
838 memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN);
839 if (spec.type == EFX_FILTER_MC_DEF)
840 memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN);
841 return 0;
842 }
843
844 rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest);
833 if (rc == 0) { 845 if (rc == 0) {
834 rule->flow_type = ETHER_FLOW; 846 rule->flow_type = ETHER_FLOW;
835 memset(rule->m_u.ether_spec.h_dest, ~0, ETH_ALEN); 847 memset(mac_mask->h_dest, ~0, ETH_ALEN);
836 if (vid != EFX_FILTER_VID_UNSPEC) { 848 if (vid != EFX_FILTER_VID_UNSPEC) {
837 rule->flow_type |= FLOW_EXT; 849 rule->flow_type |= FLOW_EXT;
838 rule->h_ext.vlan_tci = htons(vid); 850 rule->h_ext.vlan_tci = htons(vid);
@@ -1001,27 +1013,40 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
1001 } 1013 }
1002 1014
1003 case ETHER_FLOW | FLOW_EXT: 1015 case ETHER_FLOW | FLOW_EXT:
1004 /* Must match all or none of VID */ 1016 case ETHER_FLOW: {
1005 if (rule->m_ext.vlan_tci != htons(0xfff) && 1017 u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ?
1006 rule->m_ext.vlan_tci != 0) 1018 ntohs(rule->m_ext.vlan_tci) : 0);
1007 return -EINVAL; 1019
1008 case ETHER_FLOW: 1020 /* Must not match on source address or Ethertype */
1009 /* Must match all of destination */
1010 if (!is_broadcast_ether_addr(mac_mask->h_dest))
1011 return -EINVAL;
1012 /* and nothing else */
1013 if (!is_zero_ether_addr(mac_mask->h_source) || 1021 if (!is_zero_ether_addr(mac_mask->h_source) ||
1014 mac_mask->h_proto) 1022 mac_mask->h_proto)
1015 return -EINVAL; 1023 return -EINVAL;
1016 1024
1017 rc = efx_filter_set_eth_local( 1025 /* Is it a default UC or MC filter? */
1018 &spec, 1026 if (!compare_ether_addr(mac_mask->h_dest, mac_addr_mc_mask) &&
1019 (rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ? 1027 vlan_tag_mask == 0) {
1020 ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, 1028 if (is_multicast_ether_addr(mac_entry->h_dest))
1021 mac_entry->h_dest); 1029 rc = efx_filter_set_mc_def(&spec);
1030 else
1031 rc = efx_filter_set_uc_def(&spec);
1032 }
1033 /* Otherwise, it must match all of destination and all
1034 * or none of VID.
1035 */
1036 else if (is_broadcast_ether_addr(mac_mask->h_dest) &&
1037 (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) {
1038 rc = efx_filter_set_eth_local(
1039 &spec,
1040 vlan_tag_mask ?
1041 ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
1042 mac_entry->h_dest);
1043 } else {
1044 rc = -EINVAL;
1045 }
1022 if (rc) 1046 if (rc)
1023 return rc; 1047 return rc;
1024 break; 1048 break;
1049 }
1025 1050
1026 default: 1051 default:
1027 return -EINVAL; 1052 return -EINVAL;