diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-13 18:45:02 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-15 19:25:10 -0500 |
commit | 7f967c011ae9c59fc7e7a017070ef7b22a5a4fbf (patch) | |
tree | c3ad2e039a8596ecbf9c7d1dc58bc8a251ecd8d2 /drivers/net/ethernet/sfc/efx.c | |
parent | a16e5b246c5b1aff3141ca6ae443307f3241a133 (diff) |
sfc: Add support for 'extra' channel types
Abstract some of the channel operations to allow for 'extra'
channels that do not have RX or TX queues.
- Try to assign a channel to each extra channel type that is enabled
for the NIC, but gracefully degrade if we can't allocate sufficient
MSI-X vectors
- Allow each extra channel type to generate its own channel name
- Allow channel types to disable reallocation and reinitialisation
of their channels
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/efx.c')
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 312 |
1 files changed, 204 insertions, 108 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 3a103f8972e7..0a9ab49eef95 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -186,11 +186,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); | |||
186 | * | 186 | * |
187 | *************************************************************************/ | 187 | *************************************************************************/ |
188 | 188 | ||
189 | static void efx_start_interrupts(struct efx_nic *efx); | 189 | static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq); |
190 | static void efx_stop_interrupts(struct efx_nic *efx); | 190 | static void efx_stop_interrupts(struct efx_nic *efx, bool may_keep_eventq); |
191 | static void efx_remove_channel(struct efx_channel *channel); | ||
191 | static void efx_remove_channels(struct efx_nic *efx); | 192 | static void efx_remove_channels(struct efx_nic *efx); |
193 | static const struct efx_channel_type efx_default_channel_type; | ||
192 | static void efx_remove_port(struct efx_nic *efx); | 194 | static void efx_remove_port(struct efx_nic *efx); |
193 | static void efx_init_napi(struct efx_nic *efx); | 195 | static void efx_init_napi_channel(struct efx_channel *channel); |
194 | static void efx_fini_napi(struct efx_nic *efx); | 196 | static void efx_fini_napi(struct efx_nic *efx); |
195 | static void efx_fini_napi_channel(struct efx_channel *channel); | 197 | static void efx_fini_napi_channel(struct efx_channel *channel); |
196 | static void efx_fini_struct(struct efx_nic *efx); | 198 | static void efx_fini_struct(struct efx_nic *efx); |
@@ -439,8 +441,7 @@ static void efx_remove_eventq(struct efx_channel *channel) | |||
439 | * | 441 | * |
440 | *************************************************************************/ | 442 | *************************************************************************/ |
441 | 443 | ||
442 | /* Allocate and initialise a channel structure, optionally copying | 444 | /* Allocate and initialise a channel structure. */ |
443 | * parameters (but not resources) from an old channel structure. */ | ||
444 | static struct efx_channel * | 445 | static struct efx_channel * |
445 | efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) | 446 | efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) |
446 | { | 447 | { |
@@ -449,45 +450,60 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) | |||
449 | struct efx_tx_queue *tx_queue; | 450 | struct efx_tx_queue *tx_queue; |
450 | int j; | 451 | int j; |
451 | 452 | ||
452 | if (old_channel) { | 453 | channel = kzalloc(sizeof(*channel), GFP_KERNEL); |
453 | channel = kmalloc(sizeof(*channel), GFP_KERNEL); | 454 | if (!channel) |
454 | if (!channel) | 455 | return NULL; |
455 | return NULL; | ||
456 | 456 | ||
457 | *channel = *old_channel; | 457 | channel->efx = efx; |
458 | channel->channel = i; | ||
459 | channel->type = &efx_default_channel_type; | ||
458 | 460 | ||
459 | channel->napi_dev = NULL; | 461 | for (j = 0; j < EFX_TXQ_TYPES; j++) { |
460 | memset(&channel->eventq, 0, sizeof(channel->eventq)); | 462 | tx_queue = &channel->tx_queue[j]; |
463 | tx_queue->efx = efx; | ||
464 | tx_queue->queue = i * EFX_TXQ_TYPES + j; | ||
465 | tx_queue->channel = channel; | ||
466 | } | ||
461 | 467 | ||
462 | rx_queue = &channel->rx_queue; | 468 | rx_queue = &channel->rx_queue; |
463 | rx_queue->buffer = NULL; | 469 | rx_queue->efx = efx; |
464 | memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); | 470 | setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, |
471 | (unsigned long)rx_queue); | ||
465 | 472 | ||
466 | for (j = 0; j < EFX_TXQ_TYPES; j++) { | 473 | return channel; |
467 | tx_queue = &channel->tx_queue[j]; | 474 | } |
468 | if (tx_queue->channel) | 475 | |
469 | tx_queue->channel = channel; | 476 | /* Allocate and initialise a channel structure, copying parameters |
470 | tx_queue->buffer = NULL; | 477 | * (but not resources) from an old channel structure. |
471 | memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); | 478 | */ |
472 | } | 479 | static struct efx_channel * |
473 | } else { | 480 | efx_copy_channel(const struct efx_channel *old_channel) |
474 | channel = kzalloc(sizeof(*channel), GFP_KERNEL); | 481 | { |
475 | if (!channel) | 482 | struct efx_channel *channel; |
476 | return NULL; | 483 | struct efx_rx_queue *rx_queue; |
484 | struct efx_tx_queue *tx_queue; | ||
485 | int j; | ||
477 | 486 | ||
478 | channel->efx = efx; | 487 | channel = kmalloc(sizeof(*channel), GFP_KERNEL); |
479 | channel->channel = i; | 488 | if (!channel) |
489 | return NULL; | ||
490 | |||
491 | *channel = *old_channel; | ||
492 | |||
493 | channel->napi_dev = NULL; | ||
494 | memset(&channel->eventq, 0, sizeof(channel->eventq)); | ||
480 | 495 | ||
481 | for (j = 0; j < EFX_TXQ_TYPES; j++) { | 496 | for (j = 0; j < EFX_TXQ_TYPES; j++) { |
482 | tx_queue = &channel->tx_queue[j]; | 497 | tx_queue = &channel->tx_queue[j]; |
483 | tx_queue->efx = efx; | 498 | if (tx_queue->channel) |
484 | tx_queue->queue = i * EFX_TXQ_TYPES + j; | ||
485 | tx_queue->channel = channel; | 499 | tx_queue->channel = channel; |
486 | } | 500 | tx_queue->buffer = NULL; |
501 | memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); | ||
487 | } | 502 | } |
488 | 503 | ||
489 | rx_queue = &channel->rx_queue; | 504 | rx_queue = &channel->rx_queue; |
490 | rx_queue->efx = efx; | 505 | rx_queue->buffer = NULL; |
506 | memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); | ||
491 | setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, | 507 | setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill, |
492 | (unsigned long)rx_queue); | 508 | (unsigned long)rx_queue); |
493 | 509 | ||
@@ -503,57 +519,62 @@ static int efx_probe_channel(struct efx_channel *channel) | |||
503 | netif_dbg(channel->efx, probe, channel->efx->net_dev, | 519 | netif_dbg(channel->efx, probe, channel->efx->net_dev, |
504 | "creating channel %d\n", channel->channel); | 520 | "creating channel %d\n", channel->channel); |
505 | 521 | ||
522 | rc = channel->type->pre_probe(channel); | ||
523 | if (rc) | ||
524 | goto fail; | ||
525 | |||
506 | rc = efx_probe_eventq(channel); | 526 | rc = efx_probe_eventq(channel); |
507 | if (rc) | 527 | if (rc) |
508 | goto fail1; | 528 | goto fail; |
509 | 529 | ||
510 | efx_for_each_channel_tx_queue(tx_queue, channel) { | 530 | efx_for_each_channel_tx_queue(tx_queue, channel) { |
511 | rc = efx_probe_tx_queue(tx_queue); | 531 | rc = efx_probe_tx_queue(tx_queue); |
512 | if (rc) | 532 | if (rc) |
513 | goto fail2; | 533 | goto fail; |
514 | } | 534 | } |
515 | 535 | ||
516 | efx_for_each_channel_rx_queue(rx_queue, channel) { | 536 | efx_for_each_channel_rx_queue(rx_queue, channel) { |
517 | rc = efx_probe_rx_queue(rx_queue); | 537 | rc = efx_probe_rx_queue(rx_queue); |
518 | if (rc) | 538 | if (rc) |
519 | goto fail3; | 539 | goto fail; |
520 | } | 540 | } |
521 | 541 | ||
522 | channel->n_rx_frm_trunc = 0; | 542 | channel->n_rx_frm_trunc = 0; |
523 | 543 | ||
524 | return 0; | 544 | return 0; |
525 | 545 | ||
526 | fail3: | 546 | fail: |
527 | efx_for_each_channel_rx_queue(rx_queue, channel) | 547 | efx_remove_channel(channel); |
528 | efx_remove_rx_queue(rx_queue); | ||
529 | fail2: | ||
530 | efx_for_each_channel_tx_queue(tx_queue, channel) | ||
531 | efx_remove_tx_queue(tx_queue); | ||
532 | fail1: | ||
533 | return rc; | 548 | return rc; |
534 | } | 549 | } |
535 | 550 | ||
551 | static void | ||
552 | efx_get_channel_name(struct efx_channel *channel, char *buf, size_t len) | ||
553 | { | ||
554 | struct efx_nic *efx = channel->efx; | ||
555 | const char *type; | ||
556 | int number; | ||
557 | |||
558 | number = channel->channel; | ||
559 | if (efx->tx_channel_offset == 0) { | ||
560 | type = ""; | ||
561 | } else if (channel->channel < efx->tx_channel_offset) { | ||
562 | type = "-rx"; | ||
563 | } else { | ||
564 | type = "-tx"; | ||
565 | number -= efx->tx_channel_offset; | ||
566 | } | ||
567 | snprintf(buf, len, "%s%s-%d", efx->name, type, number); | ||
568 | } | ||
536 | 569 | ||
537 | static void efx_set_channel_names(struct efx_nic *efx) | 570 | static void efx_set_channel_names(struct efx_nic *efx) |
538 | { | 571 | { |
539 | struct efx_channel *channel; | 572 | struct efx_channel *channel; |
540 | const char *type = ""; | ||
541 | int number; | ||
542 | 573 | ||
543 | efx_for_each_channel(channel, efx) { | 574 | efx_for_each_channel(channel, efx) |
544 | number = channel->channel; | 575 | channel->type->get_name(channel, |
545 | if (efx->n_channels > efx->n_rx_channels) { | 576 | efx->channel_name[channel->channel], |
546 | if (channel->channel < efx->n_rx_channels) { | 577 | sizeof(efx->channel_name[0])); |
547 | type = "-rx"; | ||
548 | } else { | ||
549 | type = "-tx"; | ||
550 | number -= efx->n_rx_channels; | ||
551 | } | ||
552 | } | ||
553 | snprintf(efx->channel_name[channel->channel], | ||
554 | sizeof(efx->channel_name[0]), | ||
555 | "%s%s-%d", efx->name, type, number); | ||
556 | } | ||
557 | } | 578 | } |
558 | 579 | ||
559 | static int efx_probe_channels(struct efx_nic *efx) | 580 | static int efx_probe_channels(struct efx_nic *efx) |
@@ -697,16 +718,40 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) | |||
697 | { | 718 | { |
698 | struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; | 719 | struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; |
699 | u32 old_rxq_entries, old_txq_entries; | 720 | u32 old_rxq_entries, old_txq_entries; |
700 | unsigned i; | 721 | unsigned i, next_buffer_table = 0; |
701 | int rc; | 722 | int rc = 0; |
723 | |||
724 | /* Not all channels should be reallocated. We must avoid | ||
725 | * reallocating their buffer table entries. | ||
726 | */ | ||
727 | efx_for_each_channel(channel, efx) { | ||
728 | struct efx_rx_queue *rx_queue; | ||
729 | struct efx_tx_queue *tx_queue; | ||
730 | |||
731 | if (channel->type->copy) | ||
732 | continue; | ||
733 | next_buffer_table = max(next_buffer_table, | ||
734 | channel->eventq.index + | ||
735 | channel->eventq.entries); | ||
736 | efx_for_each_channel_rx_queue(rx_queue, channel) | ||
737 | next_buffer_table = max(next_buffer_table, | ||
738 | rx_queue->rxd.index + | ||
739 | rx_queue->rxd.entries); | ||
740 | efx_for_each_channel_tx_queue(tx_queue, channel) | ||
741 | next_buffer_table = max(next_buffer_table, | ||
742 | tx_queue->txd.index + | ||
743 | tx_queue->txd.entries); | ||
744 | } | ||
702 | 745 | ||
703 | efx_stop_all(efx); | 746 | efx_stop_all(efx); |
704 | efx_stop_interrupts(efx); | 747 | efx_stop_interrupts(efx, true); |
705 | 748 | ||
706 | /* Clone channels */ | 749 | /* Clone channels (where possible) */ |
707 | memset(other_channel, 0, sizeof(other_channel)); | 750 | memset(other_channel, 0, sizeof(other_channel)); |
708 | for (i = 0; i < efx->n_channels; i++) { | 751 | for (i = 0; i < efx->n_channels; i++) { |
709 | channel = efx_alloc_channel(efx, i, efx->channel[i]); | 752 | channel = efx->channel[i]; |
753 | if (channel->type->copy) | ||
754 | channel = channel->type->copy(channel); | ||
710 | if (!channel) { | 755 | if (!channel) { |
711 | rc = -ENOMEM; | 756 | rc = -ENOMEM; |
712 | goto out; | 757 | goto out; |
@@ -725,23 +770,31 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) | |||
725 | other_channel[i] = channel; | 770 | other_channel[i] = channel; |
726 | } | 771 | } |
727 | 772 | ||
728 | rc = efx_probe_channels(efx); | 773 | /* Restart buffer table allocation */ |
729 | if (rc) | 774 | efx->next_buffer_table = next_buffer_table; |
730 | goto rollback; | ||
731 | |||
732 | efx_init_napi(efx); | ||
733 | 775 | ||
734 | /* Destroy old channels */ | ||
735 | for (i = 0; i < efx->n_channels; i++) { | 776 | for (i = 0; i < efx->n_channels; i++) { |
736 | efx_fini_napi_channel(other_channel[i]); | 777 | channel = efx->channel[i]; |
737 | efx_remove_channel(other_channel[i]); | 778 | if (!channel->type->copy) |
779 | continue; | ||
780 | rc = efx_probe_channel(channel); | ||
781 | if (rc) | ||
782 | goto rollback; | ||
783 | efx_init_napi_channel(efx->channel[i]); | ||
738 | } | 784 | } |
785 | |||
739 | out: | 786 | out: |
740 | /* Free unused channel structures */ | 787 | /* Destroy unused channel structures */ |
741 | for (i = 0; i < efx->n_channels; i++) | 788 | for (i = 0; i < efx->n_channels; i++) { |
742 | kfree(other_channel[i]); | 789 | channel = other_channel[i]; |
790 | if (channel && channel->type->copy) { | ||
791 | efx_fini_napi_channel(channel); | ||
792 | efx_remove_channel(channel); | ||
793 | kfree(channel); | ||
794 | } | ||
795 | } | ||
743 | 796 | ||
744 | efx_start_interrupts(efx); | 797 | efx_start_interrupts(efx, true); |
745 | efx_start_all(efx); | 798 | efx_start_all(efx); |
746 | return rc; | 799 | return rc; |
747 | 800 | ||
@@ -762,6 +815,18 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) | |||
762 | mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); | 815 | mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100)); |
763 | } | 816 | } |
764 | 817 | ||
818 | static const struct efx_channel_type efx_default_channel_type = { | ||
819 | .pre_probe = efx_channel_dummy_op_int, | ||
820 | .get_name = efx_get_channel_name, | ||
821 | .copy = efx_copy_channel, | ||
822 | .keep_eventq = false, | ||
823 | }; | ||
824 | |||
825 | int efx_channel_dummy_op_int(struct efx_channel *channel) | ||
826 | { | ||
827 | return 0; | ||
828 | } | ||
829 | |||
765 | /************************************************************************** | 830 | /************************************************************************** |
766 | * | 831 | * |
767 | * Port handling | 832 | * Port handling |
@@ -1162,9 +1227,14 @@ static int efx_probe_interrupts(struct efx_nic *efx) | |||
1162 | { | 1227 | { |
1163 | unsigned int max_channels = | 1228 | unsigned int max_channels = |
1164 | min(efx->type->phys_addr_channels, EFX_MAX_CHANNELS); | 1229 | min(efx->type->phys_addr_channels, EFX_MAX_CHANNELS); |
1165 | unsigned int i; | 1230 | unsigned int extra_channels = 0; |
1231 | unsigned int i, j; | ||
1166 | int rc; | 1232 | int rc; |
1167 | 1233 | ||
1234 | for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) | ||
1235 | if (efx->extra_channel_type[i]) | ||
1236 | ++extra_channels; | ||
1237 | |||
1168 | if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { | 1238 | if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { |
1169 | struct msix_entry xentries[EFX_MAX_CHANNELS]; | 1239 | struct msix_entry xentries[EFX_MAX_CHANNELS]; |
1170 | unsigned int n_channels; | 1240 | unsigned int n_channels; |
@@ -1172,6 +1242,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) | |||
1172 | n_channels = efx_wanted_parallelism(); | 1242 | n_channels = efx_wanted_parallelism(); |
1173 | if (separate_tx_channels) | 1243 | if (separate_tx_channels) |
1174 | n_channels *= 2; | 1244 | n_channels *= 2; |
1245 | n_channels += extra_channels; | ||
1175 | n_channels = min(n_channels, max_channels); | 1246 | n_channels = min(n_channels, max_channels); |
1176 | 1247 | ||
1177 | for (i = 0; i < n_channels; i++) | 1248 | for (i = 0; i < n_channels; i++) |
@@ -1191,22 +1262,23 @@ static int efx_probe_interrupts(struct efx_nic *efx) | |||
1191 | 1262 | ||
1192 | if (rc == 0) { | 1263 | if (rc == 0) { |
1193 | efx->n_channels = n_channels; | 1264 | efx->n_channels = n_channels; |
1265 | if (n_channels > extra_channels) | ||
1266 | n_channels -= extra_channels; | ||
1194 | if (separate_tx_channels) { | 1267 | if (separate_tx_channels) { |
1195 | efx->n_tx_channels = | 1268 | efx->n_tx_channels = max(n_channels / 2, 1U); |
1196 | max(efx->n_channels / 2, 1U); | 1269 | efx->n_rx_channels = max(n_channels - |
1197 | efx->n_rx_channels = | 1270 | efx->n_tx_channels, |
1198 | max(efx->n_channels - | 1271 | 1U); |
1199 | efx->n_tx_channels, 1U); | ||
1200 | } else { | 1272 | } else { |
1201 | efx->n_tx_channels = efx->n_channels; | 1273 | efx->n_tx_channels = n_channels; |
1202 | efx->n_rx_channels = efx->n_channels; | 1274 | efx->n_rx_channels = n_channels; |
1203 | } | 1275 | } |
1204 | rc = efx_init_rx_cpu_rmap(efx, xentries); | 1276 | rc = efx_init_rx_cpu_rmap(efx, xentries); |
1205 | if (rc) { | 1277 | if (rc) { |
1206 | pci_disable_msix(efx->pci_dev); | 1278 | pci_disable_msix(efx->pci_dev); |
1207 | return rc; | 1279 | return rc; |
1208 | } | 1280 | } |
1209 | for (i = 0; i < n_channels; i++) | 1281 | for (i = 0; i < efx->n_channels; i++) |
1210 | efx_get_channel(efx, i)->irq = | 1282 | efx_get_channel(efx, i)->irq = |
1211 | xentries[i].vector; | 1283 | xentries[i].vector; |
1212 | } else { | 1284 | } else { |
@@ -1240,11 +1312,26 @@ static int efx_probe_interrupts(struct efx_nic *efx) | |||
1240 | efx->legacy_irq = efx->pci_dev->irq; | 1312 | efx->legacy_irq = efx->pci_dev->irq; |
1241 | } | 1313 | } |
1242 | 1314 | ||
1315 | /* Assign extra channels if possible */ | ||
1316 | j = efx->n_channels; | ||
1317 | for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) { | ||
1318 | if (!efx->extra_channel_type[i]) | ||
1319 | continue; | ||
1320 | if (efx->interrupt_mode != EFX_INT_MODE_MSIX || | ||
1321 | efx->n_channels <= extra_channels) { | ||
1322 | efx->extra_channel_type[i]->handle_no_channel(efx); | ||
1323 | } else { | ||
1324 | --j; | ||
1325 | efx_get_channel(efx, j)->type = | ||
1326 | efx->extra_channel_type[i]; | ||
1327 | } | ||
1328 | } | ||
1329 | |||
1243 | return 0; | 1330 | return 0; |
1244 | } | 1331 | } |
1245 | 1332 | ||
1246 | /* Enable interrupts, then probe and start the event queues */ | 1333 | /* Enable interrupts, then probe and start the event queues */ |
1247 | static void efx_start_interrupts(struct efx_nic *efx) | 1334 | static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq) |
1248 | { | 1335 | { |
1249 | struct efx_channel *channel; | 1336 | struct efx_channel *channel; |
1250 | 1337 | ||
@@ -1253,14 +1340,15 @@ static void efx_start_interrupts(struct efx_nic *efx) | |||
1253 | efx_nic_enable_interrupts(efx); | 1340 | efx_nic_enable_interrupts(efx); |
1254 | 1341 | ||
1255 | efx_for_each_channel(channel, efx) { | 1342 | efx_for_each_channel(channel, efx) { |
1256 | efx_init_eventq(channel); | 1343 | if (!channel->type->keep_eventq || !may_keep_eventq) |
1344 | efx_init_eventq(channel); | ||
1257 | efx_start_eventq(channel); | 1345 | efx_start_eventq(channel); |
1258 | } | 1346 | } |
1259 | 1347 | ||
1260 | efx_mcdi_mode_event(efx); | 1348 | efx_mcdi_mode_event(efx); |
1261 | } | 1349 | } |
1262 | 1350 | ||
1263 | static void efx_stop_interrupts(struct efx_nic *efx) | 1351 | static void efx_stop_interrupts(struct efx_nic *efx, bool may_keep_eventq) |
1264 | { | 1352 | { |
1265 | struct efx_channel *channel; | 1353 | struct efx_channel *channel; |
1266 | 1354 | ||
@@ -1277,7 +1365,8 @@ static void efx_stop_interrupts(struct efx_nic *efx) | |||
1277 | synchronize_irq(channel->irq); | 1365 | synchronize_irq(channel->irq); |
1278 | 1366 | ||
1279 | efx_stop_eventq(channel); | 1367 | efx_stop_eventq(channel); |
1280 | efx_fini_eventq(channel); | 1368 | if (!channel->type->keep_eventq || !may_keep_eventq) |
1369 | efx_fini_eventq(channel); | ||
1281 | } | 1370 | } |
1282 | } | 1371 | } |
1283 | 1372 | ||
@@ -1383,21 +1472,22 @@ static int efx_probe_all(struct efx_nic *efx) | |||
1383 | } | 1472 | } |
1384 | 1473 | ||
1385 | efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; | 1474 | efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; |
1386 | rc = efx_probe_channels(efx); | ||
1387 | if (rc) | ||
1388 | goto fail3; | ||
1389 | 1475 | ||
1390 | rc = efx_probe_filters(efx); | 1476 | rc = efx_probe_filters(efx); |
1391 | if (rc) { | 1477 | if (rc) { |
1392 | netif_err(efx, probe, efx->net_dev, | 1478 | netif_err(efx, probe, efx->net_dev, |
1393 | "failed to create filter tables\n"); | 1479 | "failed to create filter tables\n"); |
1394 | goto fail4; | 1480 | goto fail3; |
1395 | } | 1481 | } |
1396 | 1482 | ||
1483 | rc = efx_probe_channels(efx); | ||
1484 | if (rc) | ||
1485 | goto fail4; | ||
1486 | |||
1397 | return 0; | 1487 | return 0; |
1398 | 1488 | ||
1399 | fail4: | 1489 | fail4: |
1400 | efx_remove_channels(efx); | 1490 | efx_remove_filters(efx); |
1401 | fail3: | 1491 | fail3: |
1402 | efx_remove_port(efx); | 1492 | efx_remove_port(efx); |
1403 | fail2: | 1493 | fail2: |
@@ -1482,8 +1572,8 @@ static void efx_stop_all(struct efx_nic *efx) | |||
1482 | 1572 | ||
1483 | static void efx_remove_all(struct efx_nic *efx) | 1573 | static void efx_remove_all(struct efx_nic *efx) |
1484 | { | 1574 | { |
1485 | efx_remove_filters(efx); | ||
1486 | efx_remove_channels(efx); | 1575 | efx_remove_channels(efx); |
1576 | efx_remove_filters(efx); | ||
1487 | efx_remove_port(efx); | 1577 | efx_remove_port(efx); |
1488 | efx_remove_nic(efx); | 1578 | efx_remove_nic(efx); |
1489 | } | 1579 | } |
@@ -1627,15 +1717,21 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) | |||
1627 | * | 1717 | * |
1628 | **************************************************************************/ | 1718 | **************************************************************************/ |
1629 | 1719 | ||
1720 | static void efx_init_napi_channel(struct efx_channel *channel) | ||
1721 | { | ||
1722 | struct efx_nic *efx = channel->efx; | ||
1723 | |||
1724 | channel->napi_dev = efx->net_dev; | ||
1725 | netif_napi_add(channel->napi_dev, &channel->napi_str, | ||
1726 | efx_poll, napi_weight); | ||
1727 | } | ||
1728 | |||
1630 | static void efx_init_napi(struct efx_nic *efx) | 1729 | static void efx_init_napi(struct efx_nic *efx) |
1631 | { | 1730 | { |
1632 | struct efx_channel *channel; | 1731 | struct efx_channel *channel; |
1633 | 1732 | ||
1634 | efx_for_each_channel(channel, efx) { | 1733 | efx_for_each_channel(channel, efx) |
1635 | channel->napi_dev = efx->net_dev; | 1734 | efx_init_napi_channel(channel); |
1636 | netif_napi_add(channel->napi_dev, &channel->napi_str, | ||
1637 | efx_poll, napi_weight); | ||
1638 | } | ||
1639 | } | 1735 | } |
1640 | 1736 | ||
1641 | static void efx_fini_napi_channel(struct efx_channel *channel) | 1737 | static void efx_fini_napi_channel(struct efx_channel *channel) |
@@ -2013,7 +2109,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method) | |||
2013 | efx_stop_all(efx); | 2109 | efx_stop_all(efx); |
2014 | mutex_lock(&efx->mac_lock); | 2110 | mutex_lock(&efx->mac_lock); |
2015 | 2111 | ||
2016 | efx_stop_interrupts(efx); | 2112 | efx_stop_interrupts(efx, false); |
2017 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) | 2113 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) |
2018 | efx->phy_op->fini(efx); | 2114 | efx->phy_op->fini(efx); |
2019 | efx->type->fini(efx); | 2115 | efx->type->fini(efx); |
@@ -2050,7 +2146,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) | |||
2050 | 2146 | ||
2051 | efx->type->reconfigure_mac(efx); | 2147 | efx->type->reconfigure_mac(efx); |
2052 | 2148 | ||
2053 | efx_start_interrupts(efx); | 2149 | efx_start_interrupts(efx, false); |
2054 | efx_restore_filters(efx); | 2150 | efx_restore_filters(efx); |
2055 | 2151 | ||
2056 | mutex_unlock(&efx->mac_lock); | 2152 | mutex_unlock(&efx->mac_lock); |
@@ -2314,7 +2410,7 @@ static void efx_pci_remove_main(struct efx_nic *efx) | |||
2314 | free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); | 2410 | free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); |
2315 | efx->net_dev->rx_cpu_rmap = NULL; | 2411 | efx->net_dev->rx_cpu_rmap = NULL; |
2316 | #endif | 2412 | #endif |
2317 | efx_stop_interrupts(efx); | 2413 | efx_stop_interrupts(efx, false); |
2318 | efx_nic_fini_interrupt(efx); | 2414 | efx_nic_fini_interrupt(efx); |
2319 | efx_fini_port(efx); | 2415 | efx_fini_port(efx); |
2320 | efx->type->fini(efx); | 2416 | efx->type->fini(efx); |
@@ -2341,7 +2437,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev) | |||
2341 | /* Allow any queued efx_resets() to complete */ | 2437 | /* Allow any queued efx_resets() to complete */ |
2342 | rtnl_unlock(); | 2438 | rtnl_unlock(); |
2343 | 2439 | ||
2344 | efx_stop_interrupts(efx); | 2440 | efx_stop_interrupts(efx, false); |
2345 | efx_unregister_netdev(efx); | 2441 | efx_unregister_netdev(efx); |
2346 | 2442 | ||
2347 | efx_mtd_remove(efx); | 2443 | efx_mtd_remove(efx); |
@@ -2393,7 +2489,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) | |||
2393 | rc = efx_nic_init_interrupt(efx); | 2489 | rc = efx_nic_init_interrupt(efx); |
2394 | if (rc) | 2490 | if (rc) |
2395 | goto fail5; | 2491 | goto fail5; |
2396 | efx_start_interrupts(efx); | 2492 | efx_start_interrupts(efx, false); |
2397 | 2493 | ||
2398 | return 0; | 2494 | return 0; |
2399 | 2495 | ||
@@ -2517,7 +2613,7 @@ static int efx_pm_freeze(struct device *dev) | |||
2517 | netif_device_detach(efx->net_dev); | 2613 | netif_device_detach(efx->net_dev); |
2518 | 2614 | ||
2519 | efx_stop_all(efx); | 2615 | efx_stop_all(efx); |
2520 | efx_stop_interrupts(efx); | 2616 | efx_stop_interrupts(efx, false); |
2521 | 2617 | ||
2522 | return 0; | 2618 | return 0; |
2523 | } | 2619 | } |
@@ -2528,7 +2624,7 @@ static int efx_pm_thaw(struct device *dev) | |||
2528 | 2624 | ||
2529 | efx->state = STATE_INIT; | 2625 | efx->state = STATE_INIT; |
2530 | 2626 | ||
2531 | efx_start_interrupts(efx); | 2627 | efx_start_interrupts(efx, false); |
2532 | 2628 | ||
2533 | mutex_lock(&efx->mac_lock); | 2629 | mutex_lock(&efx->mac_lock); |
2534 | efx->phy_op->reconfigure(efx); | 2630 | efx->phy_op->reconfigure(efx); |