aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2009-11-28 22:43:00 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-29 19:46:28 -0500
commit78c1f0a06551f6ff61bfd7c1a9302115a8135a62 (patch)
treeb39d17b5635aab76c323d8a8e4a10ff02125f068 /drivers/net/sfc
parentd3245b28ef2a45ec4e115062a38100bd06229289 (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.c16
-rw-r--r--drivers/net/sfc/selftest.c79
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. */
570static 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
566static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, 602static 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 ==