aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/ethtool.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-02-02 22:41:49 +0000
committerBen Hutchings <bhutchings@solarflare.com>2012-02-16 00:11:24 +0000
commitc274d65c949d0909fc8f4f19561ecb7c1d3d1559 (patch)
treea30ae1b9657f498a582f025b43d9db203d23965a /drivers/net/ethernet/sfc/ethtool.c
parentsfc: Warn if unable to create MTDs (diff)
downloadlinux-dev-c274d65c949d0909fc8f4f19561ecb7c1d3d1559.tar.xz
linux-dev-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.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)
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;