diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-11-30 21:21:17 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-11-30 21:37:36 -0500 |
commit | ebf98e797b4e26ad52ace1511a0b503ee60a6cd4 (patch) | |
tree | f1857b52b3eced0485c059dac8a4882216cbf7a0 /drivers/net/ethernet | |
parent | c2f3b8e3a44b6fe9e36704e30157ebe1a88c08b1 (diff) |
sfc: Fix timekeeping in efx_mcdi_poll()
efx_mcdi_poll() uses get_seconds() to read the current time and to
implement a polling timeout. The use of this function was chosen
partly because it could easily be replaced in a co-sim environment
with a macro that read the simulated time.
Unfortunately the real get_seconds() returns the system time (real
time) which is subject to adjustment by e.g. ntpd. If the system time
is adjusted forward during a polled MCDI operation, the effective
timeout can be shorter than the intended 10 seconds, resulting in a
spurious failure. It is also possible for a backward adjustment to
delay detection of a areal failure.
Use jiffies instead, and change MCDI_RPC_TIMEOUT to be denominated in
jiffies. Also correct rounding of the timeout: check time > finish
(or rather time_after(time, finish)) and not time >= finish.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 3ef71a0f99a8..0095ce95150b 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
@@ -22,7 +22,7 @@ | |||
22 | ************************************************************************** | 22 | ************************************************************************** |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define MCDI_RPC_TIMEOUT 10 /*seconds */ | 25 | #define MCDI_RPC_TIMEOUT (10 * HZ) |
26 | 26 | ||
27 | #define MCDI_PDU(efx) \ | 27 | #define MCDI_PDU(efx) \ |
28 | (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) | 28 | (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST) |
@@ -120,7 +120,7 @@ static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) | |||
120 | static int efx_mcdi_poll(struct efx_nic *efx) | 120 | static int efx_mcdi_poll(struct efx_nic *efx) |
121 | { | 121 | { |
122 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 122 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
123 | unsigned int time, finish; | 123 | unsigned long time, finish; |
124 | unsigned int respseq, respcmd, error; | 124 | unsigned int respseq, respcmd, error; |
125 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); | 125 | unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); |
126 | unsigned int rc, spins; | 126 | unsigned int rc, spins; |
@@ -136,7 +136,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
136 | * and poll once a jiffy (approximately) | 136 | * and poll once a jiffy (approximately) |
137 | */ | 137 | */ |
138 | spins = TICK_USEC; | 138 | spins = TICK_USEC; |
139 | finish = get_seconds() + MCDI_RPC_TIMEOUT; | 139 | finish = jiffies + MCDI_RPC_TIMEOUT; |
140 | 140 | ||
141 | while (1) { | 141 | while (1) { |
142 | if (spins != 0) { | 142 | if (spins != 0) { |
@@ -146,7 +146,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
146 | schedule_timeout_uninterruptible(1); | 146 | schedule_timeout_uninterruptible(1); |
147 | } | 147 | } |
148 | 148 | ||
149 | time = get_seconds(); | 149 | time = jiffies; |
150 | 150 | ||
151 | rmb(); | 151 | rmb(); |
152 | efx_readd(efx, ®, pdu); | 152 | efx_readd(efx, ®, pdu); |
@@ -158,7 +158,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
158 | EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) | 158 | EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) |
159 | break; | 159 | break; |
160 | 160 | ||
161 | if (time >= finish) | 161 | if (time_after(time, finish)) |
162 | return -ETIMEDOUT; | 162 | return -ETIMEDOUT; |
163 | } | 163 | } |
164 | 164 | ||
@@ -257,7 +257,7 @@ static int efx_mcdi_await_completion(struct efx_nic *efx) | |||
257 | if (wait_event_timeout( | 257 | if (wait_event_timeout( |
258 | mcdi->wq, | 258 | mcdi->wq, |
259 | atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, | 259 | atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, |
260 | msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0) | 260 | MCDI_RPC_TIMEOUT) == 0) |
261 | return -ETIMEDOUT; | 261 | return -ETIMEDOUT; |
262 | 262 | ||
263 | /* Check if efx_mcdi_set_mode() switched us back to polled completions. | 263 | /* Check if efx_mcdi_set_mode() switched us back to polled completions. |