diff options
author | Steve Hodgson <shodgson@solarflare.com> | 2009-11-28 22:43:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 19:46:28 -0500 |
commit | 78c1f0a06551f6ff61bfd7c1a9302115a8135a62 (patch) | |
tree | b39d17b5635aab76c323d8a8e4a10ff02125f068 /drivers/net/sfc | |
parent | d3245b28ef2a45ec4e115062a38100bd06229289 (diff) |
sfc: Generalise link state monitoring
Use the efx_nic_type::monitor operation or event handling as
appropriate.
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.c | 16 | ||||
-rw-r--r-- | drivers/net/sfc/selftest.c | 79 |
2 files changed, 61 insertions, 34 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4210121eeff9..14ef27fa8416 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1174,10 +1174,18 @@ static void efx_start_all(struct efx_nic *efx) | |||
1174 | 1174 | ||
1175 | falcon_enable_interrupts(efx); | 1175 | falcon_enable_interrupts(efx); |
1176 | 1176 | ||
1177 | /* Start the hardware monitor (if there is one) if we're in RUNNING */ | 1177 | /* Start the hardware monitor if there is one. Otherwise (we're link |
1178 | if (efx->state == STATE_RUNNING && efx->type->monitor != NULL) | 1178 | * event driven), we have to poll the PHY because after an event queue |
1179 | * flush, we could have a missed a link state change */ | ||
1180 | if (efx->type->monitor != NULL) { | ||
1179 | queue_delayed_work(efx->workqueue, &efx->monitor_work, | 1181 | queue_delayed_work(efx->workqueue, &efx->monitor_work, |
1180 | efx_monitor_interval); | 1182 | efx_monitor_interval); |
1183 | } else { | ||
1184 | mutex_lock(&efx->mac_lock); | ||
1185 | if (efx->phy_op->poll(efx)) | ||
1186 | efx_link_status_changed(efx); | ||
1187 | mutex_unlock(&efx->mac_lock); | ||
1188 | } | ||
1181 | 1189 | ||
1182 | efx->type->start_stats(efx); | 1190 | efx->type->start_stats(efx); |
1183 | } | 1191 | } |
@@ -1421,6 +1429,10 @@ static int efx_net_open(struct net_device *net_dev) | |||
1421 | if (efx->phy_mode & PHY_MODE_SPECIAL) | 1429 | if (efx->phy_mode & PHY_MODE_SPECIAL) |
1422 | return -EBUSY; | 1430 | return -EBUSY; |
1423 | 1431 | ||
1432 | /* Notify the kernel of the link state polled during driver load, | ||
1433 | * before the monitor starts running */ | ||
1434 | efx_link_status_changed(efx); | ||
1435 | |||
1424 | efx_start_all(efx); | 1436 | efx_start_all(efx); |
1425 | return 0; | 1437 | return 0; |
1426 | } | 1438 | } |
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index dddeb9dfb373..f45bf7442154 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c | |||
@@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
563 | return 0; | 563 | return 0; |
564 | } | 564 | } |
565 | 565 | ||
566 | /* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but | ||
567 | * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it | ||
568 | * to delay and retry. Therefore, it's safer to just poll directly. Wait | ||
569 | * for link up and any faults to dissipate. */ | ||
570 | static int efx_wait_for_link(struct efx_nic *efx) | ||
571 | { | ||
572 | struct efx_link_state *link_state = &efx->link_state; | ||
573 | int count; | ||
574 | bool link_up; | ||
575 | |||
576 | for (count = 0; count < 40; count++) { | ||
577 | schedule_timeout_uninterruptible(HZ / 10); | ||
578 | |||
579 | if (efx->type->monitor != NULL) { | ||
580 | mutex_lock(&efx->mac_lock); | ||
581 | efx->type->monitor(efx); | ||
582 | mutex_unlock(&efx->mac_lock); | ||
583 | } else { | ||
584 | struct efx_channel *channel = &efx->channel[0]; | ||
585 | if (channel->work_pending) | ||
586 | efx_process_channel_now(channel); | ||
587 | } | ||
588 | |||
589 | mutex_lock(&efx->mac_lock); | ||
590 | link_up = link_state->up; | ||
591 | if (link_up) | ||
592 | link_up = !efx->mac_op->check_fault(efx); | ||
593 | mutex_unlock(&efx->mac_lock); | ||
594 | |||
595 | if (link_up) | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | return -ETIMEDOUT; | ||
600 | } | ||
601 | |||
566 | static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, | 602 | static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, |
567 | unsigned int loopback_modes) | 603 | unsigned int loopback_modes) |
568 | { | 604 | { |
569 | enum efx_loopback_mode mode; | 605 | enum efx_loopback_mode mode; |
570 | struct efx_loopback_state *state; | 606 | struct efx_loopback_state *state; |
571 | struct efx_tx_queue *tx_queue; | 607 | struct efx_tx_queue *tx_queue; |
572 | bool link_up; | 608 | int rc = 0; |
573 | int count, rc = 0; | ||
574 | 609 | ||
575 | /* Set the port loopback_selftest member. From this point on | 610 | /* Set the port loopback_selftest member. From this point on |
576 | * all received packets will be dropped. Mark the state as | 611 | * all received packets will be dropped. Mark the state as |
@@ -589,43 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, | |||
589 | 624 | ||
590 | /* Move the port into the specified loopback mode. */ | 625 | /* Move the port into the specified loopback mode. */ |
591 | state->flush = true; | 626 | state->flush = true; |
627 | mutex_lock(&efx->mac_lock); | ||
592 | efx->loopback_mode = mode; | 628 | efx->loopback_mode = mode; |
593 | efx_reconfigure_port(efx); | 629 | rc = __efx_reconfigure_port(efx); |
594 | 630 | mutex_unlock(&efx->mac_lock); | |
595 | /* Wait for the PHY to signal the link is up. Interrupts | 631 | if (rc) { |
596 | * are enabled for PHY's using LASI, otherwise we poll() | 632 | EFX_ERR(efx, "unable to move into %s loopback\n", |
597 | * quickly */ | 633 | LOOPBACK_MODE(efx)); |
598 | count = 0; | 634 | goto out; |
599 | do { | 635 | } |
600 | struct efx_channel *channel = &efx->channel[0]; | ||
601 | |||
602 | efx->phy_op->poll(efx); | ||
603 | schedule_timeout_uninterruptible(HZ / 10); | ||
604 | if (channel->work_pending) | ||
605 | efx_process_channel_now(channel); | ||
606 | /* Wait for PHY events to be processed */ | ||
607 | flush_workqueue(efx->workqueue); | ||
608 | rmb(); | ||
609 | |||
610 | /* We need both the PHY and MAC-PHY links to be OK */ | ||
611 | link_up = efx->link_state.up; | ||
612 | if (link_up) | ||
613 | link_up = !efx->mac_op->check_fault(efx); | ||
614 | |||
615 | } while ((++count < 20) && !link_up); | ||
616 | 636 | ||
617 | /* The link should now be up. If it isn't, there is no point | 637 | rc = efx_wait_for_link(efx); |
618 | * in attempting a loopback test */ | 638 | if (rc) { |
619 | if (!link_up) { | ||
620 | EFX_ERR(efx, "loopback %s never came up\n", | 639 | EFX_ERR(efx, "loopback %s never came up\n", |
621 | LOOPBACK_MODE(efx)); | 640 | LOOPBACK_MODE(efx)); |
622 | rc = -EIO; | ||
623 | goto out; | 641 | goto out; |
624 | } | 642 | } |
625 | 643 | ||
626 | EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", | ||
627 | LOOPBACK_MODE(efx), count); | ||
628 | |||
629 | /* Test every TX queue */ | 644 | /* Test every TX queue */ |
630 | efx_for_each_tx_queue(tx_queue, efx) { | 645 | efx_for_each_tx_queue(tx_queue, efx) { |
631 | state->offload_csum = (tx_queue->queue == | 646 | state->offload_csum = (tx_queue->queue == |