diff options
author | Santwona Behera <santwona.behera@sun.com> | 2008-07-02 06:49:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-02 06:49:11 -0400 |
commit | b4653e99450693b75a3c6c8ff4f070164f12815e (patch) | |
tree | 5ecc2ce4777b46b119ed1ed0a9e2ef27a59f445c | |
parent | 0853ad66b14feb12acde7ac13b7c3b75770a0adc (diff) |
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>
-rw-r--r-- | drivers/net/niu.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 918f802fe089..de2a8a30199d 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -6385,6 +6385,162 @@ static int niu_get_eeprom(struct net_device *dev, | |||
6385 | return 0; | 6385 | return 0; |
6386 | } | 6386 | } |
6387 | 6387 | ||
6388 | static int niu_ethflow_to_class(int flow_type, u64 *class) | ||
6389 | { | ||
6390 | switch (flow_type) { | ||
6391 | case TCP_V4_FLOW: | ||
6392 | *class = CLASS_CODE_TCP_IPV4; | ||
6393 | break; | ||
6394 | case UDP_V4_FLOW: | ||
6395 | *class = CLASS_CODE_UDP_IPV4; | ||
6396 | break; | ||
6397 | case AH_ESP_V4_FLOW: | ||
6398 | *class = CLASS_CODE_AH_ESP_IPV4; | ||
6399 | break; | ||
6400 | case SCTP_V4_FLOW: | ||
6401 | *class = CLASS_CODE_SCTP_IPV4; | ||
6402 | break; | ||
6403 | case TCP_V6_FLOW: | ||
6404 | *class = CLASS_CODE_TCP_IPV6; | ||
6405 | break; | ||
6406 | case UDP_V6_FLOW: | ||
6407 | *class = CLASS_CODE_UDP_IPV6; | ||
6408 | break; | ||
6409 | case AH_ESP_V6_FLOW: | ||
6410 | *class = CLASS_CODE_AH_ESP_IPV6; | ||
6411 | break; | ||
6412 | case SCTP_V6_FLOW: | ||
6413 | *class = CLASS_CODE_SCTP_IPV6; | ||
6414 | break; | ||
6415 | default: | ||
6416 | return -1; | ||
6417 | } | ||
6418 | |||
6419 | return 1; | ||
6420 | } | ||
6421 | |||
6422 | static u64 niu_flowkey_to_ethflow(u64 flow_key) | ||
6423 | { | ||
6424 | u64 ethflow = 0; | ||
6425 | |||
6426 | if (flow_key & FLOW_KEY_PORT) | ||
6427 | ethflow |= RXH_DEV_PORT; | ||
6428 | if (flow_key & FLOW_KEY_L2DA) | ||
6429 | ethflow |= RXH_L2DA; | ||
6430 | if (flow_key & FLOW_KEY_VLAN) | ||
6431 | ethflow |= RXH_VLAN; | ||
6432 | if (flow_key & FLOW_KEY_IPSA) | ||
6433 | ethflow |= RXH_IP_SRC; | ||
6434 | if (flow_key & FLOW_KEY_IPDA) | ||
6435 | ethflow |= RXH_IP_DST; | ||
6436 | if (flow_key & FLOW_KEY_PROTO) | ||
6437 | ethflow |= RXH_L3_PROTO; | ||
6438 | if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT)) | ||
6439 | ethflow |= RXH_L4_B_0_1; | ||
6440 | if (flow_key & (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT)) | ||
6441 | ethflow |= RXH_L4_B_2_3; | ||
6442 | |||
6443 | return ethflow; | ||
6444 | |||
6445 | } | ||
6446 | |||
6447 | static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key) | ||
6448 | { | ||
6449 | u64 key = 0; | ||
6450 | |||
6451 | if (ethflow & RXH_DEV_PORT) | ||
6452 | key |= FLOW_KEY_PORT; | ||
6453 | if (ethflow & RXH_L2DA) | ||
6454 | key |= FLOW_KEY_L2DA; | ||
6455 | if (ethflow & RXH_VLAN) | ||
6456 | key |= FLOW_KEY_VLAN; | ||
6457 | if (ethflow & RXH_IP_SRC) | ||
6458 | key |= FLOW_KEY_IPSA; | ||
6459 | if (ethflow & RXH_IP_DST) | ||
6460 | key |= FLOW_KEY_IPDA; | ||
6461 | if (ethflow & RXH_L3_PROTO) | ||
6462 | key |= FLOW_KEY_PROTO; | ||
6463 | if (ethflow & RXH_L4_B_0_1) | ||
6464 | key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_0_SHIFT); | ||
6465 | if (ethflow & RXH_L4_B_2_3) | ||
6466 | key |= (FLOW_KEY_L4_BYTE12 << FLOW_KEY_L4_1_SHIFT); | ||
6467 | |||
6468 | *flow_key = key; | ||
6469 | |||
6470 | return 1; | ||
6471 | |||
6472 | } | ||
6473 | |||
6474 | static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
6475 | { | ||
6476 | struct niu *np = netdev_priv(dev); | ||
6477 | u64 class; | ||
6478 | |||
6479 | cmd->data = 0; | ||
6480 | |||
6481 | if (!niu_ethflow_to_class(cmd->flow_type, &class)) | ||
6482 | return -EINVAL; | ||
6483 | |||
6484 | if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & | ||
6485 | TCAM_KEY_DISC) | ||
6486 | cmd->data = RXH_DISCARD; | ||
6487 | else | ||
6488 | |||
6489 | cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class - | ||
6490 | CLASS_CODE_USER_PROG1]); | ||
6491 | return 0; | ||
6492 | } | ||
6493 | |||
6494 | static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
6495 | { | ||
6496 | struct niu *np = netdev_priv(dev); | ||
6497 | u64 class; | ||
6498 | u64 flow_key = 0; | ||
6499 | unsigned long flags; | ||
6500 | |||
6501 | if (!niu_ethflow_to_class(cmd->flow_type, &class)) | ||
6502 | return -EINVAL; | ||
6503 | |||
6504 | if (class < CLASS_CODE_USER_PROG1 || | ||
6505 | class > CLASS_CODE_SCTP_IPV6) | ||
6506 | return -EINVAL; | ||
6507 | |||
6508 | if (cmd->data & RXH_DISCARD) { | ||
6509 | niu_lock_parent(np, flags); | ||
6510 | flow_key = np->parent->tcam_key[class - | ||
6511 | CLASS_CODE_USER_PROG1]; | ||
6512 | flow_key |= TCAM_KEY_DISC; | ||
6513 | nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), flow_key); | ||
6514 | np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = flow_key; | ||
6515 | niu_unlock_parent(np, flags); | ||
6516 | return 0; | ||
6517 | } else { | ||
6518 | /* Discard was set before, but is not set now */ | ||
6519 | if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] & | ||
6520 | TCAM_KEY_DISC) { | ||
6521 | niu_lock_parent(np, flags); | ||
6522 | flow_key = np->parent->tcam_key[class - | ||
6523 | CLASS_CODE_USER_PROG1]; | ||
6524 | flow_key &= ~TCAM_KEY_DISC; | ||
6525 | nw64(TCAM_KEY(class - CLASS_CODE_USER_PROG1), | ||
6526 | flow_key); | ||
6527 | np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] = | ||
6528 | flow_key; | ||
6529 | niu_unlock_parent(np, flags); | ||
6530 | } | ||
6531 | } | ||
6532 | |||
6533 | if (!niu_ethflow_to_flowkey(cmd->data, &flow_key)) | ||
6534 | return -EINVAL; | ||
6535 | |||
6536 | niu_lock_parent(np, flags); | ||
6537 | nw64(FLOW_KEY(class - CLASS_CODE_USER_PROG1), flow_key); | ||
6538 | np->parent->flow_key[class - CLASS_CODE_USER_PROG1] = flow_key; | ||
6539 | niu_unlock_parent(np, flags); | ||
6540 | |||
6541 | return 0; | ||
6542 | } | ||
6543 | |||
6388 | static const struct { | 6544 | static const struct { |
6389 | const char string[ETH_GSTRING_LEN]; | 6545 | const char string[ETH_GSTRING_LEN]; |
6390 | } niu_xmac_stat_keys[] = { | 6546 | } niu_xmac_stat_keys[] = { |
@@ -6615,6 +6771,8 @@ static const struct ethtool_ops niu_ethtool_ops = { | |||
6615 | .get_stats_count = niu_get_stats_count, | 6771 | .get_stats_count = niu_get_stats_count, |
6616 | .get_ethtool_stats = niu_get_ethtool_stats, | 6772 | .get_ethtool_stats = niu_get_ethtool_stats, |
6617 | .phys_id = niu_phys_id, | 6773 | .phys_id = niu_phys_id, |
6774 | .get_rxhash = niu_get_hash_opts, | ||
6775 | .set_rxhash = niu_set_hash_opts, | ||
6618 | }; | 6776 | }; |
6619 | 6777 | ||
6620 | static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, | 6778 | static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, |