aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/igb/igb_ethtool.c
diff options
context:
space:
mode:
authorAkeem G. Abodunrin <akeem.g.abodunrin@intel.com>2012-11-12 23:03:21 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-13 14:18:14 -0500
commit039454a818b4bfdb530d84b2cdcf014b2f4d2b53 (patch)
tree5ef12c533df7e3760215461858ff26f2b3051471 /drivers/net/ethernet/intel/igb/igb_ethtool.c
parent867eb39e8b023b25073ad9d47ff3230b4f65990b (diff)
igb: Support for modifying UDP RSS flow hashing
This patch provides ability to enable or disable UDP RSS hashing. It gives users option of generating RSS hash based on the UDP source and destination ports numbers. Currently, UDP flow hash is always disabled in igb-driver. Signed-off-by: Akeem G Abodunrin <akeem.g.abodunrin@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/intel/igb/igb_ethtool.c')
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index d8b1bee606c0..2b82a53f4ab3 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2350,6 +2350,185 @@ static int igb_get_ts_info(struct net_device *dev,
2350 } 2350 }
2351} 2351}
2352 2352
2353static int igb_get_rss_hash_opts(struct igb_adapter *adapter,
2354 struct ethtool_rxnfc *cmd)
2355{
2356 cmd->data = 0;
2357
2358 /* Report default options for RSS on igb */
2359 switch (cmd->flow_type) {
2360 case TCP_V4_FLOW:
2361 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
2362 case UDP_V4_FLOW:
2363 if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
2364 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
2365 case SCTP_V4_FLOW:
2366 case AH_ESP_V4_FLOW:
2367 case AH_V4_FLOW:
2368 case ESP_V4_FLOW:
2369 case IPV4_FLOW:
2370 cmd->data |= RXH_IP_SRC | RXH_IP_DST;
2371 break;
2372 case TCP_V6_FLOW:
2373 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
2374 case UDP_V6_FLOW:
2375 if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
2376 cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
2377 case SCTP_V6_FLOW:
2378 case AH_ESP_V6_FLOW:
2379 case AH_V6_FLOW:
2380 case ESP_V6_FLOW:
2381 case IPV6_FLOW:
2382 cmd->data |= RXH_IP_SRC | RXH_IP_DST;
2383 break;
2384 default:
2385 return -EINVAL;
2386 }
2387
2388 return 0;
2389}
2390
2391static int igb_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
2392 u32 *rule_locs)
2393{
2394 struct igb_adapter *adapter = netdev_priv(dev);
2395 int ret = -EOPNOTSUPP;
2396
2397 switch (cmd->cmd) {
2398 case ETHTOOL_GRXRINGS:
2399 cmd->data = adapter->num_rx_queues;
2400 ret = 0;
2401 break;
2402 case ETHTOOL_GRXFH:
2403 ret = igb_get_rss_hash_opts(adapter, cmd);
2404 break;
2405 default:
2406 break;
2407 }
2408
2409 return ret;
2410}
2411
2412#define UDP_RSS_FLAGS (IGB_FLAG_RSS_FIELD_IPV4_UDP | \
2413 IGB_FLAG_RSS_FIELD_IPV6_UDP)
2414static int igb_set_rss_hash_opt(struct igb_adapter *adapter,
2415 struct ethtool_rxnfc *nfc)
2416{
2417 u32 flags = adapter->flags;
2418
2419 /* RSS does not support anything other than hashing
2420 * to queues on src and dst IPs and ports
2421 */
2422 if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
2423 RXH_L4_B_0_1 | RXH_L4_B_2_3))
2424 return -EINVAL;
2425
2426 switch (nfc->flow_type) {
2427 case TCP_V4_FLOW:
2428 case TCP_V6_FLOW:
2429 if (!(nfc->data & RXH_IP_SRC) ||
2430 !(nfc->data & RXH_IP_DST) ||
2431 !(nfc->data & RXH_L4_B_0_1) ||
2432 !(nfc->data & RXH_L4_B_2_3))
2433 return -EINVAL;
2434 break;
2435 case UDP_V4_FLOW:
2436 if (!(nfc->data & RXH_IP_SRC) ||
2437 !(nfc->data & RXH_IP_DST))
2438 return -EINVAL;
2439 switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
2440 case 0:
2441 flags &= ~IGB_FLAG_RSS_FIELD_IPV4_UDP;
2442 break;
2443 case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
2444 flags |= IGB_FLAG_RSS_FIELD_IPV4_UDP;
2445 break;
2446 default:
2447 return -EINVAL;
2448 }
2449 break;
2450 case UDP_V6_FLOW:
2451 if (!(nfc->data & RXH_IP_SRC) ||
2452 !(nfc->data & RXH_IP_DST))
2453 return -EINVAL;
2454 switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
2455 case 0:
2456 flags &= ~IGB_FLAG_RSS_FIELD_IPV6_UDP;
2457 break;
2458 case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
2459 flags |= IGB_FLAG_RSS_FIELD_IPV6_UDP;
2460 break;
2461 default:
2462 return -EINVAL;
2463 }
2464 break;
2465 case AH_ESP_V4_FLOW:
2466 case AH_V4_FLOW:
2467 case ESP_V4_FLOW:
2468 case SCTP_V4_FLOW:
2469 case AH_ESP_V6_FLOW:
2470 case AH_V6_FLOW:
2471 case ESP_V6_FLOW:
2472 case SCTP_V6_FLOW:
2473 if (!(nfc->data & RXH_IP_SRC) ||
2474 !(nfc->data & RXH_IP_DST) ||
2475 (nfc->data & RXH_L4_B_0_1) ||
2476 (nfc->data & RXH_L4_B_2_3))
2477 return -EINVAL;
2478 break;
2479 default:
2480 return -EINVAL;
2481 }
2482
2483 /* if we changed something we need to update flags */
2484 if (flags != adapter->flags) {
2485 struct e1000_hw *hw = &adapter->hw;
2486 u32 mrqc = rd32(E1000_MRQC);
2487
2488 if ((flags & UDP_RSS_FLAGS) &&
2489 !(adapter->flags & UDP_RSS_FLAGS))
2490 dev_err(&adapter->pdev->dev,
2491 "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
2492
2493 adapter->flags = flags;
2494
2495 /* Perform hash on these packet types */
2496 mrqc |= E1000_MRQC_RSS_FIELD_IPV4 |
2497 E1000_MRQC_RSS_FIELD_IPV4_TCP |
2498 E1000_MRQC_RSS_FIELD_IPV6 |
2499 E1000_MRQC_RSS_FIELD_IPV6_TCP;
2500
2501 mrqc &= ~(E1000_MRQC_RSS_FIELD_IPV4_UDP |
2502 E1000_MRQC_RSS_FIELD_IPV6_UDP);
2503
2504 if (flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
2505 mrqc |= E1000_MRQC_RSS_FIELD_IPV4_UDP;
2506
2507 if (flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
2508 mrqc |= E1000_MRQC_RSS_FIELD_IPV6_UDP;
2509
2510 wr32(E1000_MRQC, mrqc);
2511 }
2512
2513 return 0;
2514}
2515
2516static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
2517{
2518 struct igb_adapter *adapter = netdev_priv(dev);
2519 int ret = -EOPNOTSUPP;
2520
2521 switch (cmd->cmd) {
2522 case ETHTOOL_SRXFH:
2523 ret = igb_set_rss_hash_opt(adapter, cmd);
2524 break;
2525 default:
2526 break;
2527 }
2528
2529 return ret;
2530}
2531
2353static int igb_ethtool_begin(struct net_device *netdev) 2532static int igb_ethtool_begin(struct net_device *netdev)
2354{ 2533{
2355 struct igb_adapter *adapter = netdev_priv(netdev); 2534 struct igb_adapter *adapter = netdev_priv(netdev);
@@ -2390,6 +2569,8 @@ static const struct ethtool_ops igb_ethtool_ops = {
2390 .get_coalesce = igb_get_coalesce, 2569 .get_coalesce = igb_get_coalesce,
2391 .set_coalesce = igb_set_coalesce, 2570 .set_coalesce = igb_set_coalesce,
2392 .get_ts_info = igb_get_ts_info, 2571 .get_ts_info = igb_get_ts_info,
2572 .get_rxnfc = igb_get_rxnfc,
2573 .set_rxnfc = igb_set_rxnfc,
2393 .begin = igb_ethtool_begin, 2574 .begin = igb_ethtool_begin,
2394 .complete = igb_ethtool_complete, 2575 .complete = igb_ethtool_complete,
2395}; 2576};