diff options
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 181 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 13 |
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 | ||
2353 | static 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 | |||
2391 | static 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) | ||
2414 | static 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 | |||
2516 | static 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 | |||
2353 | static int igb_ethtool_begin(struct net_device *netdev) | 2532 | static 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 */ |