aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel
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
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')
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h14
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c181
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c13
3 files changed, 197 insertions, 11 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 796db53954d9..b23a6678acc9 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -386,12 +386,14 @@ struct igb_adapter {
386 char fw_version[32]; 386 char fw_version[32];
387}; 387};
388 388
389#define IGB_FLAG_HAS_MSI (1 << 0) 389#define IGB_FLAG_HAS_MSI (1 << 0)
390#define IGB_FLAG_DCA_ENABLED (1 << 1) 390#define IGB_FLAG_DCA_ENABLED (1 << 1)
391#define IGB_FLAG_QUAD_PORT_A (1 << 2) 391#define IGB_FLAG_QUAD_PORT_A (1 << 2)
392#define IGB_FLAG_QUEUE_PAIRS (1 << 3) 392#define IGB_FLAG_QUEUE_PAIRS (1 << 3)
393#define IGB_FLAG_DMAC (1 << 4) 393#define IGB_FLAG_DMAC (1 << 4)
394#define IGB_FLAG_PTP (1 << 5) 394#define IGB_FLAG_PTP (1 << 5)
395#define IGB_FLAG_RSS_FIELD_IPV4_UDP (1 << 6)
396#define IGB_FLAG_RSS_FIELD_IPV6_UDP (1 << 7)
395 397
396/* DMA Coalescing defines */ 398/* DMA Coalescing defines */
397#define IGB_MIN_TXPBSIZE 20408 399#define IGB_MIN_TXPBSIZE 20408
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};
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 082ce73dc627..da9fd7b8e23a 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2874,18 +2874,21 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
2874 2874
2875 /* Don't need to set TUOFL or IPOFL, they default to 1 */ 2875 /* Don't need to set TUOFL or IPOFL, they default to 1 */
2876 wr32(E1000_RXCSUM, rxcsum); 2876 wr32(E1000_RXCSUM, rxcsum);
2877 /*
2878 * Generate RSS hash based on TCP port numbers and/or
2879 * IPv4/v6 src and dst addresses since UDP cannot be
2880 * hashed reliably due to IP fragmentation
2881 */
2882 2877
2878 /* Generate RSS hash based on packet types, TCP/UDP
2879 * port numbers and/or IPv4/v6 src and dst addresses
2880 */
2883 mrqc = E1000_MRQC_RSS_FIELD_IPV4 | 2881 mrqc = E1000_MRQC_RSS_FIELD_IPV4 |
2884 E1000_MRQC_RSS_FIELD_IPV4_TCP | 2882 E1000_MRQC_RSS_FIELD_IPV4_TCP |
2885 E1000_MRQC_RSS_FIELD_IPV6 | 2883 E1000_MRQC_RSS_FIELD_IPV6 |
2886 E1000_MRQC_RSS_FIELD_IPV6_TCP | 2884 E1000_MRQC_RSS_FIELD_IPV6_TCP |
2887 E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; 2885 E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;
2888 2886
2887 if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)
2888 mrqc |= E1000_MRQC_RSS_FIELD_IPV4_UDP;
2889 if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)
2890 mrqc |= E1000_MRQC_RSS_FIELD_IPV6_UDP;
2891
2889 /* If VMDq is enabled then we set the appropriate mode for that, else 2892 /* If VMDq is enabled then we set the appropriate mode for that, else
2890 * we default to RSS so that an RSS hash is calculated per packet even 2893 * we default to RSS so that an RSS hash is calculated per packet even
2891 * if we are only using one queue */ 2894 * if we are only using one queue */