diff options
-rw-r--r-- | drivers/net/sfc/efx.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 90 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 19 | ||||
-rw-r--r-- | drivers/net/sfc/nic.h | 1 |
5 files changed, 105 insertions, 10 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 2a90bf9df913..35b3f2922e5c 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1121,6 +1121,7 @@ static void efx_set_channels(struct efx_nic *efx) | |||
1121 | 1121 | ||
1122 | static int efx_probe_nic(struct efx_nic *efx) | 1122 | static int efx_probe_nic(struct efx_nic *efx) |
1123 | { | 1123 | { |
1124 | size_t i; | ||
1124 | int rc; | 1125 | int rc; |
1125 | 1126 | ||
1126 | netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); | 1127 | netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); |
@@ -1136,6 +1137,8 @@ static int efx_probe_nic(struct efx_nic *efx) | |||
1136 | 1137 | ||
1137 | if (efx->n_channels > 1) | 1138 | if (efx->n_channels > 1) |
1138 | get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); | 1139 | get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); |
1140 | for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) | ||
1141 | efx->rx_indir_table[i] = i % efx->n_rx_channels; | ||
1139 | 1142 | ||
1140 | efx_set_channels(efx); | 1143 | efx_set_channels(efx); |
1141 | efx->net_dev->real_num_tx_queues = efx->n_tx_channels; | 1144 | efx->net_dev->real_num_tx_queues = efx->n_tx_channels; |
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 23372bf5cd59..3b8b0a062749 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -868,6 +868,93 @@ extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) | |||
868 | return efx_reset(efx, method); | 868 | return efx_reset(efx, method); |
869 | } | 869 | } |
870 | 870 | ||
871 | static int | ||
872 | efx_ethtool_get_rxnfc(struct net_device *net_dev, | ||
873 | struct ethtool_rxnfc *info, void *rules __always_unused) | ||
874 | { | ||
875 | struct efx_nic *efx = netdev_priv(net_dev); | ||
876 | |||
877 | switch (info->cmd) { | ||
878 | case ETHTOOL_GRXRINGS: | ||
879 | info->data = efx->n_rx_channels; | ||
880 | return 0; | ||
881 | |||
882 | case ETHTOOL_GRXFH: { | ||
883 | unsigned min_revision = 0; | ||
884 | |||
885 | info->data = 0; | ||
886 | switch (info->flow_type) { | ||
887 | case TCP_V4_FLOW: | ||
888 | info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
889 | /* fall through */ | ||
890 | case UDP_V4_FLOW: | ||
891 | case SCTP_V4_FLOW: | ||
892 | case AH_ESP_V4_FLOW: | ||
893 | case IPV4_FLOW: | ||
894 | info->data |= RXH_IP_SRC | RXH_IP_DST; | ||
895 | min_revision = EFX_REV_FALCON_B0; | ||
896 | break; | ||
897 | case TCP_V6_FLOW: | ||
898 | info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | ||
899 | /* fall through */ | ||
900 | case UDP_V6_FLOW: | ||
901 | case SCTP_V6_FLOW: | ||
902 | case AH_ESP_V6_FLOW: | ||
903 | case IPV6_FLOW: | ||
904 | info->data |= RXH_IP_SRC | RXH_IP_DST; | ||
905 | min_revision = EFX_REV_SIENA_A0; | ||
906 | break; | ||
907 | default: | ||
908 | break; | ||
909 | } | ||
910 | if (efx_nic_rev(efx) < min_revision) | ||
911 | info->data = 0; | ||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | default: | ||
916 | return -EOPNOTSUPP; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, | ||
921 | struct ethtool_rxfh_indir *indir) | ||
922 | { | ||
923 | struct efx_nic *efx = netdev_priv(net_dev); | ||
924 | size_t copy_size = | ||
925 | min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table)); | ||
926 | |||
927 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) | ||
928 | return -EOPNOTSUPP; | ||
929 | |||
930 | indir->size = ARRAY_SIZE(efx->rx_indir_table); | ||
931 | memcpy(indir->ring_index, efx->rx_indir_table, | ||
932 | copy_size * sizeof(indir->ring_index[0])); | ||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | ||
937 | const struct ethtool_rxfh_indir *indir) | ||
938 | { | ||
939 | struct efx_nic *efx = netdev_priv(net_dev); | ||
940 | size_t i; | ||
941 | |||
942 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) | ||
943 | return -EOPNOTSUPP; | ||
944 | |||
945 | /* Validate size and indices */ | ||
946 | if (indir->size != ARRAY_SIZE(efx->rx_indir_table)) | ||
947 | return -EINVAL; | ||
948 | for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) | ||
949 | if (indir->ring_index[i] >= efx->n_rx_channels) | ||
950 | return -EINVAL; | ||
951 | |||
952 | memcpy(efx->rx_indir_table, indir->ring_index, | ||
953 | sizeof(efx->rx_indir_table)); | ||
954 | efx_nic_push_rx_indir_table(efx); | ||
955 | return 0; | ||
956 | } | ||
957 | |||
871 | const struct ethtool_ops efx_ethtool_ops = { | 958 | const struct ethtool_ops efx_ethtool_ops = { |
872 | .get_settings = efx_ethtool_get_settings, | 959 | .get_settings = efx_ethtool_get_settings, |
873 | .set_settings = efx_ethtool_set_settings, | 960 | .set_settings = efx_ethtool_set_settings, |
@@ -905,4 +992,7 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
905 | .get_wol = efx_ethtool_get_wol, | 992 | .get_wol = efx_ethtool_get_wol, |
906 | .set_wol = efx_ethtool_set_wol, | 993 | .set_wol = efx_ethtool_set_wol, |
907 | .reset = efx_ethtool_reset, | 994 | .reset = efx_ethtool_reset, |
995 | .get_rxnfc = efx_ethtool_get_rxnfc, | ||
996 | .get_rxfh_indir = efx_ethtool_get_rxfh_indir, | ||
997 | .set_rxfh_indir = efx_ethtool_set_rxfh_indir, | ||
908 | }; | 998 | }; |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 28f3ff4cff4a..bab836c22719 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -648,6 +648,7 @@ union efx_multicast_hash { | |||
648 | * @n_tx_channels: Number of channels used for TX | 648 | * @n_tx_channels: Number of channels used for TX |
649 | * @rx_buffer_len: RX buffer length | 649 | * @rx_buffer_len: RX buffer length |
650 | * @rx_buffer_order: Order (log2) of number of pages for each RX buffer | 650 | * @rx_buffer_order: Order (log2) of number of pages for each RX buffer |
651 | * @rx_indir_table: Indirection table for RSS | ||
651 | * @int_error_count: Number of internal errors seen recently | 652 | * @int_error_count: Number of internal errors seen recently |
652 | * @int_error_expire: Time at which error count will be expired | 653 | * @int_error_expire: Time at which error count will be expired |
653 | * @irq_status: Interrupt status buffer | 654 | * @irq_status: Interrupt status buffer |
@@ -736,6 +737,7 @@ struct efx_nic { | |||
736 | unsigned int rx_buffer_len; | 737 | unsigned int rx_buffer_len; |
737 | unsigned int rx_buffer_order; | 738 | unsigned int rx_buffer_order; |
738 | u8 rx_hash_key[40]; | 739 | u8 rx_hash_key[40]; |
740 | u32 rx_indir_table[128]; | ||
739 | 741 | ||
740 | unsigned int_error_count; | 742 | unsigned int_error_count; |
741 | unsigned long int_error_expire; | 743 | unsigned long int_error_expire; |
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 30836578c1cc..f595d920c7c4 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c | |||
@@ -1484,22 +1484,21 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) | |||
1484 | /* Setup RSS indirection table. | 1484 | /* Setup RSS indirection table. |
1485 | * This maps from the hash value of the packet to RXQ | 1485 | * This maps from the hash value of the packet to RXQ |
1486 | */ | 1486 | */ |
1487 | static void efx_setup_rss_indir_table(struct efx_nic *efx) | 1487 | void efx_nic_push_rx_indir_table(struct efx_nic *efx) |
1488 | { | 1488 | { |
1489 | int i = 0; | 1489 | size_t i = 0; |
1490 | unsigned long offset; | ||
1491 | efx_dword_t dword; | 1490 | efx_dword_t dword; |
1492 | 1491 | ||
1493 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) | 1492 | if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) |
1494 | return; | 1493 | return; |
1495 | 1494 | ||
1496 | for (offset = FR_BZ_RX_INDIRECTION_TBL; | 1495 | BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != |
1497 | offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; | 1496 | FR_BZ_RX_INDIRECTION_TBL_ROWS); |
1498 | offset += 0x10) { | 1497 | |
1498 | for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) { | ||
1499 | EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, | 1499 | EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, |
1500 | i % efx->n_rx_channels); | 1500 | efx->rx_indir_table[i]); |
1501 | efx_writed(efx, &dword, offset); | 1501 | efx_writed_table(efx, &dword, FR_BZ_RX_INDIRECTION_TBL, i); |
1502 | i++; | ||
1503 | } | 1502 | } |
1504 | } | 1503 | } |
1505 | 1504 | ||
@@ -1634,7 +1633,7 @@ void efx_nic_init_common(struct efx_nic *efx) | |||
1634 | EFX_INVERT_OWORD(temp); | 1633 | EFX_INVERT_OWORD(temp); |
1635 | efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); | 1634 | efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); |
1636 | 1635 | ||
1637 | efx_setup_rss_indir_table(efx); | 1636 | efx_nic_push_rx_indir_table(efx); |
1638 | 1637 | ||
1639 | /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be | 1638 | /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be |
1640 | * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. | 1639 | * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. |
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index a39822da081b..0438dc98722d 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h | |||
@@ -207,6 +207,7 @@ extern void falcon_stop_nic_stats(struct efx_nic *efx); | |||
207 | extern void falcon_setup_xaui(struct efx_nic *efx); | 207 | extern void falcon_setup_xaui(struct efx_nic *efx); |
208 | extern int falcon_reset_xaui(struct efx_nic *efx); | 208 | extern int falcon_reset_xaui(struct efx_nic *efx); |
209 | extern void efx_nic_init_common(struct efx_nic *efx); | 209 | extern void efx_nic_init_common(struct efx_nic *efx); |
210 | extern void efx_nic_push_rx_indir_table(struct efx_nic *efx); | ||
210 | 211 | ||
211 | int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, | 212 | int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, |
212 | unsigned int len); | 213 | unsigned int len); |