Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sfc: support RSS spreading of ethtool ntuple filters

Use a linked list to associate user-facing context IDs with FW-facing
context IDs (since the latter can change after an MC reset).

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Edward Cree and committed by
David S. Miller
42356d9a 84a1d9c4

+443 -150
+181 -92
drivers/net/ethernet/sfc/ef10.c
··· 28 28 EFX_EF10_TEST = 1, 29 29 EFX_EF10_REFILL, 30 30 }; 31 - 32 - /* The reserved RSS context value */ 33 - #define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff 34 31 /* The maximum size of a shared RSS context */ 35 32 /* TODO: this should really be from the mcdi protocol export */ 36 33 #define EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE 64UL ··· 694 697 } 695 698 nic_data->warm_boot_count = rc; 696 699 697 - nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; 700 + efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID; 698 701 699 702 nic_data->vport_id = EVB_PORT_ID_ASSIGNED; 700 703 ··· 1486 1489 } 1487 1490 1488 1491 /* don't fail init if RSS setup doesn't work */ 1489 - rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table, NULL); 1490 - efx->rss_active = (rc == 0); 1492 + rc = efx->type->rx_push_rss_config(efx, false, 1493 + efx->rss_context.rx_indir_table, NULL); 1491 1494 1492 1495 return 0; 1493 1496 } ··· 1504 1507 nic_data->must_restore_filters = true; 1505 1508 nic_data->must_restore_piobufs = true; 1506 1509 efx_ef10_forget_old_piobufs(efx); 1507 - nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; 1510 + efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID; 1508 1511 1509 1512 /* Driver-created vswitches and vports must be re-created */ 1510 1513 nic_data->must_probe_vswitching = true; ··· 2700 2703 * Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we 2701 2704 * just need to set the UDP ports flags (for both IP versions). 2702 2705 */ 2703 - static void efx_ef10_set_rss_flags(struct efx_nic *efx, u32 context) 2706 + static void efx_ef10_set_rss_flags(struct efx_nic *efx, 2707 + struct efx_rss_context *ctx) 2704 2708 { 2705 2709 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN); 2706 2710 u32 flags; 2707 2711 2708 2712 BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN != 0); 2709 2713 2710 - if (efx_ef10_get_rss_flags(efx, context, &flags) != 0) 2714 + if (efx_ef10_get_rss_flags(efx, ctx->context_id, &flags) != 0) 2711 2715 return; 2712 - MCDI_SET_DWORD(inbuf, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, context); 2716 + MCDI_SET_DWORD(inbuf, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, 2717 + ctx->context_id); 2713 2718 flags |= RSS_MODE_HASH_PORTS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_LBN; 2714 2719 flags |= RSS_MODE_HASH_PORTS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN; 2715 2720 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, flags); 2716 2721 if (!efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_FLAGS, inbuf, sizeof(inbuf), 2717 2722 NULL, 0, NULL)) 2718 2723 /* Succeeded, so UDP 4-tuple is now enabled */ 2719 - efx->rx_hash_udp_4tuple = true; 2724 + ctx->rx_hash_udp_4tuple = true; 2720 2725 } 2721 2726 2722 - static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context, 2723 - bool exclusive, unsigned *context_size) 2727 + static int efx_ef10_alloc_rss_context(struct efx_nic *efx, bool exclusive, 2728 + struct efx_rss_context *ctx, 2729 + unsigned *context_size) 2724 2730 { 2725 2731 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); 2726 2732 MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN); ··· 2739 2739 EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE); 2740 2740 2741 2741 if (!exclusive && rss_spread == 1) { 2742 - *context = EFX_EF10_RSS_CONTEXT_INVALID; 2742 + ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID; 2743 2743 if (context_size) 2744 2744 *context_size = 1; 2745 2745 return 0; ··· 2762 2762 if (outlen < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) 2763 2763 return -EIO; 2764 2764 2765 - *context = MCDI_DWORD(outbuf, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); 2765 + ctx->context_id = MCDI_DWORD(outbuf, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); 2766 2766 2767 2767 if (context_size) 2768 2768 *context_size = rss_spread; 2769 2769 2770 2770 if (nic_data->datapath_caps & 2771 2771 1 << MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_LBN) 2772 - efx_ef10_set_rss_flags(efx, *context); 2772 + efx_ef10_set_rss_flags(efx, ctx); 2773 2773 2774 2774 return 0; 2775 2775 } 2776 2776 2777 - static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context) 2777 + static int efx_ef10_free_rss_context(struct efx_nic *efx, u32 context) 2778 2778 { 2779 2779 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_FREE_IN_LEN); 2780 - int rc; 2781 2780 2782 2781 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, 2783 2782 context); 2784 - 2785 - rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_FREE, inbuf, sizeof(inbuf), 2783 + return efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_FREE, inbuf, sizeof(inbuf), 2786 2784 NULL, 0, NULL); 2787 - WARN_ON(rc != 0); 2788 2785 } 2789 2786 2790 2787 static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, ··· 2793 2796 2794 2797 MCDI_SET_DWORD(tablebuf, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID, 2795 2798 context); 2796 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != 2799 + BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_indir_table) != 2797 2800 MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN); 2798 2801 2799 - /* This iterates over the length of efx->rx_indir_table, but copies 2800 - * bytes from rx_indir_table. That's because the latter is a pointer 2801 - * rather than an array, but should have the same length. 2802 - * The efx->rx_hash_key loop below is similar. 2802 + /* This iterates over the length of efx->rss_context.rx_indir_table, but 2803 + * copies bytes from rx_indir_table. That's because the latter is a 2804 + * pointer rather than an array, but should have the same length. 2805 + * The efx->rss_context.rx_hash_key loop below is similar. 2803 2806 */ 2804 - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i) 2807 + for (i = 0; i < ARRAY_SIZE(efx->rss_context.rx_indir_table); ++i) 2805 2808 MCDI_PTR(tablebuf, 2806 2809 RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] = 2807 2810 (u8) rx_indir_table[i]; ··· 2813 2816 2814 2817 MCDI_SET_DWORD(keybuf, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID, 2815 2818 context); 2816 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) != 2819 + BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_hash_key) != 2817 2820 MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); 2818 - for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i) 2821 + for (i = 0; i < ARRAY_SIZE(efx->rss_context.rx_hash_key); ++i) 2819 2822 MCDI_PTR(keybuf, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY)[i] = key[i]; 2820 2823 2821 2824 return efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_KEY, keybuf, ··· 2824 2827 2825 2828 static void efx_ef10_rx_free_indir_table(struct efx_nic *efx) 2826 2829 { 2827 - struct efx_ef10_nic_data *nic_data = efx->nic_data; 2830 + int rc; 2828 2831 2829 - if (nic_data->rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID) 2830 - efx_ef10_free_rss_context(efx, nic_data->rx_rss_context); 2831 - nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; 2832 + if (efx->rss_context.context_id != EFX_EF10_RSS_CONTEXT_INVALID) { 2833 + rc = efx_ef10_free_rss_context(efx, efx->rss_context.context_id); 2834 + WARN_ON(rc != 0); 2835 + } 2836 + efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID; 2832 2837 } 2833 2838 2834 2839 static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx, 2835 2840 unsigned *context_size) 2836 2841 { 2837 - u32 new_rx_rss_context; 2838 2842 struct efx_ef10_nic_data *nic_data = efx->nic_data; 2839 - int rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, 2840 - false, context_size); 2843 + int rc = efx_ef10_alloc_rss_context(efx, false, &efx->rss_context, 2844 + context_size); 2841 2845 2842 2846 if (rc != 0) 2843 2847 return rc; 2844 2848 2845 - nic_data->rx_rss_context = new_rx_rss_context; 2846 2849 nic_data->rx_rss_context_exclusive = false; 2847 - efx_set_default_rx_indir_table(efx); 2850 + efx_set_default_rx_indir_table(efx, &efx->rss_context); 2848 2851 return 0; 2849 2852 } 2850 2853 ··· 2852 2855 const u32 *rx_indir_table, 2853 2856 const u8 *key) 2854 2857 { 2858 + u32 old_rx_rss_context = efx->rss_context.context_id; 2855 2859 struct efx_ef10_nic_data *nic_data = efx->nic_data; 2856 2860 int rc; 2857 - u32 new_rx_rss_context; 2858 2861 2859 - if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID || 2862 + if (efx->rss_context.context_id == EFX_EF10_RSS_CONTEXT_INVALID || 2860 2863 !nic_data->rx_rss_context_exclusive) { 2861 - rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, 2862 - true, NULL); 2864 + rc = efx_ef10_alloc_rss_context(efx, true, &efx->rss_context, 2865 + NULL); 2863 2866 if (rc == -EOPNOTSUPP) 2864 2867 return rc; 2865 2868 else if (rc != 0) 2866 2869 goto fail1; 2867 - } else { 2868 - new_rx_rss_context = nic_data->rx_rss_context; 2869 2870 } 2870 2871 2871 - rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context, 2872 + rc = efx_ef10_populate_rss_table(efx, efx->rss_context.context_id, 2872 2873 rx_indir_table, key); 2873 2874 if (rc != 0) 2874 2875 goto fail2; 2875 2876 2876 - if (nic_data->rx_rss_context != new_rx_rss_context) 2877 - efx_ef10_rx_free_indir_table(efx); 2878 - nic_data->rx_rss_context = new_rx_rss_context; 2877 + if (efx->rss_context.context_id != old_rx_rss_context && 2878 + old_rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID) 2879 + WARN_ON(efx_ef10_free_rss_context(efx, old_rx_rss_context) != 0); 2879 2880 nic_data->rx_rss_context_exclusive = true; 2880 - if (rx_indir_table != efx->rx_indir_table) 2881 - memcpy(efx->rx_indir_table, rx_indir_table, 2882 - sizeof(efx->rx_indir_table)); 2883 - if (key != efx->rx_hash_key) 2884 - memcpy(efx->rx_hash_key, key, efx->type->rx_hash_key_size); 2881 + if (rx_indir_table != efx->rss_context.rx_indir_table) 2882 + memcpy(efx->rss_context.rx_indir_table, rx_indir_table, 2883 + sizeof(efx->rss_context.rx_indir_table)); 2884 + if (key != efx->rss_context.rx_hash_key) 2885 + memcpy(efx->rss_context.rx_hash_key, key, 2886 + efx->type->rx_hash_key_size); 2885 2887 2886 2888 return 0; 2887 2889 2888 2890 fail2: 2889 - if (new_rx_rss_context != nic_data->rx_rss_context) 2890 - efx_ef10_free_rss_context(efx, new_rx_rss_context); 2891 + if (old_rx_rss_context != efx->rss_context.context_id) { 2892 + WARN_ON(efx_ef10_free_rss_context(efx, efx->rss_context.context_id) != 0); 2893 + efx->rss_context.context_id = old_rx_rss_context; 2894 + } 2891 2895 fail1: 2892 2896 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 2893 2897 return rc; 2894 2898 } 2895 2899 2896 - static int efx_ef10_rx_pull_rss_config(struct efx_nic *efx) 2900 + static int efx_ef10_rx_push_rss_context_config(struct efx_nic *efx, 2901 + struct efx_rss_context *ctx, 2902 + const u32 *rx_indir_table, 2903 + const u8 *key) 2897 2904 { 2898 - struct efx_ef10_nic_data *nic_data = efx->nic_data; 2905 + int rc; 2906 + 2907 + if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) { 2908 + rc = efx_ef10_alloc_rss_context(efx, true, ctx, NULL); 2909 + if (rc) 2910 + return rc; 2911 + } 2912 + 2913 + if (!rx_indir_table) /* Delete this context */ 2914 + return efx_ef10_free_rss_context(efx, ctx->context_id); 2915 + 2916 + rc = efx_ef10_populate_rss_table(efx, ctx->context_id, 2917 + rx_indir_table, key); 2918 + if (rc) 2919 + return rc; 2920 + 2921 + memcpy(ctx->rx_indir_table, rx_indir_table, 2922 + sizeof(efx->rss_context.rx_indir_table)); 2923 + memcpy(ctx->rx_hash_key, key, efx->type->rx_hash_key_size); 2924 + 2925 + return 0; 2926 + } 2927 + 2928 + static int efx_ef10_rx_pull_rss_context_config(struct efx_nic *efx, 2929 + struct efx_rss_context *ctx) 2930 + { 2899 2931 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN); 2900 2932 MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_LEN); 2901 2933 MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_GET_KEY_OUT_LEN); ··· 2934 2908 BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN != 2935 2909 MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN); 2936 2910 2937 - if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID) 2911 + if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) 2938 2912 return -ENOENT; 2939 2913 2940 2914 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID, 2941 - nic_data->rx_rss_context); 2942 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != 2915 + ctx->context_id); 2916 + BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_indir_table) != 2943 2917 MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN); 2944 2918 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf), 2945 2919 tablebuf, sizeof(tablebuf), &outlen); ··· 2949 2923 if (WARN_ON(outlen != MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_LEN)) 2950 2924 return -EIO; 2951 2925 2952 - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 2953 - efx->rx_indir_table[i] = MCDI_PTR(tablebuf, 2926 + for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++) 2927 + ctx->rx_indir_table[i] = MCDI_PTR(tablebuf, 2954 2928 RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i]; 2955 2929 2956 2930 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID, 2957 - nic_data->rx_rss_context); 2958 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) != 2931 + ctx->context_id); 2932 + BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_hash_key) != 2959 2933 MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); 2960 2934 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf), 2961 2935 keybuf, sizeof(keybuf), &outlen); ··· 2965 2939 if (WARN_ON(outlen != MC_CMD_RSS_CONTEXT_GET_KEY_OUT_LEN)) 2966 2940 return -EIO; 2967 2941 2968 - for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i) 2969 - efx->rx_hash_key[i] = MCDI_PTR( 2942 + for (i = 0; i < ARRAY_SIZE(ctx->rx_hash_key); ++i) 2943 + ctx->rx_hash_key[i] = MCDI_PTR( 2970 2944 keybuf, RSS_CONTEXT_GET_KEY_OUT_TOEPLITZ_KEY)[i]; 2971 2945 2972 2946 return 0; 2947 + } 2948 + 2949 + static int efx_ef10_rx_pull_rss_config(struct efx_nic *efx) 2950 + { 2951 + return efx_ef10_rx_pull_rss_context_config(efx, &efx->rss_context); 2952 + } 2953 + 2954 + static void efx_ef10_rx_restore_rss_contexts(struct efx_nic *efx) 2955 + { 2956 + struct efx_rss_context *ctx; 2957 + int rc; 2958 + 2959 + list_for_each_entry(ctx, &efx->rss_context.list, list) { 2960 + /* previous NIC RSS context is gone */ 2961 + ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID; 2962 + /* so try to allocate a new one */ 2963 + rc = efx_ef10_rx_push_rss_context_config(efx, ctx, 2964 + ctx->rx_indir_table, 2965 + ctx->rx_hash_key); 2966 + if (rc) 2967 + netif_warn(efx, probe, efx->net_dev, 2968 + "failed to restore RSS context %u, rc=%d" 2969 + "; RSS filters may fail to be applied\n", 2970 + ctx->user_id, rc); 2971 + } 2973 2972 } 2974 2973 2975 2974 static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user, ··· 3007 2956 return 0; 3008 2957 3009 2958 if (!key) 3010 - key = efx->rx_hash_key; 2959 + key = efx->rss_context.rx_hash_key; 3011 2960 3012 2961 rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table, key); 3013 2962 ··· 3016 2965 bool mismatch = false; 3017 2966 size_t i; 3018 2967 3019 - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table) && !mismatch; 2968 + for (i = 0; 2969 + i < ARRAY_SIZE(efx->rss_context.rx_indir_table) && !mismatch; 3020 2970 i++) 3021 2971 mismatch = rx_indir_table[i] != 3022 2972 ethtool_rxfh_indir_default(i, efx->rss_spread); ··· 3052 3000 const u8 *key 3053 3001 __attribute__ ((unused))) 3054 3002 { 3055 - struct efx_ef10_nic_data *nic_data = efx->nic_data; 3056 - 3057 3003 if (user) 3058 3004 return -EOPNOTSUPP; 3059 - if (nic_data->rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID) 3005 + if (efx->rss_context.context_id != EFX_EF10_RSS_CONTEXT_INVALID) 3060 3006 return 0; 3061 3007 return efx_ef10_rx_push_shared_rss_config(efx, NULL); 3062 3008 } ··· 4159 4109 static void efx_ef10_filter_push_prep(struct efx_nic *efx, 4160 4110 const struct efx_filter_spec *spec, 4161 4111 efx_dword_t *inbuf, u64 handle, 4112 + struct efx_rss_context *ctx, 4162 4113 bool replacing) 4163 4114 { 4164 4115 struct efx_ef10_nic_data *nic_data = efx->nic_data; ··· 4167 4116 4168 4117 memset(inbuf, 0, MC_CMD_FILTER_OP_EXT_IN_LEN); 4169 4118 4170 - /* Remove RSS flag if we don't have an RSS context. */ 4171 - if (flags & EFX_FILTER_FLAG_RX_RSS && 4172 - spec->rss_context == EFX_FILTER_RSS_CONTEXT_DEFAULT && 4173 - nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID) 4174 - flags &= ~EFX_FILTER_FLAG_RX_RSS; 4119 + /* If RSS filter, caller better have given us an RSS context */ 4120 + if (flags & EFX_FILTER_FLAG_RX_RSS) { 4121 + /* We don't have the ability to return an error, so we'll just 4122 + * log a warning and disable RSS for the filter. 4123 + */ 4124 + if (WARN_ON_ONCE(!ctx)) 4125 + flags &= ~EFX_FILTER_FLAG_RX_RSS; 4126 + else if (WARN_ON_ONCE(ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID)) 4127 + flags &= ~EFX_FILTER_FLAG_RX_RSS; 4128 + } 4175 4129 4176 4130 if (replacing) { 4177 4131 MCDI_SET_DWORD(inbuf, FILTER_OP_IN_OP, ··· 4202 4146 MC_CMD_FILTER_OP_IN_RX_MODE_RSS : 4203 4147 MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); 4204 4148 if (flags & EFX_FILTER_FLAG_RX_RSS) 4205 - MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_CONTEXT, 4206 - spec->rss_context != 4207 - EFX_FILTER_RSS_CONTEXT_DEFAULT ? 4208 - spec->rss_context : nic_data->rx_rss_context); 4149 + MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_CONTEXT, ctx->context_id); 4209 4150 } 4210 4151 4211 4152 static int efx_ef10_filter_push(struct efx_nic *efx, 4212 - const struct efx_filter_spec *spec, 4213 - u64 *handle, bool replacing) 4153 + const struct efx_filter_spec *spec, u64 *handle, 4154 + struct efx_rss_context *ctx, bool replacing) 4214 4155 { 4215 4156 MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN); 4216 4157 MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN); 4217 4158 int rc; 4218 4159 4219 - efx_ef10_filter_push_prep(efx, spec, inbuf, *handle, replacing); 4160 + efx_ef10_filter_push_prep(efx, spec, inbuf, *handle, ctx, replacing); 4220 4161 rc = efx_mcdi_rpc(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf), 4221 4162 outbuf, sizeof(outbuf), NULL); 4222 4163 if (rc == 0) ··· 4305 4252 struct efx_ef10_filter_table *table = efx->filter_state; 4306 4253 DECLARE_BITMAP(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); 4307 4254 struct efx_filter_spec *saved_spec; 4255 + struct efx_rss_context *ctx = NULL; 4308 4256 unsigned int match_pri, hash; 4309 4257 unsigned int priv_flags; 4310 4258 bool replacing = false; ··· 4328 4274 is_mc_recip = efx_filter_is_mc_recipient(spec); 4329 4275 if (is_mc_recip) 4330 4276 bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); 4277 + 4278 + if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { 4279 + if (spec->rss_context) 4280 + ctx = efx_find_rss_context_entry(spec->rss_context, 4281 + &efx->rss_context.list); 4282 + else 4283 + ctx = &efx->rss_context; 4284 + if (!ctx) 4285 + return -ENOENT; 4286 + if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) 4287 + return -EOPNOTSUPP; 4288 + } 4331 4289 4332 4290 /* Find any existing filters with the same match tuple or 4333 4291 * else a free slot to insert at. If any of them are busy, ··· 4456 4390 spin_unlock_bh(&efx->filter_lock); 4457 4391 4458 4392 rc = efx_ef10_filter_push(efx, spec, &table->entry[ins_index].handle, 4459 - replacing); 4393 + ctx, replacing); 4460 4394 4461 4395 /* Finalise the software table entry */ 4462 4396 spin_lock_bh(&efx->filter_lock); ··· 4600 4534 4601 4535 new_spec.priority = EFX_FILTER_PRI_AUTO; 4602 4536 new_spec.flags = (EFX_FILTER_FLAG_RX | 4603 - (efx_rss_enabled(efx) ? 4537 + (efx_rss_active(&efx->rss_context) ? 4604 4538 EFX_FILTER_FLAG_RX_RSS : 0)); 4605 4539 new_spec.dmaq_id = 0; 4606 - new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT; 4540 + new_spec.rss_context = 0; 4607 4541 rc = efx_ef10_filter_push(efx, &new_spec, 4608 4542 &table->entry[filter_idx].handle, 4543 + &efx->rss_context, 4609 4544 true); 4610 4545 4611 4546 spin_lock_bh(&efx->filter_lock); ··· 4850 4783 cookie = replacing << 31 | ins_index << 16 | spec->dmaq_id; 4851 4784 4852 4785 efx_ef10_filter_push_prep(efx, spec, inbuf, 4853 - table->entry[ins_index].handle, replacing); 4786 + table->entry[ins_index].handle, NULL, 4787 + replacing); 4854 4788 efx_mcdi_rpc_async(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf), 4855 4789 MC_CMD_FILTER_OP_OUT_LEN, 4856 4790 efx_ef10_filter_rfs_insert_complete, cookie); ··· 5172 5104 unsigned int invalid_filters = 0, failed = 0; 5173 5105 struct efx_ef10_filter_vlan *vlan; 5174 5106 struct efx_filter_spec *spec; 5107 + struct efx_rss_context *ctx; 5175 5108 unsigned int filter_idx; 5176 5109 u32 mcdi_flags; 5177 5110 int match_pri; ··· 5202 5133 invalid_filters++; 5203 5134 goto not_restored; 5204 5135 } 5205 - if (spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT && 5206 - spec->rss_context != nic_data->rx_rss_context) 5207 - netif_warn(efx, drv, efx->net_dev, 5208 - "Warning: unable to restore a filter with specific RSS context.\n"); 5136 + if (spec->rss_context) 5137 + ctx = efx_find_rss_context_entry(spec->rss_context, 5138 + &efx->rss_context.list); 5139 + else 5140 + ctx = &efx->rss_context; 5141 + if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { 5142 + if (!ctx) { 5143 + netif_warn(efx, drv, efx->net_dev, 5144 + "Warning: unable to restore a filter with nonexistent RSS context %u.\n", 5145 + spec->rss_context); 5146 + invalid_filters++; 5147 + goto not_restored; 5148 + } 5149 + if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) { 5150 + netif_warn(efx, drv, efx->net_dev, 5151 + "Warning: unable to restore a filter with RSS context %u as it was not created.\n", 5152 + spec->rss_context); 5153 + invalid_filters++; 5154 + goto not_restored; 5155 + } 5156 + } 5209 5157 5210 5158 table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_BUSY; 5211 5159 spin_unlock_bh(&efx->filter_lock); 5212 5160 5213 5161 rc = efx_ef10_filter_push(efx, spec, 5214 5162 &table->entry[filter_idx].handle, 5215 - false); 5163 + ctx, false); 5216 5164 if (rc) 5217 5165 failed++; 5218 5166 spin_lock_bh(&efx->filter_lock); ··· 6870 6784 .tx_limit_len = efx_ef10_tx_limit_len, 6871 6785 .rx_push_rss_config = efx_ef10_pf_rx_push_rss_config, 6872 6786 .rx_pull_rss_config = efx_ef10_rx_pull_rss_config, 6787 + .rx_push_rss_context_config = efx_ef10_rx_push_rss_context_config, 6788 + .rx_pull_rss_context_config = efx_ef10_rx_pull_rss_context_config, 6789 + .rx_restore_rss_contexts = efx_ef10_rx_restore_rss_contexts, 6873 6790 .rx_probe = efx_ef10_rx_probe, 6874 6791 .rx_init = efx_ef10_rx_init, 6875 6792 .rx_remove = efx_ef10_rx_remove,
+59 -6
drivers/net/ethernet/sfc/efx.c
··· 1353 1353 pci_disable_device(efx->pci_dev); 1354 1354 } 1355 1355 1356 - void efx_set_default_rx_indir_table(struct efx_nic *efx) 1356 + void efx_set_default_rx_indir_table(struct efx_nic *efx, 1357 + struct efx_rss_context *ctx) 1357 1358 { 1358 1359 size_t i; 1359 1360 1360 - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 1361 - efx->rx_indir_table[i] = 1361 + for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++) 1362 + ctx->rx_indir_table[i] = 1362 1363 ethtool_rxfh_indir_default(i, efx->rss_spread); 1363 1364 } 1364 1365 ··· 1740 1739 } while (rc == -EAGAIN); 1741 1740 1742 1741 if (efx->n_channels > 1) 1743 - netdev_rss_key_fill(&efx->rx_hash_key, 1744 - sizeof(efx->rx_hash_key)); 1745 - efx_set_default_rx_indir_table(efx); 1742 + netdev_rss_key_fill(efx->rss_context.rx_hash_key, 1743 + sizeof(efx->rss_context.rx_hash_key)); 1744 + efx_set_default_rx_indir_table(efx, &efx->rss_context); 1746 1745 1747 1746 netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); 1748 1747 netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); ··· 2701 2700 " VFs may not function\n", rc); 2702 2701 #endif 2703 2702 2703 + if (efx->type->rx_restore_rss_contexts) 2704 + efx->type->rx_restore_rss_contexts(efx); 2704 2705 down_read(&efx->filter_sem); 2705 2706 efx_restore_filters(efx); 2706 2707 up_read(&efx->filter_sem); ··· 3006 3003 efx->type->rx_hash_offset - efx->type->rx_prefix_size; 3007 3004 efx->rx_packet_ts_offset = 3008 3005 efx->type->rx_ts_offset - efx->type->rx_prefix_size; 3006 + INIT_LIST_HEAD(&efx->rss_context.list); 3009 3007 spin_lock_init(&efx->stats_lock); 3010 3008 efx->vi_stride = EFX_DEFAULT_VI_STRIDE; 3011 3009 efx->num_mac_stats = MC_CMD_MAC_NSTATS; ··· 3074 3070 n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc; 3075 3071 stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc; 3076 3072 stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops); 3073 + } 3074 + 3075 + /* RSS contexts. We're using linked lists and crappy O(n) algorithms, because 3076 + * (a) this is an infrequent control-plane operation and (b) n is small (max 64) 3077 + */ 3078 + struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *head) 3079 + { 3080 + struct efx_rss_context *ctx, *new; 3081 + u32 id = 1; /* Don't use zero, that refers to the master RSS context */ 3082 + 3083 + /* Search for first gap in the numbering */ 3084 + list_for_each_entry(ctx, head, list) { 3085 + if (ctx->user_id != id) 3086 + break; 3087 + id++; 3088 + /* Check for wrap. If this happens, we have nearly 2^32 3089 + * allocated RSS contexts, which seems unlikely. 3090 + */ 3091 + if (WARN_ON_ONCE(!id)) 3092 + return NULL; 3093 + } 3094 + 3095 + /* Create the new entry */ 3096 + new = kmalloc(sizeof(struct efx_rss_context), GFP_KERNEL); 3097 + if (!new) 3098 + return NULL; 3099 + new->context_id = EFX_EF10_RSS_CONTEXT_INVALID; 3100 + new->rx_hash_udp_4tuple = false; 3101 + 3102 + /* Insert the new entry into the gap */ 3103 + new->user_id = id; 3104 + list_add_tail(&new->list, &ctx->list); 3105 + return new; 3106 + } 3107 + 3108 + struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *head) 3109 + { 3110 + struct efx_rss_context *ctx; 3111 + 3112 + list_for_each_entry(ctx, head, list) 3113 + if (ctx->user_id == id) 3114 + return ctx; 3115 + return NULL; 3116 + } 3117 + 3118 + void efx_free_rss_context_entry(struct efx_rss_context *ctx) 3119 + { 3120 + list_del(&ctx->list); 3121 + kfree(ctx); 3077 3122 } 3078 3123 3079 3124 /**************************************************************************
+11 -1
drivers/net/ethernet/sfc/efx.h
··· 34 34 extern bool efx_separate_tx_channels; 35 35 36 36 /* RX */ 37 - void efx_set_default_rx_indir_table(struct efx_nic *efx); 37 + void efx_set_default_rx_indir_table(struct efx_nic *efx, 38 + struct efx_rss_context *ctx); 38 39 void efx_rx_config_page_split(struct efx_nic *efx); 39 40 int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); 40 41 void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); ··· 182 181 #define efx_filter_rfs_enabled() 0 183 182 #endif 184 183 bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec); 184 + 185 + /* RSS contexts */ 186 + struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *list); 187 + struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *list); 188 + void efx_free_rss_context_entry(struct efx_rss_context *ctx); 189 + static inline bool efx_rss_active(struct efx_rss_context *ctx) 190 + { 191 + return ctx->context_id != EFX_EF10_RSS_CONTEXT_INVALID; 192 + } 185 193 186 194 /* Channels */ 187 195 int efx_channel_dummy_op_int(struct efx_channel *channel);
+134 -19
drivers/net/ethernet/sfc/ethtool.c
··· 808 808 } 809 809 810 810 static int efx_ethtool_get_class_rule(struct efx_nic *efx, 811 - struct ethtool_rx_flow_spec *rule) 811 + struct ethtool_rx_flow_spec *rule, 812 + u32 *rss_context) 812 813 { 813 814 struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 814 815 struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; ··· 965 964 rule->m_ext.vlan_tci = htons(0xfff); 966 965 } 967 966 967 + if (spec.flags & EFX_FILTER_FLAG_RX_RSS) { 968 + rule->flow_type |= FLOW_RSS; 969 + *rss_context = spec.rss_context; 970 + } 971 + 968 972 return rc; 969 973 } 970 974 ··· 978 972 struct ethtool_rxnfc *info, u32 *rule_locs) 979 973 { 980 974 struct efx_nic *efx = netdev_priv(net_dev); 975 + u32 rss_context = 0; 976 + s32 rc; 981 977 982 978 switch (info->cmd) { 983 979 case ETHTOOL_GRXRINGS: ··· 987 979 return 0; 988 980 989 981 case ETHTOOL_GRXFH: { 982 + struct efx_rss_context *ctx = &efx->rss_context; 983 + 984 + if (info->flow_type & FLOW_RSS && info->rss_context) { 985 + ctx = efx_find_rss_context_entry(info->rss_context, 986 + &efx->rss_context.list); 987 + if (!ctx) 988 + return -ENOENT; 989 + } 990 990 info->data = 0; 991 - if (!efx->rss_active) /* No RSS */ 991 + if (!efx_rss_active(ctx)) /* No RSS */ 992 992 return 0; 993 - switch (info->flow_type) { 993 + switch (info->flow_type & ~FLOW_RSS) { 994 994 case UDP_V4_FLOW: 995 - if (efx->rx_hash_udp_4tuple) 995 + if (ctx->rx_hash_udp_4tuple) 996 996 /* fall through */ 997 997 case TCP_V4_FLOW: 998 998 info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; ··· 1011 995 info->data |= RXH_IP_SRC | RXH_IP_DST; 1012 996 break; 1013 997 case UDP_V6_FLOW: 1014 - if (efx->rx_hash_udp_4tuple) 998 + if (ctx->rx_hash_udp_4tuple) 1015 999 /* fall through */ 1016 1000 case TCP_V6_FLOW: 1017 1001 info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; ··· 1039 1023 case ETHTOOL_GRXCLSRULE: 1040 1024 if (efx_filter_get_rx_id_limit(efx) == 0) 1041 1025 return -EOPNOTSUPP; 1042 - return efx_ethtool_get_class_rule(efx, &info->fs); 1026 + rc = efx_ethtool_get_class_rule(efx, &info->fs, &rss_context); 1027 + if (rc < 0) 1028 + return rc; 1029 + if (info->fs.flow_type & FLOW_RSS) 1030 + info->rss_context = rss_context; 1031 + return 0; 1043 1032 1044 - case ETHTOOL_GRXCLSRLALL: { 1045 - s32 rc; 1033 + case ETHTOOL_GRXCLSRLALL: 1046 1034 info->data = efx_filter_get_rx_id_limit(efx); 1047 1035 if (info->data == 0) 1048 1036 return -EOPNOTSUPP; ··· 1056 1036 return rc; 1057 1037 info->rule_cnt = rc; 1058 1038 return 0; 1059 - } 1060 1039 1061 1040 default: 1062 1041 return -EOPNOTSUPP; ··· 1073 1054 } 1074 1055 1075 1056 static int efx_ethtool_set_class_rule(struct efx_nic *efx, 1076 - struct ethtool_rx_flow_spec *rule) 1057 + struct ethtool_rx_flow_spec *rule, 1058 + u32 rss_context) 1077 1059 { 1078 1060 struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec; 1079 1061 struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec; ··· 1086 1066 struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec; 1087 1067 struct ethhdr *mac_entry = &rule->h_u.ether_spec; 1088 1068 struct ethhdr *mac_mask = &rule->m_u.ether_spec; 1069 + enum efx_filter_flags flags = 0; 1089 1070 struct efx_filter_spec spec; 1090 1071 int rc; 1091 1072 ··· 1105 1084 rule->m_ext.data[1])) 1106 1085 return -EINVAL; 1107 1086 1108 - efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, 1109 - efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0, 1087 + if (efx->rx_scatter) 1088 + flags |= EFX_FILTER_FLAG_RX_SCATTER; 1089 + if (rule->flow_type & FLOW_RSS) 1090 + flags |= EFX_FILTER_FLAG_RX_RSS; 1091 + 1092 + efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, flags, 1110 1093 (rule->ring_cookie == RX_CLS_FLOW_DISC) ? 1111 1094 EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie); 1112 1095 1113 - switch (rule->flow_type & ~FLOW_EXT) { 1096 + if (rule->flow_type & FLOW_RSS) 1097 + spec.rss_context = rss_context; 1098 + 1099 + switch (rule->flow_type & ~(FLOW_EXT | FLOW_RSS)) { 1114 1100 case TCP_V4_FLOW: 1115 1101 case UDP_V4_FLOW: 1116 1102 spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE | ··· 1293 1265 1294 1266 switch (info->cmd) { 1295 1267 case ETHTOOL_SRXCLSRLINS: 1296 - return efx_ethtool_set_class_rule(efx, &info->fs); 1268 + return efx_ethtool_set_class_rule(efx, &info->fs, 1269 + info->rss_context); 1297 1270 1298 1271 case ETHTOOL_SRXCLSRLDEL: 1299 1272 return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL, ··· 1309 1280 { 1310 1281 struct efx_nic *efx = netdev_priv(net_dev); 1311 1282 1312 - return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table); 1283 + if (efx->n_rx_channels == 1) 1284 + return 0; 1285 + return ARRAY_SIZE(efx->rss_context.rx_indir_table); 1313 1286 } 1314 1287 1315 1288 static u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev) ··· 1334 1303 if (hfunc) 1335 1304 *hfunc = ETH_RSS_HASH_TOP; 1336 1305 if (indir) 1337 - memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); 1306 + memcpy(indir, efx->rss_context.rx_indir_table, 1307 + sizeof(efx->rss_context.rx_indir_table)); 1338 1308 if (key) 1339 - memcpy(key, efx->rx_hash_key, efx->type->rx_hash_key_size); 1309 + memcpy(key, efx->rss_context.rx_hash_key, 1310 + efx->type->rx_hash_key_size); 1340 1311 return 0; 1341 1312 } 1342 1313 ··· 1354 1321 return 0; 1355 1322 1356 1323 if (!key) 1357 - key = efx->rx_hash_key; 1324 + key = efx->rss_context.rx_hash_key; 1358 1325 if (!indir) 1359 - indir = efx->rx_indir_table; 1326 + indir = efx->rss_context.rx_indir_table; 1360 1327 1361 1328 return efx->type->rx_push_rss_config(efx, true, indir, key); 1329 + } 1330 + 1331 + static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir, 1332 + u8 *key, u8 *hfunc, u32 rss_context) 1333 + { 1334 + struct efx_nic *efx = netdev_priv(net_dev); 1335 + struct efx_rss_context *ctx; 1336 + int rc; 1337 + 1338 + if (!efx->type->rx_pull_rss_context_config) 1339 + return -EOPNOTSUPP; 1340 + ctx = efx_find_rss_context_entry(rss_context, &efx->rss_context.list); 1341 + if (!ctx) 1342 + return -ENOENT; 1343 + rc = efx->type->rx_pull_rss_context_config(efx, ctx); 1344 + if (rc) 1345 + return rc; 1346 + 1347 + if (hfunc) 1348 + *hfunc = ETH_RSS_HASH_TOP; 1349 + if (indir) 1350 + memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table)); 1351 + if (key) 1352 + memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size); 1353 + return 0; 1354 + } 1355 + 1356 + static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, 1357 + const u32 *indir, const u8 *key, 1358 + const u8 hfunc, u32 *rss_context, 1359 + bool delete) 1360 + { 1361 + struct efx_nic *efx = netdev_priv(net_dev); 1362 + struct efx_rss_context *ctx; 1363 + bool allocated = false; 1364 + int rc; 1365 + 1366 + if (!efx->type->rx_push_rss_context_config) 1367 + return -EOPNOTSUPP; 1368 + /* Hash function is Toeplitz, cannot be changed */ 1369 + if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 1370 + return -EOPNOTSUPP; 1371 + if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) { 1372 + if (delete) 1373 + /* alloc + delete == Nothing to do */ 1374 + return -EINVAL; 1375 + ctx = efx_alloc_rss_context_entry(&efx->rss_context.list); 1376 + if (!ctx) 1377 + return -ENOMEM; 1378 + ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID; 1379 + /* Initialise indir table and key to defaults */ 1380 + efx_set_default_rx_indir_table(efx, ctx); 1381 + netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key)); 1382 + allocated = true; 1383 + } else { 1384 + ctx = efx_find_rss_context_entry(*rss_context, 1385 + &efx->rss_context.list); 1386 + if (!ctx) 1387 + return -ENOENT; 1388 + } 1389 + 1390 + if (delete) { 1391 + /* delete this context */ 1392 + rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL); 1393 + if (!rc) 1394 + efx_free_rss_context_entry(ctx); 1395 + return rc; 1396 + } 1397 + 1398 + if (!key) 1399 + key = ctx->rx_hash_key; 1400 + if (!indir) 1401 + indir = ctx->rx_indir_table; 1402 + 1403 + rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key); 1404 + if (rc && allocated) 1405 + efx_free_rss_context_entry(ctx); 1406 + else 1407 + *rss_context = ctx->user_id; 1408 + return rc; 1362 1409 } 1363 1410 1364 1411 static int efx_ethtool_get_ts_info(struct net_device *net_dev, ··· 1516 1403 .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, 1517 1404 .get_rxfh = efx_ethtool_get_rxfh, 1518 1405 .set_rxfh = efx_ethtool_set_rxfh, 1406 + .get_rxfh_context = efx_ethtool_get_rxfh_context, 1407 + .set_rxfh_context = efx_ethtool_set_rxfh_context, 1519 1408 .get_ts_info = efx_ethtool_get_ts_info, 1520 1409 .get_module_info = efx_ethtool_get_module_info, 1521 1410 .get_module_eeprom = efx_ethtool_get_module_eeprom,
+5 -6
drivers/net/ethernet/sfc/farch.c
··· 1630 1630 size_t i = 0; 1631 1631 efx_dword_t dword; 1632 1632 1633 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != 1633 + BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_indir_table) != 1634 1634 FR_BZ_RX_INDIRECTION_TBL_ROWS); 1635 1635 1636 1636 for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) { 1637 1637 EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, 1638 - efx->rx_indir_table[i]); 1638 + efx->rss_context.rx_indir_table[i]); 1639 1639 efx_writed(efx, &dword, 1640 1640 FR_BZ_RX_INDIRECTION_TBL + 1641 1641 FR_BZ_RX_INDIRECTION_TBL_STEP * i); ··· 1647 1647 size_t i = 0; 1648 1648 efx_dword_t dword; 1649 1649 1650 - BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != 1650 + BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_indir_table) != 1651 1651 FR_BZ_RX_INDIRECTION_TBL_ROWS); 1652 1652 1653 1653 for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) { 1654 1654 efx_readd(efx, &dword, 1655 1655 FR_BZ_RX_INDIRECTION_TBL + 1656 1656 FR_BZ_RX_INDIRECTION_TBL_STEP * i); 1657 - efx->rx_indir_table[i] = EFX_DWORD_FIELD(dword, FRF_BZ_IT_QUEUE); 1657 + efx->rss_context.rx_indir_table[i] = EFX_DWORD_FIELD(dword, FRF_BZ_IT_QUEUE); 1658 1658 } 1659 1659 } 1660 1660 ··· 2032 2032 { 2033 2033 bool is_full = false; 2034 2034 2035 - if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) && 2036 - gen_spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT) 2035 + if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) && gen_spec->rss_context) 2037 2036 return -EINVAL; 2038 2037 2039 2038 spec->priority = gen_spec->priority;
+4 -3
drivers/net/ethernet/sfc/filter.h
··· 125 125 * @match_flags: Match type flags, from &enum efx_filter_match_flags 126 126 * @priority: Priority of the filter, from &enum efx_filter_priority 127 127 * @flags: Miscellaneous flags, from &enum efx_filter_flags 128 - * @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set 128 + * @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set. This 129 + * is a user_id (with 0 meaning the driver/default RSS context), not an 130 + * MCFW context_id. 129 131 * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for 130 132 * an RX drop filter 131 133 * @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set ··· 175 173 }; 176 174 177 175 enum { 178 - EFX_FILTER_RSS_CONTEXT_DEFAULT = 0xffffffff, 179 176 EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff 180 177 }; 181 178 ··· 186 185 memset(spec, 0, sizeof(*spec)); 187 186 spec->priority = priority; 188 187 spec->flags = EFX_FILTER_FLAG_RX | flags; 189 - spec->rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT; 188 + spec->rss_context = 0; 190 189 spec->dmaq_id = rxq_id; 191 190 } 192 191
+36 -8
drivers/net/ethernet/sfc/net_driver.h
··· 704 704 705 705 struct vfdi_status; 706 706 707 + /* The reserved RSS context value */ 708 + #define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff 709 + /** 710 + * struct efx_rss_context - A user-defined RSS context for filtering 711 + * @list: node of linked list on which this struct is stored 712 + * @context_id: the RSS_CONTEXT_ID returned by MC firmware, or 713 + * %EFX_EF10_RSS_CONTEXT_INVALID if this context is not present on the NIC. 714 + * For Siena, 0 if RSS is active, else %EFX_EF10_RSS_CONTEXT_INVALID. 715 + * @user_id: the rss_context ID exposed to userspace over ethtool. 716 + * @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled 717 + * @rx_hash_key: Toeplitz hash key for this RSS context 718 + * @indir_table: Indirection table for this RSS context 719 + */ 720 + struct efx_rss_context { 721 + struct list_head list; 722 + u32 context_id; 723 + u32 user_id; 724 + bool rx_hash_udp_4tuple; 725 + u8 rx_hash_key[40]; 726 + u32 rx_indir_table[128]; 727 + }; 728 + 707 729 /** 708 730 * struct efx_nic - an Efx NIC 709 731 * @name: Device name (net device name or bus id before net device registered) ··· 786 764 * (valid only for NICs that set %EFX_RX_PKT_PREFIX_LEN; always negative) 787 765 * @rx_packet_ts_offset: Offset of timestamp from start of packet data 788 766 * (valid only if channel->sync_timestamps_enabled; always negative) 789 - * @rx_hash_key: Toeplitz hash key for RSS 790 - * @rx_indir_table: Indirection table for RSS 791 767 * @rx_scatter: Scatter mode enabled for receives 792 - * @rss_active: RSS enabled on hardware 793 - * @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled 768 + * @rss_context: Main RSS context. Its @list member is the head of the list of 769 + * RSS contexts created by user requests 794 770 * @int_error_count: Number of internal errors seen recently 795 771 * @int_error_expire: Time at which error count will be expired 796 772 * @irq_soft_enabled: Are IRQs soft-enabled? If not, IRQ handler will ··· 929 909 int rx_packet_hash_offset; 930 910 int rx_packet_len_offset; 931 911 int rx_packet_ts_offset; 932 - u8 rx_hash_key[40]; 933 - u32 rx_indir_table[128]; 934 912 bool rx_scatter; 935 - bool rss_active; 936 - bool rx_hash_udp_4tuple; 913 + struct efx_rss_context rss_context; 937 914 938 915 unsigned int_error_count; 939 916 unsigned long int_error_expire; ··· 1116 1099 * @tx_write: Write TX descriptors and doorbell 1117 1100 * @rx_push_rss_config: Write RSS hash key and indirection table to the NIC 1118 1101 * @rx_pull_rss_config: Read RSS hash key and indirection table back from the NIC 1102 + * @rx_push_rss_context_config: Write RSS hash key and indirection table for 1103 + * user RSS context to the NIC 1104 + * @rx_pull_rss_context_config: Read RSS hash key and indirection table for user 1105 + * RSS context back from the NIC 1119 1106 * @rx_probe: Allocate resources for RX queue 1120 1107 * @rx_init: Initialise RX queue on the NIC 1121 1108 * @rx_remove: Free resources for RX queue ··· 1258 1237 int (*rx_push_rss_config)(struct efx_nic *efx, bool user, 1259 1238 const u32 *rx_indir_table, const u8 *key); 1260 1239 int (*rx_pull_rss_config)(struct efx_nic *efx); 1240 + int (*rx_push_rss_context_config)(struct efx_nic *efx, 1241 + struct efx_rss_context *ctx, 1242 + const u32 *rx_indir_table, 1243 + const u8 *key); 1244 + int (*rx_pull_rss_context_config)(struct efx_nic *efx, 1245 + struct efx_rss_context *ctx); 1246 + void (*rx_restore_rss_contexts)(struct efx_nic *efx); 1261 1247 int (*rx_probe)(struct efx_rx_queue *rx_queue); 1262 1248 void (*rx_init)(struct efx_rx_queue *rx_queue); 1263 1249 void (*rx_remove)(struct efx_rx_queue *rx_queue);
-2
drivers/net/ethernet/sfc/nic.h
··· 374 374 * @piobuf_size: size of a single PIO buffer 375 375 * @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC 376 376 * reboot 377 - * @rx_rss_context: Firmware handle for our RSS context 378 377 * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared 379 378 * @stats: Hardware statistics 380 379 * @workaround_35388: Flag: firmware supports workaround for bug 35388 ··· 414 415 unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT]; 415 416 u16 piobuf_size; 416 417 bool must_restore_piobufs; 417 - u32 rx_rss_context; 418 418 bool rx_rss_context_exclusive; 419 419 u64 stats[EF10_STAT_COUNT]; 420 420 bool workaround_35388;
+13 -13
drivers/net/ethernet/sfc/siena.c
··· 350 350 * siena_rx_push_rss_config, below) 351 351 */ 352 352 efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1); 353 - memcpy(efx->rx_hash_key, &temp, sizeof(temp)); 353 + memcpy(efx->rss_context.rx_hash_key, &temp, sizeof(temp)); 354 354 efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2); 355 - memcpy(efx->rx_hash_key + sizeof(temp), &temp, sizeof(temp)); 355 + memcpy(efx->rss_context.rx_hash_key + sizeof(temp), &temp, sizeof(temp)); 356 356 efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); 357 - memcpy(efx->rx_hash_key + 2 * sizeof(temp), &temp, 357 + memcpy(efx->rss_context.rx_hash_key + 2 * sizeof(temp), &temp, 358 358 FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); 359 359 efx_farch_rx_pull_indir_table(efx); 360 360 return 0; ··· 367 367 368 368 /* Set hash key for IPv4 */ 369 369 if (key) 370 - memcpy(efx->rx_hash_key, key, sizeof(temp)); 371 - memcpy(&temp, efx->rx_hash_key, sizeof(temp)); 370 + memcpy(efx->rss_context.rx_hash_key, key, sizeof(temp)); 371 + memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp)); 372 372 efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); 373 373 374 374 /* Enable IPv6 RSS */ 375 - BUILD_BUG_ON(sizeof(efx->rx_hash_key) < 375 + BUILD_BUG_ON(sizeof(efx->rss_context.rx_hash_key) < 376 376 2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 || 377 377 FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0); 378 - memcpy(&temp, efx->rx_hash_key, sizeof(temp)); 378 + memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp)); 379 379 efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1); 380 - memcpy(&temp, efx->rx_hash_key + sizeof(temp), sizeof(temp)); 380 + memcpy(&temp, efx->rss_context.rx_hash_key + sizeof(temp), sizeof(temp)); 381 381 efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2); 382 382 EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1, 383 383 FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1); 384 - memcpy(&temp, efx->rx_hash_key + 2 * sizeof(temp), 384 + memcpy(&temp, efx->rss_context.rx_hash_key + 2 * sizeof(temp), 385 385 FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); 386 386 efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); 387 387 388 - memcpy(efx->rx_indir_table, rx_indir_table, 389 - sizeof(efx->rx_indir_table)); 388 + memcpy(efx->rss_context.rx_indir_table, rx_indir_table, 389 + sizeof(efx->rss_context.rx_indir_table)); 390 390 efx_farch_rx_push_indir_table(efx); 391 391 392 392 return 0; ··· 432 432 EFX_RX_USR_BUF_SIZE >> 5); 433 433 efx_writeo(efx, &temp, FR_AZ_RX_CFG); 434 434 435 - siena_rx_push_rss_config(efx, false, efx->rx_indir_table, NULL); 436 - efx->rss_active = true; 435 + siena_rx_push_rss_config(efx, false, efx->rss_context.rx_indir_table, NULL); 436 + efx->rss_context.context_id = 0; /* indicates RSS is active */ 437 437 438 438 /* Enable event logging */ 439 439 rc = efx_mcdi_log_ctrl(efx, true, false, 0);