From c274d65c949d0909fc8f4f19561ecb7c1d3d1559 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 2 Feb 2012 22:41:49 +0000 Subject: 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 --- drivers/net/ethernet/sfc/ethtool.c | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) (limited to 'drivers/net/ethernet/sfc/ethtool.c') 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; -- cgit v1.2.3