aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-10-08 16:43:00 -0400
committerBen Hutchings <bhutchings@solarflare.com>2013-08-21 15:20:36 -0400
commit5bc283e51327e249459caab1aff505000ae2beeb (patch)
tree8fd6c302fe5eab6e3c9946d9ef4b667eccb1b3c6
parent86094f7f38ff711f3db8497fcb4d2e109100f497 (diff)
sfc: Translate MCDI error numbers received in events
Currently we only translate error codes in efx_mcdi_poll(), but we also need to do so in efx_mcdi_ev_cpl(). The reason we didn't notice before is that the MC firmware error codes are mostly taken from Unix/Linux and no translation is necessary on most architectures. Make sure we notice any future failure by changing the sign of resprc (matching the kernel convention) and BUG if it's ever positive at command completion. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c62
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h4
2 files changed, 37 insertions, 29 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index dffadb24b364..4f3301d84f64 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -105,16 +105,39 @@ efx_mcdi_copyout(struct efx_nic *efx, efx_dword_t *outbuf, size_t outlen)
105 efx->type->mcdi_read_response(efx, outbuf, 4, outlen); 105 efx->type->mcdi_read_response(efx, outbuf, 4, outlen);
106} 106}
107 107
108static int efx_mcdi_errno(unsigned int mcdi_err)
109{
110 switch (mcdi_err) {
111 case 0:
112 return 0;
113#define TRANSLATE_ERROR(name) \
114 case MC_CMD_ERR_ ## name: \
115 return -name;
116 TRANSLATE_ERROR(ENOENT);
117 TRANSLATE_ERROR(EINTR);
118 TRANSLATE_ERROR(EACCES);
119 TRANSLATE_ERROR(EBUSY);
120 TRANSLATE_ERROR(EINVAL);
121 TRANSLATE_ERROR(EDEADLK);
122 TRANSLATE_ERROR(ENOSYS);
123 TRANSLATE_ERROR(ETIME);
124#undef TRANSLATE_ERROR
125 default:
126 return -EIO;
127 }
128}
129
108static int efx_mcdi_poll(struct efx_nic *efx) 130static int efx_mcdi_poll(struct efx_nic *efx)
109{ 131{
110 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 132 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
111 unsigned long time, finish; 133 unsigned long time, finish;
112 unsigned int respseq, respcmd, error; 134 unsigned int respseq, respcmd, error;
113 unsigned int rc, spins; 135 unsigned int spins;
114 efx_dword_t reg; 136 efx_dword_t reg;
137 int rc;
115 138
116 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */ 139 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
117 rc = -efx_mcdi_poll_reboot(efx); 140 rc = efx_mcdi_poll_reboot(efx);
118 if (rc) 141 if (rc)
119 goto out; 142 goto out;
120 143
@@ -151,32 +174,15 @@ static int efx_mcdi_poll(struct efx_nic *efx)
151 174
152 if (error && mcdi->resplen == 0) { 175 if (error && mcdi->resplen == 0) {
153 netif_err(efx, hw, efx->net_dev, "MC rebooted\n"); 176 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
154 rc = EIO; 177 rc = -EIO;
155 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) { 178 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
156 netif_err(efx, hw, efx->net_dev, 179 netif_err(efx, hw, efx->net_dev,
157 "MC response mismatch tx seq 0x%x rx seq 0x%x\n", 180 "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
158 respseq, mcdi->seqno); 181 respseq, mcdi->seqno);
159 rc = EIO; 182 rc = -EIO;
160 } else if (error) { 183 } else if (error) {
161 efx->type->mcdi_read_response(efx, &reg, 4, 4); 184 efx->type->mcdi_read_response(efx, &reg, 4, 4);
162 switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { 185 rc = efx_mcdi_errno(EFX_DWORD_FIELD(reg, EFX_DWORD_0));
163#define TRANSLATE_ERROR(name) \
164 case MC_CMD_ERR_ ## name: \
165 rc = name; \
166 break
167 TRANSLATE_ERROR(ENOENT);
168 TRANSLATE_ERROR(EINTR);
169 TRANSLATE_ERROR(EACCES);
170 TRANSLATE_ERROR(EBUSY);
171 TRANSLATE_ERROR(EINVAL);
172 TRANSLATE_ERROR(EDEADLK);
173 TRANSLATE_ERROR(ENOSYS);
174 TRANSLATE_ERROR(ETIME);
175#undef TRANSLATE_ERROR
176 default:
177 rc = EIO;
178 break;
179 }
180 } else 186 } else
181 rc = 0; 187 rc = 0;
182 188
@@ -271,7 +277,7 @@ static void efx_mcdi_release(struct efx_mcdi_iface *mcdi)
271} 277}
272 278
273static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, 279static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
274 unsigned int datalen, unsigned int errno) 280 unsigned int datalen, unsigned int mcdi_err)
275{ 281{
276 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 282 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
277 bool wake = false; 283 bool wake = false;
@@ -287,7 +293,7 @@ static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
287 "MC response mismatch tx seq 0x%x rx " 293 "MC response mismatch tx seq 0x%x rx "
288 "seq 0x%x\n", seqno, mcdi->seqno); 294 "seq 0x%x\n", seqno, mcdi->seqno);
289 } else { 295 } else {
290 mcdi->resprc = errno; 296 mcdi->resprc = efx_mcdi_errno(mcdi_err);
291 mcdi->resplen = datalen; 297 mcdi->resplen = datalen;
292 298
293 wake = true; 299 wake = true;
@@ -357,10 +363,12 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
357 * a spurious efx_mcdi_ev_cpl() running concurrently by 363 * a spurious efx_mcdi_ev_cpl() running concurrently by
358 * acquiring the iface_lock. */ 364 * acquiring the iface_lock. */
359 spin_lock_bh(&mcdi->iface_lock); 365 spin_lock_bh(&mcdi->iface_lock);
360 rc = -mcdi->resprc; 366 rc = mcdi->resprc;
361 resplen = mcdi->resplen; 367 resplen = mcdi->resplen;
362 spin_unlock_bh(&mcdi->iface_lock); 368 spin_unlock_bh(&mcdi->iface_lock);
363 369
370 BUG_ON(rc > 0);
371
364 if (rc == 0) { 372 if (rc == 0) {
365 efx_mcdi_copyout(efx, outbuf, 373 efx_mcdi_copyout(efx, outbuf,
366 min(outlen, mcdi->resplen)); 374 min(outlen, mcdi->resplen));
@@ -491,7 +499,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
491 case MCDI_EVENT_CODE_BADSSERT: 499 case MCDI_EVENT_CODE_BADSSERT:
492 netif_err(efx, hw, efx->net_dev, 500 netif_err(efx, hw, efx->net_dev,
493 "MC watchdog or assertion failure at 0x%x\n", data); 501 "MC watchdog or assertion failure at 0x%x\n", data);
494 efx_mcdi_ev_death(efx, EINTR); 502 efx_mcdi_ev_death(efx, -EINTR);
495 break; 503 break;
496 504
497 case MCDI_EVENT_CODE_PMNOTICE: 505 case MCDI_EVENT_CODE_PMNOTICE:
@@ -517,7 +525,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
517 break; 525 break;
518 case MCDI_EVENT_CODE_REBOOT: 526 case MCDI_EVENT_CODE_REBOOT:
519 netif_info(efx, hw, efx->net_dev, "MC Reboot\n"); 527 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
520 efx_mcdi_ev_death(efx, EIO); 528 efx_mcdi_ev_death(efx, -EIO);
521 break; 529 break;
522 case MCDI_EVENT_CODE_MAC_STATS_DMA: 530 case MCDI_EVENT_CODE_MAC_STATS_DMA:
523 /* MAC stats are gather lazily. We can ignore this. */ 531 /* MAC stats are gather lazily. We can ignore this. */
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 0bfed2a64399..9b536d08a162 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -42,7 +42,7 @@ enum efx_mcdi_mode {
42 * Serialised by @lock 42 * Serialised by @lock
43 * @credits: Number of spurious MCDI completion events allowed before we 43 * @credits: Number of spurious MCDI completion events allowed before we
44 * trigger a fatal error. Protected by @lock 44 * trigger a fatal error. Protected by @lock
45 * @resprc: Returned MCDI completion 45 * @resprc: Response error/success code (Linux numbering)
46 * @resplen: Returned payload length 46 * @resplen: Returned payload length
47 */ 47 */
48struct efx_mcdi_iface { 48struct efx_mcdi_iface {
@@ -52,7 +52,7 @@ struct efx_mcdi_iface {
52 enum efx_mcdi_mode mode; 52 enum efx_mcdi_mode mode;
53 unsigned int credits; 53 unsigned int credits;
54 unsigned int seqno; 54 unsigned int seqno;
55 unsigned int resprc; 55 int resprc;
56 size_t resplen; 56 size_t resplen;
57}; 57};
58 58