diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-02 23:41:49 +0100 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-16 01:11:24 +0100 |
commit | c274d65c949d0909fc8f4f19561ecb7c1d3d1559 (patch) | |
tree | a30ae1b9657f498a582f025b43d9db203d23965a /drivers/net/ethernet/sfc/ethtool.c | |
parent | sfc: Warn if unable to create MTDs (diff) | |
download | linux-c274d65c949d0909fc8f4f19561ecb7c1d3d1559.tar.xz linux-c274d65c949d0909fc8f4f19561ecb7c1d3d1559.zip |
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.c | 59 |
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) return efx_reset(efx, rc); } +/* MAC address mask including only MC flag */ +static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; + static int efx_ethtool_get_class_rule(struct efx_nic *efx, struct ethtool_rx_flow_spec *rule) { struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; + struct ethhdr *mac_entry = &rule->h_u.ether_spec; + struct ethhdr *mac_mask = &rule->m_u.ether_spec; struct efx_filter_spec spec; u16 vid; u8 proto; @@ -828,11 +833,18 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, else rule->ring_cookie = spec.dmaq_id; - rc = efx_filter_get_eth_local(&spec, &vid, - rule->h_u.ether_spec.h_dest); + if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) { + rule->flow_type = ETHER_FLOW; + memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN); + if (spec.type == EFX_FILTER_MC_DEF) + memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN); + return 0; + } + + rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest); if (rc == 0) { rule->flow_type = ETHER_FLOW; - memset(rule->m_u.ether_spec.h_dest, ~0, ETH_ALEN); + memset(mac_mask->h_dest, ~0, ETH_ALEN); if (vid != EFX_FILTER_VID_UNSPEC) { rule->flow_type |= FLOW_EXT; rule->h_ext.vlan_tci = htons(vid); @@ -1001,27 +1013,40 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, } case ETHER_FLOW | FLOW_EXT: - /* Must match all or none of VID */ - if (rule->m_ext.vlan_tci != htons(0xfff) && - rule->m_ext.vlan_tci != 0) - return -EINVAL; - case ETHER_FLOW: - /* Must match all of destination */ - if (!is_broadcast_ether_addr(mac_mask->h_dest)) - return -EINVAL; - /* and nothing else */ + case ETHER_FLOW: { + u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ? + ntohs(rule->m_ext.vlan_tci) : 0); + + /* Must not match on source address or Ethertype */ if (!is_zero_ether_addr(mac_mask->h_source) || mac_mask->h_proto) return -EINVAL; - rc = efx_filter_set_eth_local( - &spec, - (rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ? - ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, - mac_entry->h_dest); + /* Is it a default UC or MC filter? */ + if (!compare_ether_addr(mac_mask->h_dest, mac_addr_mc_mask) && + vlan_tag_mask == 0) { + if (is_multicast_ether_addr(mac_entry->h_dest)) + rc = efx_filter_set_mc_def(&spec); + else + rc = efx_filter_set_uc_def(&spec); + } + /* Otherwise, it must match all of destination and all + * or none of VID. + */ + else if (is_broadcast_ether_addr(mac_mask->h_dest) && + (vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) { + rc = efx_filter_set_eth_local( + &spec, + vlan_tag_mask ? + ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC, + mac_entry->h_dest); + } else { + rc = -EINVAL; + } if (rc) return rc; break; + } default: return -EINVAL; |