diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-09-10 02:42:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-10 15:27:34 -0400 |
commit | 4642610c77b345130d6b5a08c75d23ad98601fd5 (patch) | |
tree | bf6345d84e6dbd3a3d44ff4e050dc862f01a01fc /drivers/net/sfc/efx.c | |
parent | ecc910f520ba8f22848982ee816ad75c449b805d (diff) |
sfc: Allow changing the DMA ring sizes dynamically via ethtool
This requires some reorganisation of channel setup and teardown to
ensure that we can always roll-back a failed change.
Based on work by Steve Hodgson <shodgson@solarflare.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/efx.c')
-rw-r--r-- | drivers/net/sfc/efx.c | 218 |
1 files changed, 172 insertions, 46 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 6166e2207160..f702f1fb63b6 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -201,10 +201,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); | |||
201 | * Utility functions and prototypes | 201 | * Utility functions and prototypes |
202 | * | 202 | * |
203 | *************************************************************************/ | 203 | *************************************************************************/ |
204 | static void efx_remove_channel(struct efx_channel *channel); | 204 | |
205 | static void efx_remove_channels(struct efx_nic *efx); | ||
205 | static void efx_remove_port(struct efx_nic *efx); | 206 | static void efx_remove_port(struct efx_nic *efx); |
206 | static void efx_fini_napi(struct efx_nic *efx); | 207 | static void efx_fini_napi(struct efx_nic *efx); |
207 | static void efx_fini_channels(struct efx_nic *efx); | 208 | static void efx_fini_struct(struct efx_nic *efx); |
209 | static void efx_start_all(struct efx_nic *efx); | ||
210 | static void efx_stop_all(struct efx_nic *efx); | ||
208 | 211 | ||
209 | #define EFX_ASSERT_RESET_SERIALISED(efx) \ | 212 | #define EFX_ASSERT_RESET_SERIALISED(efx) \ |
210 | do { \ | 213 | do { \ |
@@ -413,6 +416,63 @@ static void efx_remove_eventq(struct efx_channel *channel) | |||
413 | * | 416 | * |
414 | *************************************************************************/ | 417 | *************************************************************************/ |
415 | 418 | ||
419 | /* Allocate and initialise a channel structure, optionally copying | ||
420 | * parameters (but not resources) from an old channel structure. */ | ||
421 | static struct efx_channel * | ||
422 | efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) | ||
423 | { | ||
424 | struct efx_channel *channel; | ||
425 | struct efx_rx_queue *rx_queue; | ||
426 | struct efx_tx_queue *tx_queue; | ||
427 | int j; | ||
428 | |||
429 | if (old_channel) { | ||
430 | channel = kmalloc(sizeof(*channel), GFP_KERNEL); | ||
431 | if (!channel) | ||
432 | return NULL; | ||
433 | |||
434 | *channel = *old_channel; | ||
435 | |||
436 | memset(&channel->eventq, 0, sizeof(channel->eventq)); | ||
437 | |||
438 | rx_queue = &channel->rx_queue; | ||
439 | rx_queue->buffer = NULL; | ||
440 | memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); | ||
441 | |||
442 | for (j = 0; j < EFX_TXQ_TYPES; j++) { | ||
443 | tx_queue = &channel->tx_queue[j]; | ||
444 | if (tx_queue->channel) | ||
445 | tx_queue->channel = channel; | ||
446 | tx_queue->buffer = NULL; | ||
447 | memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); | ||
448 | } | ||
449 | } else { | ||
450 | channel = kzalloc(sizeof(*channel), GFP_KERNEL); | ||
451 | if (!channel) | ||
452 | return NULL; | ||
453 | |||
454 | channel->efx = efx; | ||
455 | channel->channel = i; | ||
456 | |||
457 | for (j = 0; j < EFX_TXQ_TYPES; j++) { | ||
458 | tx_queue = &channel->tx_queue[j]; | ||
459 | tx_queue->efx = efx; | ||
460 | tx_queue->queue = i * EFX_TXQ_TYPES + j; | ||
461 | tx_queue->channel = channel; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | spin_lock_init(&channel->tx_stop_lock); | ||
466 | atomic_set(&channel->tx_stop_count, 1); | ||
467 | |||
468 | rx_queue = &channel->rx_queue; | ||
469 | rx_queue->efx = efx; | ||
470 | setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, | ||
471 | (unsigned long)rx_queue); | ||
472 | |||
473 | return channel; | ||
474 | } | ||
475 | |||
416 | static int efx_probe_channel(struct efx_channel *channel) | 476 | static int efx_probe_channel(struct efx_channel *channel) |
417 | { | 477 | { |
418 | struct efx_tx_queue *tx_queue; | 478 | struct efx_tx_queue *tx_queue; |
@@ -469,11 +529,38 @@ static void efx_set_channel_names(struct efx_nic *efx) | |||
469 | number -= efx->n_rx_channels; | 529 | number -= efx->n_rx_channels; |
470 | } | 530 | } |
471 | } | 531 | } |
472 | snprintf(channel->name, sizeof(channel->name), | 532 | snprintf(efx->channel_name[channel->channel], |
533 | sizeof(efx->channel_name[0]), | ||
473 | "%s%s-%d", efx->name, type, number); | 534 | "%s%s-%d", efx->name, type, number); |
474 | } | 535 | } |
475 | } | 536 | } |
476 | 537 | ||
538 | static int efx_probe_channels(struct efx_nic *efx) | ||
539 | { | ||
540 | struct efx_channel *channel; | ||
541 | int rc; | ||
542 | |||
543 | /* Restart special buffer allocation */ | ||
544 | efx->next_buffer_table = 0; | ||
545 | |||
546 | efx_for_each_channel(channel, efx) { | ||
547 | rc = efx_probe_channel(channel); | ||
548 | if (rc) { | ||
549 | netif_err(efx, probe, efx->net_dev, | ||
550 | "failed to create channel %d\n", | ||
551 | channel->channel); | ||
552 | goto fail; | ||
553 | } | ||
554 | } | ||
555 | efx_set_channel_names(efx); | ||
556 | |||
557 | return 0; | ||
558 | |||
559 | fail: | ||
560 | efx_remove_channels(efx); | ||
561 | return rc; | ||
562 | } | ||
563 | |||
477 | /* Channels are shutdown and reinitialised whilst the NIC is running | 564 | /* Channels are shutdown and reinitialised whilst the NIC is running |
478 | * to propagate configuration changes (mtu, checksum offload), or | 565 | * to propagate configuration changes (mtu, checksum offload), or |
479 | * to clear hardware error conditions | 566 | * to clear hardware error conditions |
@@ -611,6 +698,75 @@ static void efx_remove_channel(struct efx_channel *channel) | |||
611 | efx_remove_eventq(channel); | 698 | efx_remove_eventq(channel); |
612 | } | 699 | } |
613 | 700 | ||
701 | static void efx_remove_channels(struct efx_nic *efx) | ||
702 | { | ||
703 | struct efx_channel *channel; | ||
704 | |||
705 | efx_for_each_channel(channel, efx) | ||
706 | efx_remove_channel(channel); | ||
707 | } | ||
708 | |||
709 | int | ||
710 | efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) | ||
711 | { | ||
712 | struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; | ||
713 | u32 old_rxq_entries, old_txq_entries; | ||
714 | unsigned i; | ||
715 | int rc; | ||
716 | |||
717 | efx_stop_all(efx); | ||
718 | efx_fini_channels(efx); | ||
719 | |||
720 | /* Clone channels */ | ||
721 | memset(other_channel, 0, sizeof(other_channel)); | ||
722 | for (i = 0; i < efx->n_channels; i++) { | ||
723 | channel = efx_alloc_channel(efx, i, efx->channel[i]); | ||
724 | if (!channel) { | ||
725 | rc = -ENOMEM; | ||
726 | goto out; | ||
727 | } | ||
728 | other_channel[i] = channel; | ||
729 | } | ||
730 | |||
731 | /* Swap entry counts and channel pointers */ | ||
732 | old_rxq_entries = efx->rxq_entries; | ||
733 | old_txq_entries = efx->txq_entries; | ||
734 | efx->rxq_entries = rxq_entries; | ||
735 | efx->txq_entries = txq_entries; | ||
736 | for (i = 0; i < efx->n_channels; i++) { | ||
737 | channel = efx->channel[i]; | ||
738 | efx->channel[i] = other_channel[i]; | ||
739 | other_channel[i] = channel; | ||
740 | } | ||
741 | |||
742 | rc = efx_probe_channels(efx); | ||
743 | if (rc) | ||
744 | goto rollback; | ||
745 | |||
746 | /* Destroy old channels */ | ||
747 | for (i = 0; i < efx->n_channels; i++) | ||
748 | efx_remove_channel(other_channel[i]); | ||
749 | out: | ||
750 | /* Free unused channel structures */ | ||
751 | for (i = 0; i < efx->n_channels; i++) | ||
752 | kfree(other_channel[i]); | ||
753 | |||
754 | efx_init_channels(efx); | ||
755 | efx_start_all(efx); | ||
756 | return rc; | ||
757 | |||
758 | rollback: | ||
759 | /* Swap back */ | ||
760 | efx->rxq_entries = old_rxq_entries; | ||
761 | efx->txq_entries = old_txq_entries; | ||
762 | for (i = 0; i < efx->n_channels; i++) { | ||
763 | channel = efx->channel[i]; | ||
764 | efx->channel[i] = other_channel[i]; | ||
765 | other_channel[i] = channel; | ||
766 | } | ||
767 | goto out; | ||
768 | } | ||
769 | |||
614 | void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) | 770 | void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) |
615 | { | 771 | { |
616 | mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); | 772 | mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); |
@@ -1182,41 +1338,28 @@ static void efx_remove_nic(struct efx_nic *efx) | |||
1182 | 1338 | ||
1183 | static int efx_probe_all(struct efx_nic *efx) | 1339 | static int efx_probe_all(struct efx_nic *efx) |
1184 | { | 1340 | { |
1185 | struct efx_channel *channel; | ||
1186 | int rc; | 1341 | int rc; |
1187 | 1342 | ||
1188 | /* Create NIC */ | ||
1189 | rc = efx_probe_nic(efx); | 1343 | rc = efx_probe_nic(efx); |
1190 | if (rc) { | 1344 | if (rc) { |
1191 | netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); | 1345 | netif_err(efx, probe, efx->net_dev, "failed to create NIC\n"); |
1192 | goto fail1; | 1346 | goto fail1; |
1193 | } | 1347 | } |
1194 | 1348 | ||
1195 | /* Create port */ | ||
1196 | rc = efx_probe_port(efx); | 1349 | rc = efx_probe_port(efx); |
1197 | if (rc) { | 1350 | if (rc) { |
1198 | netif_err(efx, probe, efx->net_dev, "failed to create port\n"); | 1351 | netif_err(efx, probe, efx->net_dev, "failed to create port\n"); |
1199 | goto fail2; | 1352 | goto fail2; |
1200 | } | 1353 | } |
1201 | 1354 | ||
1202 | /* Create channels */ | ||
1203 | efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; | 1355 | efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; |
1204 | efx_for_each_channel(channel, efx) { | 1356 | rc = efx_probe_channels(efx); |
1205 | rc = efx_probe_channel(channel); | 1357 | if (rc) |
1206 | if (rc) { | 1358 | goto fail3; |
1207 | netif_err(efx, probe, efx->net_dev, | ||
1208 | "failed to create channel %d\n", | ||
1209 | channel->channel); | ||
1210 | goto fail3; | ||
1211 | } | ||
1212 | } | ||
1213 | efx_set_channel_names(efx); | ||
1214 | 1359 | ||
1215 | return 0; | 1360 | return 0; |
1216 | 1361 | ||
1217 | fail3: | 1362 | fail3: |
1218 | efx_for_each_channel(channel, efx) | ||
1219 | efx_remove_channel(channel); | ||
1220 | efx_remove_port(efx); | 1363 | efx_remove_port(efx); |
1221 | fail2: | 1364 | fail2: |
1222 | efx_remove_nic(efx); | 1365 | efx_remove_nic(efx); |
@@ -1346,10 +1489,7 @@ static void efx_stop_all(struct efx_nic *efx) | |||
1346 | 1489 | ||
1347 | static void efx_remove_all(struct efx_nic *efx) | 1490 | static void efx_remove_all(struct efx_nic *efx) |
1348 | { | 1491 | { |
1349 | struct efx_channel *channel; | 1492 | efx_remove_channels(efx); |
1350 | |||
1351 | efx_for_each_channel(channel, efx) | ||
1352 | efx_remove_channel(channel); | ||
1353 | efx_remove_port(efx); | 1493 | efx_remove_port(efx); |
1354 | efx_remove_nic(efx); | 1494 | efx_remove_nic(efx); |
1355 | } | 1495 | } |
@@ -2058,10 +2198,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { | |||
2058 | static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | 2198 | static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, |
2059 | struct pci_dev *pci_dev, struct net_device *net_dev) | 2199 | struct pci_dev *pci_dev, struct net_device *net_dev) |
2060 | { | 2200 | { |
2061 | struct efx_channel *channel; | 2201 | int i; |
2062 | struct efx_tx_queue *tx_queue; | ||
2063 | struct efx_rx_queue *rx_queue; | ||
2064 | int i, j; | ||
2065 | 2202 | ||
2066 | /* Initialise common structures */ | 2203 | /* Initialise common structures */ |
2067 | memset(efx, 0, sizeof(*efx)); | 2204 | memset(efx, 0, sizeof(*efx)); |
@@ -2089,24 +2226,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
2089 | INIT_WORK(&efx->mac_work, efx_mac_work); | 2226 | INIT_WORK(&efx->mac_work, efx_mac_work); |
2090 | 2227 | ||
2091 | for (i = 0; i < EFX_MAX_CHANNELS; i++) { | 2228 | for (i = 0; i < EFX_MAX_CHANNELS; i++) { |
2092 | efx->channel[i] = kzalloc(sizeof(*channel), GFP_KERNEL); | 2229 | efx->channel[i] = efx_alloc_channel(efx, i, NULL); |
2093 | channel = efx->channel[i]; | 2230 | if (!efx->channel[i]) |
2094 | channel->efx = efx; | 2231 | goto fail; |
2095 | channel->channel = i; | ||
2096 | spin_lock_init(&channel->tx_stop_lock); | ||
2097 | atomic_set(&channel->tx_stop_count, 1); | ||
2098 | |||
2099 | for (j = 0; j < EFX_TXQ_TYPES; j++) { | ||
2100 | tx_queue = &channel->tx_queue[j]; | ||
2101 | tx_queue->efx = efx; | ||
2102 | tx_queue->queue = i * EFX_TXQ_TYPES + j; | ||
2103 | tx_queue->channel = channel; | ||
2104 | } | ||
2105 | |||
2106 | rx_queue = &channel->rx_queue; | ||
2107 | rx_queue->efx = efx; | ||
2108 | setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, | ||
2109 | (unsigned long)rx_queue); | ||
2110 | } | 2232 | } |
2111 | 2233 | ||
2112 | efx->type = type; | 2234 | efx->type = type; |
@@ -2122,9 +2244,13 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
2122 | pci_name(pci_dev)); | 2244 | pci_name(pci_dev)); |
2123 | efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); | 2245 | efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); |
2124 | if (!efx->workqueue) | 2246 | if (!efx->workqueue) |
2125 | return -ENOMEM; | 2247 | goto fail; |
2126 | 2248 | ||
2127 | return 0; | 2249 | return 0; |
2250 | |||
2251 | fail: | ||
2252 | efx_fini_struct(efx); | ||
2253 | return -ENOMEM; | ||
2128 | } | 2254 | } |
2129 | 2255 | ||
2130 | static void efx_fini_struct(struct efx_nic *efx) | 2256 | static void efx_fini_struct(struct efx_nic *efx) |