aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/efx.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-01-04 19:50:41 -0500
committerBen Hutchings <bhutchings@solarflare.com>2011-02-17 16:00:33 -0500
commit64d8ad6d745bbb596bfce3c5d0157267feba7e26 (patch)
tree1a3a93506dc8e851ea83bb95fe6b041bf9638110 /drivers/net/sfc/efx.c
parentd4726051043dd270f9a161414a8d5ced76e91dff (diff)
sfc: Implement hardware acceleration of RFS
Use the existing filter management functions to insert TCP/IPv4 and UDP/IPv4 4-tuple filters for Receive Flow Steering. For each channel, track how many RFS filters are being added during processing of received packets and scan the corresponding number of table entries for filters that may be reclaimed. Do this in batches to reduce lock overhead. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/sfc/efx.c')
-rw-r--r--drivers/net/sfc/efx.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index d4e04256730b..35b7bc52a2d1 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -21,6 +21,7 @@
21#include <linux/ethtool.h> 21#include <linux/ethtool.h>
22#include <linux/topology.h> 22#include <linux/topology.h>
23#include <linux/gfp.h> 23#include <linux/gfp.h>
24#include <linux/cpu_rmap.h>
24#include "net_driver.h" 25#include "net_driver.h"
25#include "efx.h" 26#include "efx.h"
26#include "nic.h" 27#include "nic.h"
@@ -307,6 +308,8 @@ static int efx_poll(struct napi_struct *napi, int budget)
307 channel->irq_mod_score = 0; 308 channel->irq_mod_score = 0;
308 } 309 }
309 310
311 efx_filter_rfs_expire(channel);
312
310 /* There is no race here; although napi_disable() will 313 /* There is no race here; although napi_disable() will
311 * only wait for napi_complete(), this isn't a problem 314 * only wait for napi_complete(), this isn't a problem
312 * since efx_channel_processed() will have no effect if 315 * since efx_channel_processed() will have no effect if
@@ -1175,10 +1178,32 @@ static int efx_wanted_channels(void)
1175 return count; 1178 return count;
1176} 1179}
1177 1180
1181static int
1182efx_init_rx_cpu_rmap(struct efx_nic *efx, struct msix_entry *xentries)
1183{
1184#ifdef CONFIG_RFS_ACCEL
1185 int i, rc;
1186
1187 efx->net_dev->rx_cpu_rmap = alloc_irq_cpu_rmap(efx->n_rx_channels);
1188 if (!efx->net_dev->rx_cpu_rmap)
1189 return -ENOMEM;
1190 for (i = 0; i < efx->n_rx_channels; i++) {
1191 rc = irq_cpu_rmap_add(efx->net_dev->rx_cpu_rmap,
1192 xentries[i].vector);
1193 if (rc) {
1194 free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap);
1195 efx->net_dev->rx_cpu_rmap = NULL;
1196 return rc;
1197 }
1198 }
1199#endif
1200 return 0;
1201}
1202
1178/* Probe the number and type of interrupts we are able to obtain, and 1203/* Probe the number and type of interrupts we are able to obtain, and
1179 * the resulting numbers of channels and RX queues. 1204 * the resulting numbers of channels and RX queues.
1180 */ 1205 */
1181static void efx_probe_interrupts(struct efx_nic *efx) 1206static int efx_probe_interrupts(struct efx_nic *efx)
1182{ 1207{
1183 int max_channels = 1208 int max_channels =
1184 min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS); 1209 min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
@@ -1220,6 +1245,11 @@ static void efx_probe_interrupts(struct efx_nic *efx)
1220 efx->n_tx_channels = efx->n_channels; 1245 efx->n_tx_channels = efx->n_channels;
1221 efx->n_rx_channels = efx->n_channels; 1246 efx->n_rx_channels = efx->n_channels;
1222 } 1247 }
1248 rc = efx_init_rx_cpu_rmap(efx, xentries);
1249 if (rc) {
1250 pci_disable_msix(efx->pci_dev);
1251 return rc;
1252 }
1223 for (i = 0; i < n_channels; i++) 1253 for (i = 0; i < n_channels; i++)
1224 efx_get_channel(efx, i)->irq = 1254 efx_get_channel(efx, i)->irq =
1225 xentries[i].vector; 1255 xentries[i].vector;
@@ -1253,6 +1283,8 @@ static void efx_probe_interrupts(struct efx_nic *efx)
1253 efx->n_tx_channels = 1; 1283 efx->n_tx_channels = 1;
1254 efx->legacy_irq = efx->pci_dev->irq; 1284 efx->legacy_irq = efx->pci_dev->irq;
1255 } 1285 }
1286
1287 return 0;
1256} 1288}
1257 1289
1258static void efx_remove_interrupts(struct efx_nic *efx) 1290static void efx_remove_interrupts(struct efx_nic *efx)
@@ -1289,7 +1321,9 @@ static int efx_probe_nic(struct efx_nic *efx)
1289 1321
1290 /* Determine the number of channels and queues by trying to hook 1322 /* Determine the number of channels and queues by trying to hook
1291 * in MSI-X interrupts. */ 1323 * in MSI-X interrupts. */
1292 efx_probe_interrupts(efx); 1324 rc = efx_probe_interrupts(efx);
1325 if (rc)
1326 goto fail;
1293 1327
1294 if (efx->n_channels > 1) 1328 if (efx->n_channels > 1)
1295 get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); 1329 get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
@@ -1304,6 +1338,10 @@ static int efx_probe_nic(struct efx_nic *efx)
1304 efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true); 1338 efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true);
1305 1339
1306 return 0; 1340 return 0;
1341
1342fail:
1343 efx->type->remove(efx);
1344 return rc;
1307} 1345}
1308 1346
1309static void efx_remove_nic(struct efx_nic *efx) 1347static void efx_remove_nic(struct efx_nic *efx)
@@ -1837,6 +1875,9 @@ static const struct net_device_ops efx_netdev_ops = {
1837 .ndo_poll_controller = efx_netpoll, 1875 .ndo_poll_controller = efx_netpoll,
1838#endif 1876#endif
1839 .ndo_setup_tc = efx_setup_tc, 1877 .ndo_setup_tc = efx_setup_tc,
1878#ifdef CONFIG_RFS_ACCEL
1879 .ndo_rx_flow_steer = efx_filter_rfs,
1880#endif
1840}; 1881};
1841 1882
1842static void efx_update_name(struct efx_nic *efx) 1883static void efx_update_name(struct efx_nic *efx)
@@ -2274,6 +2315,10 @@ static void efx_fini_struct(struct efx_nic *efx)
2274 */ 2315 */
2275static void efx_pci_remove_main(struct efx_nic *efx) 2316static void efx_pci_remove_main(struct efx_nic *efx)
2276{ 2317{
2318#ifdef CONFIG_RFS_ACCEL
2319 free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap);
2320 efx->net_dev->rx_cpu_rmap = NULL;
2321#endif
2277 efx_nic_fini_interrupt(efx); 2322 efx_nic_fini_interrupt(efx);
2278 efx_fini_channels(efx); 2323 efx_fini_channels(efx);
2279 efx_fini_port(efx); 2324 efx_fini_port(efx);