diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi.c')
| -rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 366c8e3e3784..4b0bd8a1514d 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
| @@ -50,6 +50,7 @@ struct efx_mcdi_async_param { | |||
| 50 | static void efx_mcdi_timeout_async(unsigned long context); | 50 | static void efx_mcdi_timeout_async(unsigned long context); |
| 51 | static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, | 51 | static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, |
| 52 | bool *was_attached_out); | 52 | bool *was_attached_out); |
| 53 | static bool efx_mcdi_poll_once(struct efx_nic *efx); | ||
| 53 | 54 | ||
| 54 | static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) | 55 | static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) |
| 55 | { | 56 | { |
| @@ -237,6 +238,21 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx) | |||
| 237 | } | 238 | } |
| 238 | } | 239 | } |
| 239 | 240 | ||
| 241 | static bool efx_mcdi_poll_once(struct efx_nic *efx) | ||
| 242 | { | ||
| 243 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | ||
| 244 | |||
| 245 | rmb(); | ||
| 246 | if (!efx->type->mcdi_poll_response(efx)) | ||
| 247 | return false; | ||
| 248 | |||
| 249 | spin_lock_bh(&mcdi->iface_lock); | ||
| 250 | efx_mcdi_read_response_header(efx); | ||
| 251 | spin_unlock_bh(&mcdi->iface_lock); | ||
| 252 | |||
| 253 | return true; | ||
| 254 | } | ||
| 255 | |||
| 240 | static int efx_mcdi_poll(struct efx_nic *efx) | 256 | static int efx_mcdi_poll(struct efx_nic *efx) |
| 241 | { | 257 | { |
| 242 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); | 258 | struct efx_mcdi_iface *mcdi = efx_mcdi(efx); |
| @@ -272,18 +288,13 @@ static int efx_mcdi_poll(struct efx_nic *efx) | |||
| 272 | 288 | ||
| 273 | time = jiffies; | 289 | time = jiffies; |
| 274 | 290 | ||
| 275 | rmb(); | 291 | if (efx_mcdi_poll_once(efx)) |
| 276 | if (efx->type->mcdi_poll_response(efx)) | ||
| 277 | break; | 292 | break; |
| 278 | 293 | ||
| 279 | if (time_after(time, finish)) | 294 | if (time_after(time, finish)) |
| 280 | return -ETIMEDOUT; | 295 | return -ETIMEDOUT; |
| 281 | } | 296 | } |
| 282 | 297 | ||
| 283 | spin_lock_bh(&mcdi->iface_lock); | ||
| 284 | efx_mcdi_read_response_header(efx); | ||
| 285 | spin_unlock_bh(&mcdi->iface_lock); | ||
| 286 | |||
| 287 | /* Return rc=0 like wait_event_timeout() */ | 298 | /* Return rc=0 like wait_event_timeout() */ |
| 288 | return 0; | 299 | return 0; |
| 289 | } | 300 | } |
| @@ -619,6 +630,16 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, | |||
| 619 | rc = efx_mcdi_await_completion(efx); | 630 | rc = efx_mcdi_await_completion(efx); |
| 620 | 631 | ||
| 621 | if (rc != 0) { | 632 | if (rc != 0) { |
| 633 | netif_err(efx, hw, efx->net_dev, | ||
| 634 | "MC command 0x%x inlen %d mode %d timed out\n", | ||
| 635 | cmd, (int)inlen, mcdi->mode); | ||
| 636 | |||
| 637 | if (mcdi->mode == MCDI_MODE_EVENTS && efx_mcdi_poll_once(efx)) { | ||
| 638 | netif_err(efx, hw, efx->net_dev, | ||
| 639 | "MCDI request was completed without an event\n"); | ||
| 640 | rc = 0; | ||
| 641 | } | ||
| 642 | |||
| 622 | /* Close the race with efx_mcdi_ev_cpl() executing just too late | 643 | /* Close the race with efx_mcdi_ev_cpl() executing just too late |
| 623 | * and completing a request we've just cancelled, by ensuring | 644 | * and completing a request we've just cancelled, by ensuring |
| 624 | * that the seqno check therein fails. | 645 | * that the seqno check therein fails. |
| @@ -627,11 +648,9 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, | |||
| 627 | ++mcdi->seqno; | 648 | ++mcdi->seqno; |
| 628 | ++mcdi->credits; | 649 | ++mcdi->credits; |
| 629 | spin_unlock_bh(&mcdi->iface_lock); | 650 | spin_unlock_bh(&mcdi->iface_lock); |
| 651 | } | ||
| 630 | 652 | ||
| 631 | netif_err(efx, hw, efx->net_dev, | 653 | if (rc == 0) { |
| 632 | "MC command 0x%x inlen %d mode %d timed out\n", | ||
| 633 | cmd, (int)inlen, mcdi->mode); | ||
| 634 | } else { | ||
| 635 | size_t hdr_len, data_len; | 654 | size_t hdr_len, data_len; |
| 636 | 655 | ||
| 637 | /* At the very least we need a memory barrier here to ensure | 656 | /* At the very least we need a memory barrier here to ensure |
