aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/niu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r--drivers/net/niu.c158
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
6388static 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
6422static 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
6447static 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
6474static 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
6494static 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
6388static const struct { 6544static 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
6620static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, 6778static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,