diff options
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 245 | ||||
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 45 |
2 files changed, 290 insertions, 0 deletions
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 649e5960f249..2965b6e7728b 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
| @@ -2456,6 +2456,250 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, | |||
| 2456 | return ret; | 2456 | return ret; |
| 2457 | } | 2457 | } |
| 2458 | 2458 | ||
| 2459 | static int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter, | ||
| 2460 | struct ixgbe_fdir_filter *input, | ||
| 2461 | u16 sw_idx) | ||
| 2462 | { | ||
| 2463 | struct ixgbe_hw *hw = &adapter->hw; | ||
| 2464 | struct hlist_node *node, *node2, *parent; | ||
| 2465 | struct ixgbe_fdir_filter *rule; | ||
| 2466 | int err = -EINVAL; | ||
| 2467 | |||
| 2468 | parent = NULL; | ||
| 2469 | rule = NULL; | ||
| 2470 | |||
| 2471 | hlist_for_each_entry_safe(rule, node, node2, | ||
| 2472 | &adapter->fdir_filter_list, fdir_node) { | ||
| 2473 | /* hash found, or no matching entry */ | ||
| 2474 | if (rule->sw_idx >= sw_idx) | ||
| 2475 | break; | ||
| 2476 | parent = node; | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | /* if there is an old rule occupying our place remove it */ | ||
| 2480 | if (rule && (rule->sw_idx == sw_idx)) { | ||
| 2481 | if (!input || (rule->filter.formatted.bkt_hash != | ||
| 2482 | input->filter.formatted.bkt_hash)) { | ||
| 2483 | err = ixgbe_fdir_erase_perfect_filter_82599(hw, | ||
| 2484 | &rule->filter, | ||
| 2485 | sw_idx); | ||
| 2486 | } | ||
| 2487 | |||
| 2488 | hlist_del(&rule->fdir_node); | ||
| 2489 | kfree(rule); | ||
| 2490 | adapter->fdir_filter_count--; | ||
| 2491 | } | ||
| 2492 | |||
| 2493 | /* | ||
| 2494 | * If no input this was a delete, err should be 0 if a rule was | ||
| 2495 | * successfully found and removed from the list else -EINVAL | ||
| 2496 | */ | ||
| 2497 | if (!input) | ||
| 2498 | return err; | ||
| 2499 | |||
| 2500 | /* initialize node and set software index */ | ||
| 2501 | INIT_HLIST_NODE(&input->fdir_node); | ||
| 2502 | |||
| 2503 | /* add filter to the list */ | ||
| 2504 | if (parent) | ||
| 2505 | hlist_add_after(parent, &input->fdir_node); | ||
| 2506 | else | ||
| 2507 | hlist_add_head(&input->fdir_node, | ||
| 2508 | &adapter->fdir_filter_list); | ||
| 2509 | |||
| 2510 | /* update counts */ | ||
| 2511 | adapter->fdir_filter_count++; | ||
| 2512 | |||
| 2513 | return 0; | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | static int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp, | ||
| 2517 | u8 *flow_type) | ||
| 2518 | { | ||
| 2519 | switch (fsp->flow_type & ~FLOW_EXT) { | ||
| 2520 | case TCP_V4_FLOW: | ||
| 2521 | *flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; | ||
| 2522 | break; | ||
| 2523 | case UDP_V4_FLOW: | ||
| 2524 | *flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; | ||
| 2525 | break; | ||
| 2526 | case SCTP_V4_FLOW: | ||
| 2527 | *flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; | ||
| 2528 | break; | ||
| 2529 | case IP_USER_FLOW: | ||
| 2530 | switch (fsp->h_u.usr_ip4_spec.proto) { | ||
| 2531 | case IPPROTO_TCP: | ||
| 2532 | *flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; | ||
| 2533 | break; | ||
| 2534 | case IPPROTO_UDP: | ||
| 2535 | *flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; | ||
| 2536 | break; | ||
| 2537 | case IPPROTO_SCTP: | ||
| 2538 | *flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; | ||
| 2539 | break; | ||
| 2540 | case 0: | ||
| 2541 | if (!fsp->m_u.usr_ip4_spec.proto) { | ||
| 2542 | *flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; | ||
| 2543 | break; | ||
| 2544 | } | ||
| 2545 | default: | ||
| 2546 | return 0; | ||
| 2547 | } | ||
| 2548 | break; | ||
| 2549 | default: | ||
| 2550 | return 0; | ||
| 2551 | } | ||
| 2552 | |||
| 2553 | return 1; | ||
| 2554 | } | ||
| 2555 | |||
| 2556 | static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter, | ||
| 2557 | struct ethtool_rxnfc *cmd) | ||
| 2558 | { | ||
| 2559 | struct ethtool_rx_flow_spec *fsp = | ||
| 2560 | (struct ethtool_rx_flow_spec *)&cmd->fs; | ||
| 2561 | struct ixgbe_hw *hw = &adapter->hw; | ||
| 2562 | struct ixgbe_fdir_filter *input; | ||
| 2563 | union ixgbe_atr_input mask; | ||
| 2564 | int err; | ||
| 2565 | |||
| 2566 | if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) | ||
| 2567 | return -EOPNOTSUPP; | ||
| 2568 | |||
| 2569 | /* | ||
| 2570 | * Don't allow programming if the action is a queue greater than | ||
| 2571 | * the number of online Rx queues. | ||
| 2572 | */ | ||
| 2573 | if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) && | ||
| 2574 | (fsp->ring_cookie >= adapter->num_rx_queues)) | ||
| 2575 | return -EINVAL; | ||
| 2576 | |||
| 2577 | /* Don't allow indexes to exist outside of available space */ | ||
| 2578 | if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) { | ||
| 2579 | e_err(drv, "Location out of range\n"); | ||
| 2580 | return -EINVAL; | ||
| 2581 | } | ||
| 2582 | |||
| 2583 | input = kzalloc(sizeof(*input), GFP_ATOMIC); | ||
| 2584 | if (!input) | ||
| 2585 | return -ENOMEM; | ||
| 2586 | |||
| 2587 | memset(&mask, 0, sizeof(union ixgbe_atr_input)); | ||
| 2588 | |||
| 2589 | /* set SW index */ | ||
| 2590 | input->sw_idx = fsp->location; | ||
| 2591 | |||
| 2592 | /* record flow type */ | ||
| 2593 | if (!ixgbe_flowspec_to_flow_type(fsp, | ||
| 2594 | &input->filter.formatted.flow_type)) { | ||
| 2595 | e_err(drv, "Unrecognized flow type\n"); | ||
| 2596 | goto err_out; | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK | | ||
| 2600 | IXGBE_ATR_L4TYPE_MASK; | ||
| 2601 | |||
| 2602 | if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4) | ||
| 2603 | mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK; | ||
| 2604 | |||
| 2605 | /* Copy input into formatted structures */ | ||
| 2606 | input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src; | ||
| 2607 | mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src; | ||
| 2608 | input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst; | ||
| 2609 | mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst; | ||
| 2610 | input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc; | ||
| 2611 | mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc; | ||
| 2612 | input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst; | ||
| 2613 | mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst; | ||
| 2614 | |||
| 2615 | if (fsp->flow_type & FLOW_EXT) { | ||
| 2616 | input->filter.formatted.vm_pool = | ||
| 2617 | (unsigned char)ntohl(fsp->h_ext.data[1]); | ||
| 2618 | mask.formatted.vm_pool = | ||
| 2619 | (unsigned char)ntohl(fsp->m_ext.data[1]); | ||
| 2620 | input->filter.formatted.vlan_id = fsp->h_ext.vlan_tci; | ||
| 2621 | mask.formatted.vlan_id = fsp->m_ext.vlan_tci; | ||
| 2622 | input->filter.formatted.flex_bytes = | ||
| 2623 | fsp->h_ext.vlan_etype; | ||
| 2624 | mask.formatted.flex_bytes = fsp->m_ext.vlan_etype; | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | /* determine if we need to drop or route the packet */ | ||
| 2628 | if (fsp->ring_cookie == RX_CLS_FLOW_DISC) | ||
| 2629 | input->action = IXGBE_FDIR_DROP_QUEUE; | ||
| 2630 | else | ||
| 2631 | input->action = fsp->ring_cookie; | ||
| 2632 | |||
| 2633 | spin_lock(&adapter->fdir_perfect_lock); | ||
| 2634 | |||
| 2635 | if (hlist_empty(&adapter->fdir_filter_list)) { | ||
| 2636 | /* save mask and program input mask into HW */ | ||
| 2637 | memcpy(&adapter->fdir_mask, &mask, sizeof(mask)); | ||
| 2638 | err = ixgbe_fdir_set_input_mask_82599(hw, &mask); | ||
| 2639 | if (err) { | ||
| 2640 | e_err(drv, "Error writing mask\n"); | ||
| 2641 | goto err_out_w_lock; | ||
| 2642 | } | ||
| 2643 | } else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) { | ||
| 2644 | e_err(drv, "Only one mask supported per port\n"); | ||
| 2645 | goto err_out_w_lock; | ||
| 2646 | } | ||
| 2647 | |||
| 2648 | /* apply mask and compute/store hash */ | ||
| 2649 | ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask); | ||
| 2650 | |||
| 2651 | /* program filters to filter memory */ | ||
| 2652 | err = ixgbe_fdir_write_perfect_filter_82599(hw, | ||
| 2653 | &input->filter, input->sw_idx, | ||
| 2654 | adapter->rx_ring[input->action]->reg_idx); | ||
| 2655 | if (err) | ||
| 2656 | goto err_out_w_lock; | ||
| 2657 | |||
| 2658 | ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx); | ||
| 2659 | |||
| 2660 | spin_unlock(&adapter->fdir_perfect_lock); | ||
| 2661 | |||
| 2662 | return err; | ||
| 2663 | err_out_w_lock: | ||
| 2664 | spin_unlock(&adapter->fdir_perfect_lock); | ||
| 2665 | err_out: | ||
| 2666 | kfree(input); | ||
| 2667 | return -EINVAL; | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | static int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter, | ||
| 2671 | struct ethtool_rxnfc *cmd) | ||
| 2672 | { | ||
| 2673 | struct ethtool_rx_flow_spec *fsp = | ||
| 2674 | (struct ethtool_rx_flow_spec *)&cmd->fs; | ||
| 2675 | int err; | ||
| 2676 | |||
| 2677 | spin_lock(&adapter->fdir_perfect_lock); | ||
| 2678 | err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location); | ||
| 2679 | spin_unlock(&adapter->fdir_perfect_lock); | ||
| 2680 | |||
| 2681 | return err; | ||
| 2682 | } | ||
| 2683 | |||
| 2684 | static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) | ||
| 2685 | { | ||
| 2686 | struct ixgbe_adapter *adapter = netdev_priv(dev); | ||
| 2687 | int ret = -EOPNOTSUPP; | ||
| 2688 | |||
| 2689 | switch (cmd->cmd) { | ||
| 2690 | case ETHTOOL_SRXCLSRLINS: | ||
| 2691 | ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd); | ||
| 2692 | break; | ||
| 2693 | case ETHTOOL_SRXCLSRLDEL: | ||
| 2694 | ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd); | ||
| 2695 | break; | ||
| 2696 | default: | ||
| 2697 | break; | ||
| 2698 | } | ||
| 2699 | |||
| 2700 | return ret; | ||
| 2701 | } | ||
| 2702 | |||
| 2459 | static const struct ethtool_ops ixgbe_ethtool_ops = { | 2703 | static const struct ethtool_ops ixgbe_ethtool_ops = { |
| 2460 | .get_settings = ixgbe_get_settings, | 2704 | .get_settings = ixgbe_get_settings, |
| 2461 | .set_settings = ixgbe_set_settings, | 2705 | .set_settings = ixgbe_set_settings, |
| @@ -2492,6 +2736,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { | |||
| 2492 | .get_flags = ethtool_op_get_flags, | 2736 | .get_flags = ethtool_op_get_flags, |
| 2493 | .set_flags = ixgbe_set_flags, | 2737 | .set_flags = ixgbe_set_flags, |
| 2494 | .get_rxnfc = ixgbe_get_rxnfc, | 2738 | .get_rxnfc = ixgbe_get_rxnfc, |
| 2739 | .set_rxnfc = ixgbe_set_rxnfc, | ||
| 2495 | }; | 2740 | }; |
| 2496 | 2741 | ||
| 2497 | void ixgbe_set_ethtool_ops(struct net_device *netdev) | 2742 | void ixgbe_set_ethtool_ops(struct net_device *netdev) |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e177b5d061fe..2886daec70ae 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
| @@ -3741,6 +3741,28 @@ static void ixgbe_configure_pb(struct ixgbe_adapter *adapter) | |||
| 3741 | hw->mac.ops.set_rxpba(&adapter->hw, num_tc, hdrm, PBA_STRATEGY_EQUAL); | 3741 | hw->mac.ops.set_rxpba(&adapter->hw, num_tc, hdrm, PBA_STRATEGY_EQUAL); |
| 3742 | } | 3742 | } |
| 3743 | 3743 | ||
| 3744 | static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) | ||
| 3745 | { | ||
| 3746 | struct ixgbe_hw *hw = &adapter->hw; | ||
| 3747 | struct hlist_node *node, *node2; | ||
| 3748 | struct ixgbe_fdir_filter *filter; | ||
| 3749 | |||
| 3750 | spin_lock(&adapter->fdir_perfect_lock); | ||
| 3751 | |||
| 3752 | if (!hlist_empty(&adapter->fdir_filter_list)) | ||
| 3753 | ixgbe_fdir_set_input_mask_82599(hw, &adapter->fdir_mask); | ||
| 3754 | |||
| 3755 | hlist_for_each_entry_safe(filter, node, node2, | ||
| 3756 | &adapter->fdir_filter_list, fdir_node) { | ||
| 3757 | ixgbe_fdir_write_perfect_filter_82599(hw, | ||
| 3758 | &filter->filter, | ||
| 3759 | filter->sw_idx, | ||
| 3760 | filter->action); | ||
| 3761 | } | ||
| 3762 | |||
| 3763 | spin_unlock(&adapter->fdir_perfect_lock); | ||
| 3764 | } | ||
| 3765 | |||
| 3744 | static void ixgbe_configure(struct ixgbe_adapter *adapter) | 3766 | static void ixgbe_configure(struct ixgbe_adapter *adapter) |
| 3745 | { | 3767 | { |
| 3746 | struct net_device *netdev = adapter->netdev; | 3768 | struct net_device *netdev = adapter->netdev; |
| @@ -3765,6 +3787,10 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) | |||
| 3765 | adapter->tx_ring[i]->atr_sample_rate = | 3787 | adapter->tx_ring[i]->atr_sample_rate = |
| 3766 | adapter->atr_sample_rate; | 3788 | adapter->atr_sample_rate; |
| 3767 | ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); | 3789 | ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); |
| 3790 | } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) { | ||
| 3791 | ixgbe_init_fdir_perfect_82599(&adapter->hw, | ||
| 3792 | adapter->fdir_pballoc); | ||
| 3793 | ixgbe_fdir_filter_restore(adapter); | ||
| 3768 | } | 3794 | } |
| 3769 | ixgbe_configure_virtualization(adapter); | 3795 | ixgbe_configure_virtualization(adapter); |
| 3770 | 3796 | ||
| @@ -4141,6 +4167,23 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter) | |||
| 4141 | ixgbe_clean_tx_ring(adapter->tx_ring[i]); | 4167 | ixgbe_clean_tx_ring(adapter->tx_ring[i]); |
| 4142 | } | 4168 | } |
| 4143 | 4169 | ||
| 4170 | static void ixgbe_fdir_filter_exit(struct ixgbe_adapter *adapter) | ||
| 4171 | { | ||
| 4172 | struct hlist_node *node, *node2; | ||
| 4173 | struct ixgbe_fdir_filter *filter; | ||
| 4174 | |||
| 4175 | spin_lock(&adapter->fdir_perfect_lock); | ||
| 4176 | |||
| 4177 | hlist_for_each_entry_safe(filter, node, node2, | ||
| 4178 | &adapter->fdir_filter_list, fdir_node) { | ||
| 4179 | hlist_del(&filter->fdir_node); | ||
| 4180 | kfree(filter); | ||
| 4181 | } | ||
| 4182 | adapter->fdir_filter_count = 0; | ||
| 4183 | |||
| 4184 | spin_unlock(&adapter->fdir_perfect_lock); | ||
| 4185 | } | ||
| 4186 | |||
| 4144 | void ixgbe_down(struct ixgbe_adapter *adapter) | 4187 | void ixgbe_down(struct ixgbe_adapter *adapter) |
| 4145 | { | 4188 | { |
| 4146 | struct net_device *netdev = adapter->netdev; | 4189 | struct net_device *netdev = adapter->netdev; |
| @@ -5527,6 +5570,8 @@ static int ixgbe_close(struct net_device *netdev) | |||
| 5527 | ixgbe_down(adapter); | 5570 | ixgbe_down(adapter); |
| 5528 | ixgbe_free_irq(adapter); | 5571 | ixgbe_free_irq(adapter); |
| 5529 | 5572 | ||
| 5573 | ixgbe_fdir_filter_exit(adapter); | ||
| 5574 | |||
| 5530 | ixgbe_free_all_tx_resources(adapter); | 5575 | ixgbe_free_all_tx_resources(adapter); |
| 5531 | ixgbe_free_all_rx_resources(adapter); | 5576 | ixgbe_free_all_rx_resources(adapter); |
| 5532 | 5577 | ||
