diff options
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 32 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/rx.c | 29 |
3 files changed, 56 insertions, 17 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 0705ec869487..097f363f1630 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -1726,14 +1726,33 @@ static int efx_probe_filters(struct efx_nic *efx) | |||
1726 | 1726 | ||
1727 | #ifdef CONFIG_RFS_ACCEL | 1727 | #ifdef CONFIG_RFS_ACCEL |
1728 | if (efx->type->offload_features & NETIF_F_NTUPLE) { | 1728 | if (efx->type->offload_features & NETIF_F_NTUPLE) { |
1729 | efx->rps_flow_id = kcalloc(efx->type->max_rx_ip_filters, | 1729 | struct efx_channel *channel; |
1730 | sizeof(*efx->rps_flow_id), | 1730 | int i, success = 1; |
1731 | GFP_KERNEL); | 1731 | |
1732 | if (!efx->rps_flow_id) { | 1732 | efx_for_each_channel(channel, efx) { |
1733 | channel->rps_flow_id = | ||
1734 | kcalloc(efx->type->max_rx_ip_filters, | ||
1735 | sizeof(*channel->rps_flow_id), | ||
1736 | GFP_KERNEL); | ||
1737 | if (!channel->rps_flow_id) | ||
1738 | success = 0; | ||
1739 | else | ||
1740 | for (i = 0; | ||
1741 | i < efx->type->max_rx_ip_filters; | ||
1742 | ++i) | ||
1743 | channel->rps_flow_id[i] = | ||
1744 | RPS_FLOW_ID_INVALID; | ||
1745 | } | ||
1746 | |||
1747 | if (!success) { | ||
1748 | efx_for_each_channel(channel, efx) | ||
1749 | kfree(channel->rps_flow_id); | ||
1733 | efx->type->filter_table_remove(efx); | 1750 | efx->type->filter_table_remove(efx); |
1734 | rc = -ENOMEM; | 1751 | rc = -ENOMEM; |
1735 | goto out_unlock; | 1752 | goto out_unlock; |
1736 | } | 1753 | } |
1754 | |||
1755 | efx->rps_expire_index = efx->rps_expire_channel = 0; | ||
1737 | } | 1756 | } |
1738 | #endif | 1757 | #endif |
1739 | out_unlock: | 1758 | out_unlock: |
@@ -1744,7 +1763,10 @@ out_unlock: | |||
1744 | static void efx_remove_filters(struct efx_nic *efx) | 1763 | static void efx_remove_filters(struct efx_nic *efx) |
1745 | { | 1764 | { |
1746 | #ifdef CONFIG_RFS_ACCEL | 1765 | #ifdef CONFIG_RFS_ACCEL |
1747 | kfree(efx->rps_flow_id); | 1766 | struct efx_channel *channel; |
1767 | |||
1768 | efx_for_each_channel(channel, efx) | ||
1769 | kfree(channel->rps_flow_id); | ||
1748 | #endif | 1770 | #endif |
1749 | down_write(&efx->filter_sem); | 1771 | down_write(&efx->filter_sem); |
1750 | efx->type->filter_table_remove(efx); | 1772 | efx->type->filter_table_remove(efx); |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 38c422321cda..d13ddf9703ff 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -403,6 +403,8 @@ enum efx_sync_events_state { | |||
403 | * @event_test_cpu: Last CPU to handle interrupt or test event for this channel | 403 | * @event_test_cpu: Last CPU to handle interrupt or test event for this channel |
404 | * @irq_count: Number of IRQs since last adaptive moderation decision | 404 | * @irq_count: Number of IRQs since last adaptive moderation decision |
405 | * @irq_mod_score: IRQ moderation score | 405 | * @irq_mod_score: IRQ moderation score |
406 | * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS, | ||
407 | * indexed by filter ID | ||
406 | * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors | 408 | * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors |
407 | * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors | 409 | * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors |
408 | * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors | 410 | * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors |
@@ -446,6 +448,8 @@ struct efx_channel { | |||
446 | unsigned int irq_mod_score; | 448 | unsigned int irq_mod_score; |
447 | #ifdef CONFIG_RFS_ACCEL | 449 | #ifdef CONFIG_RFS_ACCEL |
448 | unsigned int rfs_filters_added; | 450 | unsigned int rfs_filters_added; |
451 | #define RPS_FLOW_ID_INVALID 0xFFFFFFFF | ||
452 | u32 *rps_flow_id; | ||
449 | #endif | 453 | #endif |
450 | 454 | ||
451 | unsigned n_rx_tobe_disc; | 455 | unsigned n_rx_tobe_disc; |
@@ -889,9 +893,9 @@ struct vfdi_status; | |||
889 | * @filter_sem: Filter table rw_semaphore, for freeing the table | 893 | * @filter_sem: Filter table rw_semaphore, for freeing the table |
890 | * @filter_lock: Filter table lock, for mere content changes | 894 | * @filter_lock: Filter table lock, for mere content changes |
891 | * @filter_state: Architecture-dependent filter table state | 895 | * @filter_state: Architecture-dependent filter table state |
892 | * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS, | 896 | * @rps_expire_channel: Next channel to check for expiry |
893 | * indexed by filter ID | 897 | * @rps_expire_index: Next index to check for expiry in |
894 | * @rps_expire_index: Next index to check for expiry in @rps_flow_id | 898 | * @rps_expire_channel's @rps_flow_id |
895 | * @active_queues: Count of RX and TX queues that haven't been flushed and drained. | 899 | * @active_queues: Count of RX and TX queues that haven't been flushed and drained. |
896 | * @rxq_flush_pending: Count of number of receive queues that need to be flushed. | 900 | * @rxq_flush_pending: Count of number of receive queues that need to be flushed. |
897 | * Decremented when the efx_flush_rx_queue() is called. | 901 | * Decremented when the efx_flush_rx_queue() is called. |
@@ -1035,7 +1039,7 @@ struct efx_nic { | |||
1035 | spinlock_t filter_lock; | 1039 | spinlock_t filter_lock; |
1036 | void *filter_state; | 1040 | void *filter_state; |
1037 | #ifdef CONFIG_RFS_ACCEL | 1041 | #ifdef CONFIG_RFS_ACCEL |
1038 | u32 *rps_flow_id; | 1042 | unsigned int rps_expire_channel; |
1039 | unsigned int rps_expire_index; | 1043 | unsigned int rps_expire_index; |
1040 | #endif | 1044 | #endif |
1041 | 1045 | ||
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 9d6cc8b92ba0..02b0b5272c14 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c | |||
@@ -845,6 +845,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
845 | struct flow_keys fk; | 845 | struct flow_keys fk; |
846 | int rc; | 846 | int rc; |
847 | 847 | ||
848 | if (flow_id == RPS_FLOW_ID_INVALID) | ||
849 | return -EINVAL; | ||
850 | |||
848 | if (!skb_flow_dissect_flow_keys(skb, &fk, 0)) | 851 | if (!skb_flow_dissect_flow_keys(skb, &fk, 0)) |
849 | return -EPROTONOSUPPORT; | 852 | return -EPROTONOSUPPORT; |
850 | 853 | ||
@@ -879,8 +882,8 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
879 | return rc; | 882 | return rc; |
880 | 883 | ||
881 | /* Remember this so we can check whether to expire the filter later */ | 884 | /* Remember this so we can check whether to expire the filter later */ |
882 | efx->rps_flow_id[rc] = flow_id; | 885 | channel = efx_get_channel(efx, rxq_index); |
883 | channel = efx_get_channel(efx, skb_get_rx_queue(skb)); | 886 | channel->rps_flow_id[rc] = flow_id; |
884 | ++channel->rfs_filters_added; | 887 | ++channel->rfs_filters_added; |
885 | 888 | ||
886 | if (spec.ether_type == htons(ETH_P_IP)) | 889 | if (spec.ether_type == htons(ETH_P_IP)) |
@@ -902,24 +905,34 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
902 | bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned int quota) | 905 | bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned int quota) |
903 | { | 906 | { |
904 | bool (*expire_one)(struct efx_nic *efx, u32 flow_id, unsigned int index); | 907 | bool (*expire_one)(struct efx_nic *efx, u32 flow_id, unsigned int index); |
905 | unsigned int index, size; | 908 | unsigned int channel_idx, index, size; |
906 | u32 flow_id; | 909 | u32 flow_id; |
907 | 910 | ||
908 | if (!spin_trylock_bh(&efx->filter_lock)) | 911 | if (!spin_trylock_bh(&efx->filter_lock)) |
909 | return false; | 912 | return false; |
910 | 913 | ||
911 | expire_one = efx->type->filter_rfs_expire_one; | 914 | expire_one = efx->type->filter_rfs_expire_one; |
915 | channel_idx = efx->rps_expire_channel; | ||
912 | index = efx->rps_expire_index; | 916 | index = efx->rps_expire_index; |
913 | size = efx->type->max_rx_ip_filters; | 917 | size = efx->type->max_rx_ip_filters; |
914 | while (quota--) { | 918 | while (quota--) { |
915 | flow_id = efx->rps_flow_id[index]; | 919 | struct efx_channel *channel = efx_get_channel(efx, channel_idx); |
916 | if (expire_one(efx, flow_id, index)) | 920 | flow_id = channel->rps_flow_id[index]; |
921 | |||
922 | if (flow_id != RPS_FLOW_ID_INVALID && | ||
923 | expire_one(efx, flow_id, index)) { | ||
917 | netif_info(efx, rx_status, efx->net_dev, | 924 | netif_info(efx, rx_status, efx->net_dev, |
918 | "expired filter %d [flow %u]\n", | 925 | "expired filter %d [queue %u flow %u]\n", |
919 | index, flow_id); | 926 | index, channel_idx, flow_id); |
920 | if (++index == size) | 927 | channel->rps_flow_id[index] = RPS_FLOW_ID_INVALID; |
928 | } | ||
929 | if (++index == size) { | ||
930 | if (++channel_idx == efx->n_channels) | ||
931 | channel_idx = 0; | ||
921 | index = 0; | 932 | index = 0; |
933 | } | ||
922 | } | 934 | } |
935 | efx->rps_expire_channel = channel_idx; | ||
923 | efx->rps_expire_index = index; | 936 | efx->rps_expire_index = index; |
924 | 937 | ||
925 | spin_unlock_bh(&efx->filter_lock); | 938 | spin_unlock_bh(&efx->filter_lock); |