aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-06-30 01:06:28 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 17:10:04 -0400
commit765c9f46867c3253c02275cbb7a453f2eb56eda1 (patch)
tree42a2f70e2a9104c620849412d8f6ce91f30815f7 /drivers/net/sfc
parenta5b6ee291e39e285e021cf251dbcf770c83cd74e (diff)
sfc: Add support for RX flow hash control
Allow ethtool to query the number of RX rings, the fields used in RX flow hashing and the hash indirection table. Allow ethtool to update the RX flow hash indirection table. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/efx.c3
-rw-r--r--drivers/net/sfc/ethtool.c90
-rw-r--r--drivers/net/sfc/net_driver.h2
-rw-r--r--drivers/net/sfc/nic.c19
-rw-r--r--drivers/net/sfc/nic.h1
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
1122static int efx_probe_nic(struct efx_nic *efx) 1122static 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
871static int
872efx_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
920static 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
936static 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
871const struct ethtool_ops efx_ethtool_ops = { 958const 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 */
1487static void efx_setup_rss_indir_table(struct efx_nic *efx) 1487void 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);
207extern void falcon_setup_xaui(struct efx_nic *efx); 207extern void falcon_setup_xaui(struct efx_nic *efx);
208extern int falcon_reset_xaui(struct efx_nic *efx); 208extern int falcon_reset_xaui(struct efx_nic *efx);
209extern void efx_nic_init_common(struct efx_nic *efx); 209extern void efx_nic_init_common(struct efx_nic *efx);
210extern void efx_nic_push_rx_indir_table(struct efx_nic *efx);
210 211
211int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, 212int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
212 unsigned int len); 213 unsigned int len);