niu: Add support for rx flow hash configuration.
Implemented ethtool callback functions for configuring receive flow hashing in the niu driver. Signed-off-by: Santwona Behera <santwona.behera@sun.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0853ad66b1
commit
b4653e9945
@ -6385,6 +6385,162 @@ static int niu_get_eeprom(struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int niu_ethflow_to_class(int flow_type, u64 *class)
|
||||
{
|
||||
switch (flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
*class = CLASS_CODE_TCP_IPV4;
|
||||
break;
|
||||
case UDP_V4_FLOW:
|
||||
*class = CLASS_CODE_UDP_IPV4;
|
||||
break;
|
||||
case AH_ESP_V4_FLOW:
|
||||
*class = CLASS_CODE_AH_ESP_IPV4;
|
||||
break;
|
||||
case SCTP_V4_FLOW:
|
||||
*class = CLASS_CODE_SCTP_IPV4;
|
||||
break;
|
||||
case TCP_V6_FLOW:
|
||||
*class = CLASS_CODE_TCP_IPV6;
|
||||
break;
|
||||
case UDP_V6_FLOW:
|
||||
*class = CLASS_CODE_UDP_IPV6;
|
||||
break;
|
||||
case AH_ESP_V6_FLOW:
|
||||
*class = CLASS_CODE_AH_ESP_IPV6;
|
||||
break;
|
||||
case SCTP_V6_FLOW:
|
||||
*class = CLASS_CODE_SCTP_IPV6;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u64 niu_flowkey_to_ethflow(u64 flow_key)
|
||||
{
|
||||
u64 ethflow = 0;
|
||||
|
||||
if (flow_key & FLOW_KEY_PORT)
|
||||
ethflow |= RXH_DEV_PORT;
|
||||
if (flow_key & FLOW_KEY_L2DA)
|
||||
ethflow |= RXH_L2DA;
|
||||
if (flow_key & FLOW_KEY_VLAN)
|
||||
ethflow |= RXH_VLAN;
|
||||
if (flow_key & FLOW_KEY_IPSA)
|
||||
ethflow |= RXH_IP_SRC;
|
||||
if (flow_key & FLOW_KEY_IPDA)
|
||||
ethflow |= RXH_IP_DST;
|
||||
if (flow_key & FLOW_KEY_PROTO)
|
||||
ethflow |= RXH_L3_PROTO;
|
||||
if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT))
|
||||
ethflow |= RXH_L4_B_0_1;
|
||||
if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT))
|
||||
ethflow |= RXH_L4_B_2_3;
|
||||
|
||||
return ethflow;
|
||||
|
||||
}
|
||||
|
||||
static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
|
||||
{
|
||||
u64 key = 0;
|
||||
|
||||
if (ethflow & RXH_DEV_PORT)
|
||||
key |= FLOW_KEY_PORT;
|
||||
if (ethflow & RXH_L2DA)
|
||||
key |= FLOW_KEY_L2DA;
|
||||
if (ethflow & RXH_VLAN)
|
||||
key |= FLOW_KEY_VLAN;
|
||||
if (ethflow & RXH_IP_SRC)
|
||||
key |= FLOW_KEY_IPSA;
|
||||
if (ethflow & RXH_IP_DST)
|
||||
key |= FLOW_KEY_IPDA;
|
||||
if (ethflow & RXH_L3_PROTO)
|
||||
key |= FLOW_KEY_PROTO;
|
||||
if (ethflow & RXH_L4_B_0_1)
|
||||
key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT);
|
||||
if (ethflow & RXH_L4_B_2_3)
|
||||
key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT);
|
||||
|
||||
*flow_key = key;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct niu *np = netdev_priv(dev);
|
||||
u64 class;
|
||||
|
||||
cmd->data = 0;
|
||||
|
||||
if (!niu_ethflow_to_class(cmd->flow_type, &class))
|
||||
return -EINVAL;
|
||||
|
||||
if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
|
||||
TCAM_KEY_DISC)
|
||||
cmd->data = RXH_DISCARD;
|
||||
else
|
||||
|
||||
cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
|
||||
CLASS_CODE_USER_PROG1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct niu *np = netdev_priv(dev);
|
||||
u64 class;
|
||||
u64 flow_key = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!niu_ethflow_to_class(cmd->flow_type, &class))
|
||||
return -EINVAL;
|
||||
|
||||
if (class < CLASS_CODE_USER_PROG1 ||
|
||||
class > CLASS_CODE_SCTP_IPV6)
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd->data & RXH_DISCARD) {
|
||||
niu_lock_parent(np, flags);
|
||||
flow_key = np->parent->tcam_key[class -
|
||||
CLASS_CODE_USER_PROG1];
|
||||
flow_key |= TCAM_KEY_DISC;
|
||||
nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
|
||||
np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key;
|
||||
niu_unlock_parent(np, flags);
|
||||
return 0;
|
||||
} else {
|
||||
/* Discard was set before, but is not set now */
|
||||
if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
|
||||
TCAM_KEY_DISC) {
|
||||
niu_lock_parent(np, flags);
|
||||
flow_key = np->parent->tcam_key[class -
|
||||
CLASS_CODE_USER_PROG1];
|
||||
flow_key &= ~TCAM_KEY_DISC;
|
||||
nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1),
|
||||
flow_key);
|
||||
np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] =
|
||||
flow_key;
|
||||
niu_unlock_parent(np, flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (!niu_ethflow_to_flowkey(cmd->data, &flow_key))
|
||||
return -EINVAL;
|
||||
|
||||
niu_lock_parent(np, flags);
|
||||
nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key);
|
||||
np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key;
|
||||
niu_unlock_parent(np, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char string[ETH_GSTRING_LEN];
|
||||
} niu_xmac_stat_keys[] = {
|
||||
@ -6615,6 +6771,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
|
||||
.get_stats_count = niu_get_stats_count,
|
||||
.get_ethtool_stats = niu_get_ethtool_stats,
|
||||
.phys_id = niu_phys_id,
|
||||
.get_rxhash = niu_get_hash_opts,
|
||||
.set_rxhash = niu_set_hash_opts,
|
||||
};
|
||||
|
||||
static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
|
||||
|
Loading…
Reference in New Issue
Block a user