diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-12-13 00:59:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-13 00:59:24 -0500 |
commit | 766ca0fa6bf1600bdf4bc7726c74f14c8455c6b8 (patch) | |
tree | b1ea2df622753f2493b1053fda21c0db3f18a043 /drivers/net/sfc/efx.c | |
parent | 04cc8cacb01c09fba2297faf1477cd570ba43f0b (diff) |
sfc: Rework MAC, PHY and board event handling
From: Steve Hodgson <shodgson@solarflare.com>
MAC, PHY and board events may be separately enabled and signalled.
Our current arrangement of chaining the polling functions can result
in events being missed. Change them to be more independent.
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 | 63 |
1 files changed, 42 insertions, 21 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 7214ea6f7e1d..ce1c7d3cd12e 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -612,10 +612,9 @@ void efx_reconfigure_port(struct efx_nic *efx) | |||
612 | /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() | 612 | /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() |
613 | * we don't efx_reconfigure_port() if the port is disabled. Care is taken | 613 | * we don't efx_reconfigure_port() if the port is disabled. Care is taken |
614 | * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ | 614 | * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ |
615 | static void efx_reconfigure_work(struct work_struct *data) | 615 | static void efx_phy_work(struct work_struct *data) |
616 | { | 616 | { |
617 | struct efx_nic *efx = container_of(data, struct efx_nic, | 617 | struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); |
618 | reconfigure_work); | ||
619 | 618 | ||
620 | mutex_lock(&efx->mac_lock); | 619 | mutex_lock(&efx->mac_lock); |
621 | if (efx->port_enabled) | 620 | if (efx->port_enabled) |
@@ -623,6 +622,16 @@ static void efx_reconfigure_work(struct work_struct *data) | |||
623 | mutex_unlock(&efx->mac_lock); | 622 | mutex_unlock(&efx->mac_lock); |
624 | } | 623 | } |
625 | 624 | ||
625 | static void efx_mac_work(struct work_struct *data) | ||
626 | { | ||
627 | struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); | ||
628 | |||
629 | mutex_lock(&efx->mac_lock); | ||
630 | if (efx->port_enabled) | ||
631 | efx->mac_op->irq(efx); | ||
632 | mutex_unlock(&efx->mac_lock); | ||
633 | } | ||
634 | |||
626 | static int efx_probe_port(struct efx_nic *efx) | 635 | static int efx_probe_port(struct efx_nic *efx) |
627 | { | 636 | { |
628 | int rc; | 637 | int rc; |
@@ -688,7 +697,7 @@ fail: | |||
688 | 697 | ||
689 | /* Allow efx_reconfigure_port() to be scheduled, and close the window | 698 | /* Allow efx_reconfigure_port() to be scheduled, and close the window |
690 | * between efx_stop_port and efx_flush_all whereby a previously scheduled | 699 | * between efx_stop_port and efx_flush_all whereby a previously scheduled |
691 | * efx_reconfigure_port() may have been cancelled */ | 700 | * efx_phy_work()/efx_mac_work() may have been cancelled */ |
692 | static void efx_start_port(struct efx_nic *efx) | 701 | static void efx_start_port(struct efx_nic *efx) |
693 | { | 702 | { |
694 | EFX_LOG(efx, "start port\n"); | 703 | EFX_LOG(efx, "start port\n"); |
@@ -697,13 +706,14 @@ static void efx_start_port(struct efx_nic *efx) | |||
697 | mutex_lock(&efx->mac_lock); | 706 | mutex_lock(&efx->mac_lock); |
698 | efx->port_enabled = true; | 707 | efx->port_enabled = true; |
699 | __efx_reconfigure_port(efx); | 708 | __efx_reconfigure_port(efx); |
709 | efx->mac_op->irq(efx); | ||
700 | mutex_unlock(&efx->mac_lock); | 710 | mutex_unlock(&efx->mac_lock); |
701 | } | 711 | } |
702 | 712 | ||
703 | /* Prevent efx_reconfigure_work and efx_monitor() from executing, and | 713 | /* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, |
704 | * efx_set_multicast_list() from scheduling efx_reconfigure_work. | 714 | * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work |
705 | * efx_reconfigure_work can still be scheduled via NAPI processing | 715 | * and efx_mac_work may still be scheduled via NAPI processing until |
706 | * until efx_flush_all() is called */ | 716 | * efx_flush_all() is called */ |
707 | static void efx_stop_port(struct efx_nic *efx) | 717 | static void efx_stop_port(struct efx_nic *efx) |
708 | { | 718 | { |
709 | EFX_LOG(efx, "stop port\n"); | 719 | EFX_LOG(efx, "stop port\n"); |
@@ -1094,7 +1104,8 @@ static void efx_flush_all(struct efx_nic *efx) | |||
1094 | cancel_delayed_work_sync(&rx_queue->work); | 1104 | cancel_delayed_work_sync(&rx_queue->work); |
1095 | 1105 | ||
1096 | /* Stop scheduled port reconfigurations */ | 1106 | /* Stop scheduled port reconfigurations */ |
1097 | cancel_work_sync(&efx->reconfigure_work); | 1107 | cancel_work_sync(&efx->mac_work); |
1108 | cancel_work_sync(&efx->phy_work); | ||
1098 | 1109 | ||
1099 | } | 1110 | } |
1100 | 1111 | ||
@@ -1131,7 +1142,7 @@ static void efx_stop_all(struct efx_nic *efx) | |||
1131 | * window to loose phy events */ | 1142 | * window to loose phy events */ |
1132 | efx_stop_port(efx); | 1143 | efx_stop_port(efx); |
1133 | 1144 | ||
1134 | /* Flush reconfigure_work, refill_workqueue, monitor_work */ | 1145 | /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ |
1135 | efx_flush_all(efx); | 1146 | efx_flush_all(efx); |
1136 | 1147 | ||
1137 | /* Isolate the MAC from the TX and RX engines, so that queue | 1148 | /* Isolate the MAC from the TX and RX engines, so that queue |
@@ -1203,24 +1214,31 @@ static void efx_monitor(struct work_struct *data) | |||
1203 | { | 1214 | { |
1204 | struct efx_nic *efx = container_of(data, struct efx_nic, | 1215 | struct efx_nic *efx = container_of(data, struct efx_nic, |
1205 | monitor_work.work); | 1216 | monitor_work.work); |
1217 | int rc; | ||
1206 | 1218 | ||
1207 | EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", | 1219 | EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", |
1208 | raw_smp_processor_id()); | 1220 | raw_smp_processor_id()); |
1209 | 1221 | ||
1210 | |||
1211 | /* If the mac_lock is already held then it is likely a port | 1222 | /* If the mac_lock is already held then it is likely a port |
1212 | * reconfiguration is already in place, which will likely do | 1223 | * reconfiguration is already in place, which will likely do |
1213 | * most of the work of check_hw() anyway. */ | 1224 | * most of the work of check_hw() anyway. */ |
1214 | if (!mutex_trylock(&efx->mac_lock)) { | 1225 | if (!mutex_trylock(&efx->mac_lock)) |
1215 | queue_delayed_work(efx->workqueue, &efx->monitor_work, | 1226 | goto out_requeue; |
1216 | efx_monitor_interval); | 1227 | if (!efx->port_enabled) |
1217 | return; | 1228 | goto out_unlock; |
1229 | rc = efx->board_info.monitor(efx); | ||
1230 | if (rc) { | ||
1231 | EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", | ||
1232 | (rc == -ERANGE) ? "reported fault" : "failed"); | ||
1233 | efx->phy_mode |= PHY_MODE_LOW_POWER; | ||
1234 | falcon_sim_phy_event(efx); | ||
1218 | } | 1235 | } |
1236 | efx->phy_op->poll(efx); | ||
1237 | efx->mac_op->poll(efx); | ||
1219 | 1238 | ||
1220 | if (efx->port_enabled) | 1239 | out_unlock: |
1221 | efx->mac_op->check_hw(efx); | ||
1222 | mutex_unlock(&efx->mac_lock); | 1240 | mutex_unlock(&efx->mac_lock); |
1223 | 1241 | out_requeue: | |
1224 | queue_delayed_work(efx->workqueue, &efx->monitor_work, | 1242 | queue_delayed_work(efx->workqueue, &efx->monitor_work, |
1225 | efx_monitor_interval); | 1243 | efx_monitor_interval); |
1226 | } | 1244 | } |
@@ -1477,7 +1495,7 @@ static void efx_set_multicast_list(struct net_device *net_dev) | |||
1477 | return; | 1495 | return; |
1478 | 1496 | ||
1479 | if (changed) | 1497 | if (changed) |
1480 | queue_work(efx->workqueue, &efx->reconfigure_work); | 1498 | queue_work(efx->workqueue, &efx->phy_work); |
1481 | 1499 | ||
1482 | /* Create and activate new global multicast hash table */ | 1500 | /* Create and activate new global multicast hash table */ |
1483 | falcon_set_multicast_hash(efx); | 1501 | falcon_set_multicast_hash(efx); |
@@ -1800,12 +1818,14 @@ void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} | |||
1800 | 1818 | ||
1801 | static struct efx_mac_operations efx_dummy_mac_operations = { | 1819 | static struct efx_mac_operations efx_dummy_mac_operations = { |
1802 | .reconfigure = efx_port_dummy_op_void, | 1820 | .reconfigure = efx_port_dummy_op_void, |
1821 | .poll = efx_port_dummy_op_void, | ||
1822 | .irq = efx_port_dummy_op_void, | ||
1803 | }; | 1823 | }; |
1804 | 1824 | ||
1805 | static struct efx_phy_operations efx_dummy_phy_operations = { | 1825 | static struct efx_phy_operations efx_dummy_phy_operations = { |
1806 | .init = efx_port_dummy_op_int, | 1826 | .init = efx_port_dummy_op_int, |
1807 | .reconfigure = efx_port_dummy_op_void, | 1827 | .reconfigure = efx_port_dummy_op_void, |
1808 | .check_hw = efx_port_dummy_op_int, | 1828 | .poll = efx_port_dummy_op_void, |
1809 | .fini = efx_port_dummy_op_void, | 1829 | .fini = efx_port_dummy_op_void, |
1810 | .clear_interrupt = efx_port_dummy_op_void, | 1830 | .clear_interrupt = efx_port_dummy_op_void, |
1811 | }; | 1831 | }; |
@@ -1857,7 +1877,8 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, | |||
1857 | efx->mac_op = &efx_dummy_mac_operations; | 1877 | efx->mac_op = &efx_dummy_mac_operations; |
1858 | efx->phy_op = &efx_dummy_phy_operations; | 1878 | efx->phy_op = &efx_dummy_phy_operations; |
1859 | efx->mii.dev = net_dev; | 1879 | efx->mii.dev = net_dev; |
1860 | INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); | 1880 | INIT_WORK(&efx->phy_work, efx_phy_work); |
1881 | INIT_WORK(&efx->mac_work, efx_mac_work); | ||
1861 | atomic_set(&efx->netif_stop_count, 1); | 1882 | atomic_set(&efx->netif_stop_count, 1); |
1862 | 1883 | ||
1863 | for (i = 0; i < EFX_MAX_CHANNELS; i++) { | 1884 | for (i = 0; i < EFX_MAX_CHANNELS; i++) { |