Commit | Line | Data |
---|---|---|
df69ba43 SN |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */ | |
3 | ||
011c7289 AB |
4 | #include <linux/printk.h> |
5 | #include <linux/dynamic_debug.h> | |
df69ba43 | 6 | #include <linux/module.h> |
df69ba43 SN |
7 | #include <linux/netdevice.h> |
8 | #include <linux/utsname.h> | |
1c79031f | 9 | #include <generated/utsrelease.h> |
36b20b7f | 10 | #include <linux/ctype.h> |
df69ba43 SN |
11 | |
12 | #include "ionic.h" | |
13 | #include "ionic_bus.h" | |
1a58e196 | 14 | #include "ionic_lif.h" |
fbfb8031 | 15 | #include "ionic_debugfs.h" |
df69ba43 SN |
16 | |
17 | MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION); | |
18 | MODULE_AUTHOR("Pensando Systems, Inc"); | |
19 | MODULE_LICENSE("GPL"); | |
df69ba43 | 20 | |
fbfb8031 SN |
21 | static const char *ionic_error_to_str(enum ionic_status_code code) |
22 | { | |
23 | switch (code) { | |
24 | case IONIC_RC_SUCCESS: | |
25 | return "IONIC_RC_SUCCESS"; | |
26 | case IONIC_RC_EVERSION: | |
27 | return "IONIC_RC_EVERSION"; | |
28 | case IONIC_RC_EOPCODE: | |
29 | return "IONIC_RC_EOPCODE"; | |
30 | case IONIC_RC_EIO: | |
31 | return "IONIC_RC_EIO"; | |
32 | case IONIC_RC_EPERM: | |
33 | return "IONIC_RC_EPERM"; | |
34 | case IONIC_RC_EQID: | |
35 | return "IONIC_RC_EQID"; | |
36 | case IONIC_RC_EQTYPE: | |
37 | return "IONIC_RC_EQTYPE"; | |
38 | case IONIC_RC_ENOENT: | |
39 | return "IONIC_RC_ENOENT"; | |
40 | case IONIC_RC_EINTR: | |
41 | return "IONIC_RC_EINTR"; | |
42 | case IONIC_RC_EAGAIN: | |
43 | return "IONIC_RC_EAGAIN"; | |
44 | case IONIC_RC_ENOMEM: | |
45 | return "IONIC_RC_ENOMEM"; | |
46 | case IONIC_RC_EFAULT: | |
47 | return "IONIC_RC_EFAULT"; | |
48 | case IONIC_RC_EBUSY: | |
49 | return "IONIC_RC_EBUSY"; | |
50 | case IONIC_RC_EEXIST: | |
51 | return "IONIC_RC_EEXIST"; | |
52 | case IONIC_RC_EINVAL: | |
53 | return "IONIC_RC_EINVAL"; | |
54 | case IONIC_RC_ENOSPC: | |
55 | return "IONIC_RC_ENOSPC"; | |
56 | case IONIC_RC_ERANGE: | |
57 | return "IONIC_RC_ERANGE"; | |
58 | case IONIC_RC_BAD_ADDR: | |
59 | return "IONIC_RC_BAD_ADDR"; | |
60 | case IONIC_RC_DEV_CMD: | |
61 | return "IONIC_RC_DEV_CMD"; | |
b2133d8d SN |
62 | case IONIC_RC_ENOSUPP: |
63 | return "IONIC_RC_ENOSUPP"; | |
fbfb8031 SN |
64 | case IONIC_RC_ERROR: |
65 | return "IONIC_RC_ERROR"; | |
66 | case IONIC_RC_ERDMA: | |
67 | return "IONIC_RC_ERDMA"; | |
9e15410d SN |
68 | case IONIC_RC_EBAD_FW: |
69 | return "IONIC_RC_EBAD_FW"; | |
fbfb8031 SN |
70 | default: |
71 | return "IONIC_RC_UNKNOWN"; | |
72 | } | |
73 | } | |
74 | ||
75 | static int ionic_error_to_errno(enum ionic_status_code code) | |
76 | { | |
77 | switch (code) { | |
78 | case IONIC_RC_SUCCESS: | |
79 | return 0; | |
80 | case IONIC_RC_EVERSION: | |
81 | case IONIC_RC_EQTYPE: | |
82 | case IONIC_RC_EQID: | |
83 | case IONIC_RC_EINVAL: | |
b2133d8d | 84 | case IONIC_RC_ENOSUPP: |
fbfb8031 SN |
85 | return -EINVAL; |
86 | case IONIC_RC_EPERM: | |
87 | return -EPERM; | |
88 | case IONIC_RC_ENOENT: | |
89 | return -ENOENT; | |
90 | case IONIC_RC_EAGAIN: | |
91 | return -EAGAIN; | |
92 | case IONIC_RC_ENOMEM: | |
93 | return -ENOMEM; | |
94 | case IONIC_RC_EFAULT: | |
95 | return -EFAULT; | |
96 | case IONIC_RC_EBUSY: | |
97 | return -EBUSY; | |
98 | case IONIC_RC_EEXIST: | |
99 | return -EEXIST; | |
100 | case IONIC_RC_ENOSPC: | |
101 | return -ENOSPC; | |
102 | case IONIC_RC_ERANGE: | |
103 | return -ERANGE; | |
104 | case IONIC_RC_BAD_ADDR: | |
105 | return -EFAULT; | |
106 | case IONIC_RC_EOPCODE: | |
107 | case IONIC_RC_EINTR: | |
108 | case IONIC_RC_DEV_CMD: | |
109 | case IONIC_RC_ERROR: | |
110 | case IONIC_RC_ERDMA: | |
111 | case IONIC_RC_EIO: | |
112 | default: | |
113 | return -EIO; | |
114 | } | |
115 | } | |
116 | ||
117 | static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode) | |
118 | { | |
119 | switch (opcode) { | |
120 | case IONIC_CMD_NOP: | |
121 | return "IONIC_CMD_NOP"; | |
122 | case IONIC_CMD_INIT: | |
123 | return "IONIC_CMD_INIT"; | |
124 | case IONIC_CMD_RESET: | |
125 | return "IONIC_CMD_RESET"; | |
126 | case IONIC_CMD_IDENTIFY: | |
127 | return "IONIC_CMD_IDENTIFY"; | |
128 | case IONIC_CMD_GETATTR: | |
129 | return "IONIC_CMD_GETATTR"; | |
130 | case IONIC_CMD_SETATTR: | |
131 | return "IONIC_CMD_SETATTR"; | |
132 | case IONIC_CMD_PORT_IDENTIFY: | |
133 | return "IONIC_CMD_PORT_IDENTIFY"; | |
134 | case IONIC_CMD_PORT_INIT: | |
135 | return "IONIC_CMD_PORT_INIT"; | |
136 | case IONIC_CMD_PORT_RESET: | |
137 | return "IONIC_CMD_PORT_RESET"; | |
138 | case IONIC_CMD_PORT_GETATTR: | |
139 | return "IONIC_CMD_PORT_GETATTR"; | |
140 | case IONIC_CMD_PORT_SETATTR: | |
141 | return "IONIC_CMD_PORT_SETATTR"; | |
142 | case IONIC_CMD_LIF_INIT: | |
143 | return "IONIC_CMD_LIF_INIT"; | |
144 | case IONIC_CMD_LIF_RESET: | |
145 | return "IONIC_CMD_LIF_RESET"; | |
146 | case IONIC_CMD_LIF_IDENTIFY: | |
147 | return "IONIC_CMD_LIF_IDENTIFY"; | |
148 | case IONIC_CMD_LIF_SETATTR: | |
149 | return "IONIC_CMD_LIF_SETATTR"; | |
150 | case IONIC_CMD_LIF_GETATTR: | |
151 | return "IONIC_CMD_LIF_GETATTR"; | |
61db421d SN |
152 | case IONIC_CMD_LIF_SETPHC: |
153 | return "IONIC_CMD_LIF_SETPHC"; | |
fbfb8031 SN |
154 | case IONIC_CMD_RX_MODE_SET: |
155 | return "IONIC_CMD_RX_MODE_SET"; | |
156 | case IONIC_CMD_RX_FILTER_ADD: | |
157 | return "IONIC_CMD_RX_FILTER_ADD"; | |
158 | case IONIC_CMD_RX_FILTER_DEL: | |
159 | return "IONIC_CMD_RX_FILTER_DEL"; | |
5b3f3f2a SN |
160 | case IONIC_CMD_Q_IDENTIFY: |
161 | return "IONIC_CMD_Q_IDENTIFY"; | |
fbfb8031 SN |
162 | case IONIC_CMD_Q_INIT: |
163 | return "IONIC_CMD_Q_INIT"; | |
164 | case IONIC_CMD_Q_CONTROL: | |
165 | return "IONIC_CMD_Q_CONTROL"; | |
166 | case IONIC_CMD_RDMA_RESET_LIF: | |
167 | return "IONIC_CMD_RDMA_RESET_LIF"; | |
168 | case IONIC_CMD_RDMA_CREATE_EQ: | |
169 | return "IONIC_CMD_RDMA_CREATE_EQ"; | |
170 | case IONIC_CMD_RDMA_CREATE_CQ: | |
171 | return "IONIC_CMD_RDMA_CREATE_CQ"; | |
172 | case IONIC_CMD_RDMA_CREATE_ADMINQ: | |
173 | return "IONIC_CMD_RDMA_CREATE_ADMINQ"; | |
174 | case IONIC_CMD_FW_DOWNLOAD: | |
175 | return "IONIC_CMD_FW_DOWNLOAD"; | |
176 | case IONIC_CMD_FW_CONTROL: | |
177 | return "IONIC_CMD_FW_CONTROL"; | |
87c905d8 SN |
178 | case IONIC_CMD_FW_DOWNLOAD_V1: |
179 | return "IONIC_CMD_FW_DOWNLOAD_V1"; | |
180 | case IONIC_CMD_FW_CONTROL_V1: | |
181 | return "IONIC_CMD_FW_CONTROL_V1"; | |
fbb39807 SN |
182 | case IONIC_CMD_VF_GETATTR: |
183 | return "IONIC_CMD_VF_GETATTR"; | |
184 | case IONIC_CMD_VF_SETATTR: | |
185 | return "IONIC_CMD_VF_SETATTR"; | |
fbfb8031 SN |
186 | default: |
187 | return "DEVCMD_UNKNOWN"; | |
188 | } | |
189 | } | |
190 | ||
938962d5 SN |
191 | static void ionic_adminq_flush(struct ionic_lif *lif) |
192 | { | |
f1d2e894 | 193 | struct ionic_desc_info *desc_info; |
e768929d SN |
194 | unsigned long irqflags; |
195 | struct ionic_queue *q; | |
196 | ||
197 | spin_lock_irqsave(&lif->adminq_lock, irqflags); | |
198 | if (!lif->adminqcq) { | |
199 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); | |
200 | return; | |
201 | } | |
938962d5 | 202 | |
e768929d | 203 | q = &lif->adminqcq->q; |
938962d5 | 204 | |
f1d2e894 SN |
205 | while (q->tail_idx != q->head_idx) { |
206 | desc_info = &q->info[q->tail_idx]; | |
207 | memset(desc_info->desc, 0, sizeof(union ionic_adminq_cmd)); | |
208 | desc_info->cb = NULL; | |
209 | desc_info->cb_arg = NULL; | |
210 | q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); | |
938962d5 | 211 | } |
e768929d | 212 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); |
938962d5 SN |
213 | } |
214 | ||
8c9d956a SN |
215 | void ionic_adminq_netdev_err_print(struct ionic_lif *lif, u8 opcode, |
216 | u8 status, int err) | |
217 | { | |
4cc787bd SN |
218 | const char *stat_str; |
219 | ||
220 | stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" : | |
221 | ionic_error_to_str(status); | |
222 | ||
8c9d956a | 223 | netdev_err(lif->netdev, "%s (%d) failed: %s (%d)\n", |
4cc787bd | 224 | ionic_opcode_to_str(opcode), opcode, stat_str, err); |
8c9d956a SN |
225 | } |
226 | ||
938962d5 SN |
227 | static int ionic_adminq_check_err(struct ionic_lif *lif, |
228 | struct ionic_admin_ctx *ctx, | |
8c9d956a SN |
229 | const bool timeout, |
230 | const bool do_msg) | |
938962d5 | 231 | { |
938962d5 SN |
232 | int err = 0; |
233 | ||
234 | if (ctx->comp.comp.status || timeout) { | |
938962d5 SN |
235 | err = timeout ? -ETIMEDOUT : |
236 | ionic_error_to_errno(ctx->comp.comp.status); | |
237 | ||
8c9d956a SN |
238 | if (do_msg) |
239 | ionic_adminq_netdev_err_print(lif, ctx->cmd.cmd.opcode, | |
240 | ctx->comp.comp.status, err); | |
938962d5 SN |
241 | |
242 | if (timeout) | |
243 | ionic_adminq_flush(lif); | |
244 | } | |
245 | ||
246 | return err; | |
247 | } | |
248 | ||
249 | static void ionic_adminq_cb(struct ionic_queue *q, | |
250 | struct ionic_desc_info *desc_info, | |
251 | struct ionic_cq_info *cq_info, void *cb_arg) | |
252 | { | |
253 | struct ionic_admin_ctx *ctx = cb_arg; | |
254 | struct ionic_admin_comp *comp; | |
938962d5 SN |
255 | |
256 | if (!ctx) | |
257 | return; | |
258 | ||
259 | comp = cq_info->cq_desc; | |
938962d5 SN |
260 | |
261 | memcpy(&ctx->comp, comp, sizeof(*comp)); | |
262 | ||
f37bc346 | 263 | dev_dbg(q->dev, "comp admin queue command:\n"); |
938962d5 SN |
264 | dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1, |
265 | &ctx->comp, sizeof(ctx->comp), true); | |
266 | ||
267 | complete_all(&ctx->work); | |
268 | } | |
269 | ||
b69585bf AH |
270 | bool ionic_adminq_poke_doorbell(struct ionic_queue *q) |
271 | { | |
272 | struct ionic_lif *lif = q->lif; | |
273 | unsigned long now, then, dif; | |
274 | unsigned long irqflags; | |
275 | ||
276 | spin_lock_irqsave(&lif->adminq_lock, irqflags); | |
277 | ||
278 | if (q->tail_idx == q->head_idx) { | |
279 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); | |
280 | return false; | |
281 | } | |
282 | ||
283 | now = READ_ONCE(jiffies); | |
284 | then = q->dbell_jiffies; | |
285 | dif = now - then; | |
286 | ||
287 | if (dif > q->dbell_deadline) { | |
288 | ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, | |
289 | q->dbval | q->head_idx); | |
290 | ||
291 | q->dbell_jiffies = now; | |
292 | } | |
293 | ||
294 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); | |
295 | ||
296 | return true; | |
297 | } | |
298 | ||
4f1704fa | 299 | int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) |
938962d5 | 300 | { |
f1d2e894 | 301 | struct ionic_desc_info *desc_info; |
e768929d | 302 | unsigned long irqflags; |
f1d2e894 | 303 | struct ionic_queue *q; |
938962d5 SN |
304 | int err = 0; |
305 | ||
e768929d SN |
306 | spin_lock_irqsave(&lif->adminq_lock, irqflags); |
307 | if (!lif->adminqcq) { | |
308 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); | |
a4674f34 | 309 | return -EIO; |
e768929d | 310 | } |
a4674f34 | 311 | |
f1d2e894 | 312 | q = &lif->adminqcq->q; |
a4674f34 | 313 | |
f1d2e894 | 314 | if (!ionic_q_has_space(q, 1)) { |
938962d5 SN |
315 | err = -ENOSPC; |
316 | goto err_out; | |
317 | } | |
318 | ||
97ca4865 SN |
319 | err = ionic_heartbeat_check(lif->ionic); |
320 | if (err) | |
321 | goto err_out; | |
322 | ||
f1d2e894 SN |
323 | desc_info = &q->info[q->head_idx]; |
324 | memcpy(desc_info->desc, &ctx->cmd, sizeof(ctx->cmd)); | |
938962d5 SN |
325 | |
326 | dev_dbg(&lif->netdev->dev, "post admin queue command:\n"); | |
327 | dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, | |
328 | &ctx->cmd, sizeof(ctx->cmd), true); | |
329 | ||
f1d2e894 | 330 | ionic_q_post(q, true, ionic_adminq_cb, ctx); |
938962d5 SN |
331 | |
332 | err_out: | |
e768929d | 333 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags); |
938962d5 SN |
334 | |
335 | return err; | |
336 | } | |
337 | ||
8c9d956a SN |
338 | int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx, |
339 | const int err, const bool do_msg) | |
938962d5 SN |
340 | { |
341 | struct net_device *netdev = lif->netdev; | |
a095e477 SN |
342 | unsigned long time_limit; |
343 | unsigned long time_start; | |
344 | unsigned long time_done; | |
938962d5 SN |
345 | unsigned long remaining; |
346 | const char *name; | |
938962d5 | 347 | |
a095e477 SN |
348 | name = ionic_opcode_to_str(ctx->cmd.cmd.opcode); |
349 | ||
938962d5 | 350 | if (err) { |
8c9d956a | 351 | if (do_msg && !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) |
c672412f SN |
352 | netdev_err(netdev, "Posting of %s (%d) failed: %d\n", |
353 | name, ctx->cmd.cmd.opcode, err); | |
bc43ed4f | 354 | ctx->comp.comp.status = IONIC_RC_ERROR; |
938962d5 SN |
355 | return err; |
356 | } | |
357 | ||
a095e477 SN |
358 | time_start = jiffies; |
359 | time_limit = time_start + HZ * (ulong)DEVCMD_TIMEOUT; | |
360 | do { | |
361 | remaining = wait_for_completion_timeout(&ctx->work, | |
362 | IONIC_ADMINQ_TIME_SLICE); | |
363 | ||
364 | /* check for done */ | |
365 | if (remaining) | |
366 | break; | |
367 | ||
ec8ee714 | 368 | /* force a check of FW status and break out if FW reset */ |
896de449 | 369 | ionic_heartbeat_check(lif->ionic); |
398d1e37 SN |
370 | if ((test_bit(IONIC_LIF_F_FW_RESET, lif->state) && |
371 | !lif->ionic->idev.fw_status_ready) || | |
372 | test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) { | |
8c9d956a | 373 | if (do_msg) |
ec8ee714 SN |
374 | netdev_warn(netdev, "%s (%d) interrupted, FW in reset\n", |
375 | name, ctx->cmd.cmd.opcode); | |
bc43ed4f | 376 | ctx->comp.comp.status = IONIC_RC_ERROR; |
a095e477 SN |
377 | return -ENXIO; |
378 | } | |
379 | ||
380 | } while (time_before(jiffies, time_limit)); | |
381 | time_done = jiffies; | |
382 | ||
383 | dev_dbg(lif->ionic->dev, "%s: elapsed %d msecs\n", | |
384 | __func__, jiffies_to_msecs(time_done - time_start)); | |
385 | ||
8c9d956a SN |
386 | return ionic_adminq_check_err(lif, ctx, |
387 | time_after_eq(time_done, time_limit), | |
388 | do_msg); | |
938962d5 SN |
389 | } |
390 | ||
ca5fdf9a SN |
391 | static int __ionic_adminq_post_wait(struct ionic_lif *lif, |
392 | struct ionic_admin_ctx *ctx, | |
393 | const bool do_msg) | |
4f1704fa SN |
394 | { |
395 | int err; | |
396 | ||
ca5fdf9a SN |
397 | if (!ionic_is_fw_running(&lif->ionic->idev)) |
398 | return 0; | |
399 | ||
4f1704fa SN |
400 | err = ionic_adminq_post(lif, ctx); |
401 | ||
ca5fdf9a | 402 | return ionic_adminq_wait(lif, ctx, err, do_msg); |
8c9d956a SN |
403 | } |
404 | ||
ca5fdf9a | 405 | int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) |
8c9d956a | 406 | { |
ca5fdf9a SN |
407 | return __ionic_adminq_post_wait(lif, ctx, true); |
408 | } | |
8c9d956a | 409 | |
ca5fdf9a SN |
410 | int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) |
411 | { | |
412 | return __ionic_adminq_post_wait(lif, ctx, false); | |
4f1704fa SN |
413 | } |
414 | ||
97ca4865 SN |
415 | static void ionic_dev_cmd_clean(struct ionic *ionic) |
416 | { | |
bc0bf9de | 417 | struct ionic_dev *idev = &ionic->idev; |
97ca4865 | 418 | |
7662fad3 SN |
419 | if (!idev->dev_cmd_regs) |
420 | return; | |
421 | ||
bc0bf9de SN |
422 | iowrite32(0, &idev->dev_cmd_regs->doorbell); |
423 | memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd)); | |
97ca4865 SN |
424 | } |
425 | ||
b640b552 BC |
426 | void ionic_dev_cmd_dev_err_print(struct ionic *ionic, u8 opcode, u8 status, |
427 | int err) | |
428 | { | |
429 | const char *stat_str; | |
430 | ||
431 | stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" : | |
432 | ionic_error_to_str(status); | |
433 | ||
434 | dev_err(ionic->dev, "DEV_CMD %s (%d) error, %s (%d) failed\n", | |
435 | ionic_opcode_to_str(opcode), opcode, stat_str, err); | |
436 | } | |
437 | ||
438 | static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds, | |
439 | const bool do_msg) | |
fbfb8031 SN |
440 | { |
441 | struct ionic_dev *idev = &ionic->idev; | |
442 | unsigned long start_time; | |
443 | unsigned long max_wait; | |
444 | unsigned long duration; | |
ec8ee714 SN |
445 | int done = 0; |
446 | bool fw_up; | |
fbfb8031 | 447 | int opcode; |
fbfb8031 SN |
448 | int err; |
449 | ||
fbfb8031 SN |
450 | /* Wait for dev cmd to complete, retrying if we get EAGAIN, |
451 | * but don't wait any longer than max_seconds. | |
452 | */ | |
453 | max_wait = jiffies + (max_seconds * HZ); | |
454 | try_again: | |
24f11024 | 455 | opcode = idev->opcode; |
fbfb8031 | 456 | start_time = jiffies; |
ec8ee714 SN |
457 | for (fw_up = ionic_is_fw_running(idev); |
458 | !done && fw_up && time_before(jiffies, max_wait); | |
459 | fw_up = ionic_is_fw_running(idev)) { | |
fbfb8031 SN |
460 | done = ionic_dev_cmd_done(idev); |
461 | if (done) | |
462 | break; | |
30b5191a | 463 | usleep_range(100, 200); |
ec8ee714 | 464 | } |
fbfb8031 SN |
465 | duration = jiffies - start_time; |
466 | ||
fbfb8031 SN |
467 | dev_dbg(ionic->dev, "DEVCMD %s (%d) done=%d took %ld secs (%ld jiffies)\n", |
468 | ionic_opcode_to_str(opcode), opcode, | |
469 | done, duration / HZ, duration); | |
470 | ||
ec8ee714 SN |
471 | if (!done && !fw_up) { |
472 | ionic_dev_cmd_clean(ionic); | |
473 | dev_warn(ionic->dev, "DEVCMD %s (%d) interrupted - FW is down\n", | |
474 | ionic_opcode_to_str(opcode), opcode); | |
97ca4865 SN |
475 | return -ENXIO; |
476 | } | |
477 | ||
fbfb8031 | 478 | if (!done && !time_before(jiffies, max_wait)) { |
97ca4865 | 479 | ionic_dev_cmd_clean(ionic); |
fbfb8031 SN |
480 | dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n", |
481 | ionic_opcode_to_str(opcode), opcode, max_seconds); | |
482 | return -ETIMEDOUT; | |
483 | } | |
484 | ||
485 | err = ionic_dev_cmd_status(&ionic->idev); | |
486 | if (err) { | |
30b5191a SN |
487 | if (err == IONIC_RC_EAGAIN && |
488 | time_before(jiffies, (max_wait - HZ))) { | |
489 | dev_dbg(ionic->dev, "DEV_CMD %s (%d), %s (%d) retrying...\n", | |
fbfb8031 SN |
490 | ionic_opcode_to_str(opcode), opcode, |
491 | ionic_error_to_str(err), err); | |
492 | ||
fbfb8031 | 493 | iowrite32(0, &idev->dev_cmd_regs->done); |
0fc4dd45 | 494 | msleep(1000); |
fbfb8031 SN |
495 | iowrite32(1, &idev->dev_cmd_regs->doorbell); |
496 | goto try_again; | |
497 | } | |
498 | ||
30b5191a | 499 | if (!(opcode == IONIC_CMD_FW_CONTROL && err == IONIC_RC_EAGAIN)) |
b640b552 BC |
500 | if (do_msg) |
501 | ionic_dev_cmd_dev_err_print(ionic, opcode, err, | |
502 | ionic_error_to_errno(err)); | |
fbfb8031 SN |
503 | |
504 | return ionic_error_to_errno(err); | |
505 | } | |
506 | ||
0fc4dd45 SN |
507 | ionic_dev_cmd_clean(ionic); |
508 | ||
fbfb8031 SN |
509 | return 0; |
510 | } | |
511 | ||
b640b552 BC |
512 | int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) |
513 | { | |
514 | return __ionic_dev_cmd_wait(ionic, max_seconds, true); | |
515 | } | |
516 | ||
517 | int ionic_dev_cmd_wait_nomsg(struct ionic *ionic, unsigned long max_seconds) | |
518 | { | |
519 | return __ionic_dev_cmd_wait(ionic, max_seconds, false); | |
520 | } | |
521 | ||
fbfb8031 SN |
522 | int ionic_setup(struct ionic *ionic) |
523 | { | |
524 | int err; | |
525 | ||
526 | err = ionic_dev_setup(ionic); | |
527 | if (err) | |
528 | return err; | |
5c784311 | 529 | ionic_reset(ionic); |
fbfb8031 SN |
530 | |
531 | return 0; | |
532 | } | |
533 | ||
534 | int ionic_identify(struct ionic *ionic) | |
535 | { | |
536 | struct ionic_identity *ident = &ionic->ident; | |
537 | struct ionic_dev *idev = &ionic->idev; | |
538 | size_t sz; | |
539 | int err; | |
540 | ||
541 | memset(ident, 0, sizeof(*ident)); | |
542 | ||
543 | ident->drv.os_type = cpu_to_le32(IONIC_OS_TYPE_LINUX); | |
ad0ebd8b JS |
544 | strscpy(ident->drv.driver_ver_str, UTS_RELEASE, |
545 | sizeof(ident->drv.driver_ver_str)); | |
fbfb8031 SN |
546 | |
547 | mutex_lock(&ionic->dev_cmd_lock); | |
548 | ||
549 | sz = min(sizeof(ident->drv), sizeof(idev->dev_cmd_regs->data)); | |
550 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->drv, sz); | |
551 | ||
f43a96d9 | 552 | ionic_dev_cmd_identify(idev, IONIC_DEV_IDENTITY_VERSION_2); |
fbfb8031 SN |
553 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); |
554 | if (!err) { | |
555 | sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data)); | |
556 | memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz); | |
557 | } | |
fbfb8031 SN |
558 | mutex_unlock(&ionic->dev_cmd_lock); |
559 | ||
a21b5d49 | 560 | if (err) { |
36b20b7f | 561 | dev_err(ionic->dev, "Cannot identify ionic: %d\n", err); |
a21b5d49 SN |
562 | goto err_out; |
563 | } | |
fbfb8031 | 564 | |
36b20b7f SN |
565 | if (isprint(idev->dev_info.fw_version[0]) && |
566 | isascii(idev->dev_info.fw_version[0])) | |
567 | dev_info(ionic->dev, "FW: %.*s\n", | |
568 | (int)(sizeof(idev->dev_info.fw_version) - 1), | |
569 | idev->dev_info.fw_version); | |
570 | else | |
571 | dev_info(ionic->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n", | |
572 | (u8)idev->dev_info.fw_version[0], | |
573 | (u8)idev->dev_info.fw_version[1], | |
574 | (u8)idev->dev_info.fw_version[2], | |
575 | (u8)idev->dev_info.fw_version[3]); | |
576 | ||
a21b5d49 SN |
577 | err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC, |
578 | &ionic->ident.lif); | |
579 | if (err) { | |
580 | dev_err(ionic->dev, "Cannot identify LIFs: %d\n", err); | |
581 | goto err_out; | |
582 | } | |
fbfb8031 SN |
583 | |
584 | return 0; | |
585 | ||
a21b5d49 | 586 | err_out: |
fbfb8031 SN |
587 | return err; |
588 | } | |
589 | ||
590 | int ionic_init(struct ionic *ionic) | |
591 | { | |
592 | struct ionic_dev *idev = &ionic->idev; | |
593 | int err; | |
594 | ||
595 | mutex_lock(&ionic->dev_cmd_lock); | |
596 | ionic_dev_cmd_init(idev); | |
597 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
598 | mutex_unlock(&ionic->dev_cmd_lock); | |
599 | ||
600 | return err; | |
601 | } | |
602 | ||
603 | int ionic_reset(struct ionic *ionic) | |
604 | { | |
605 | struct ionic_dev *idev = &ionic->idev; | |
606 | int err; | |
607 | ||
b8fd0271 BC |
608 | if (!ionic_is_fw_running(idev)) |
609 | return 0; | |
610 | ||
fbfb8031 SN |
611 | mutex_lock(&ionic->dev_cmd_lock); |
612 | ionic_dev_cmd_reset(idev); | |
613 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
614 | mutex_unlock(&ionic->dev_cmd_lock); | |
615 | ||
616 | return err; | |
617 | } | |
618 | ||
04436595 SN |
619 | int ionic_port_identify(struct ionic *ionic) |
620 | { | |
621 | struct ionic_identity *ident = &ionic->ident; | |
622 | struct ionic_dev *idev = &ionic->idev; | |
623 | size_t sz; | |
624 | int err; | |
625 | ||
626 | mutex_lock(&ionic->dev_cmd_lock); | |
627 | ||
628 | ionic_dev_cmd_port_identify(idev); | |
629 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
630 | if (!err) { | |
631 | sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data)); | |
632 | memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz); | |
633 | } | |
634 | ||
635 | mutex_unlock(&ionic->dev_cmd_lock); | |
636 | ||
637 | return err; | |
638 | } | |
639 | ||
640 | int ionic_port_init(struct ionic *ionic) | |
641 | { | |
642 | struct ionic_identity *ident = &ionic->ident; | |
643 | struct ionic_dev *idev = &ionic->idev; | |
644 | size_t sz; | |
645 | int err; | |
646 | ||
04436595 | 647 | if (!idev->port_info) { |
ddc5911b SN |
648 | idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE); |
649 | idev->port_info = dma_alloc_coherent(ionic->dev, | |
650 | idev->port_info_sz, | |
651 | &idev->port_info_pa, | |
652 | GFP_KERNEL); | |
c0c682ee | 653 | if (!idev->port_info) |
ddc5911b | 654 | return -ENOMEM; |
04436595 SN |
655 | } |
656 | ||
657 | sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data)); | |
658 | ||
659 | mutex_lock(&ionic->dev_cmd_lock); | |
660 | ||
661 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz); | |
662 | ionic_dev_cmd_port_init(idev); | |
663 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
664 | ||
665 | ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP); | |
896de449 | 666 | ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); |
04436595 SN |
667 | |
668 | mutex_unlock(&ionic->dev_cmd_lock); | |
669 | if (err) { | |
670 | dev_err(ionic->dev, "Failed to init port\n"); | |
671 | dma_free_coherent(ionic->dev, idev->port_info_sz, | |
672 | idev->port_info, idev->port_info_pa); | |
673 | idev->port_info = NULL; | |
674 | idev->port_info_pa = 0; | |
675 | } | |
676 | ||
677 | return err; | |
678 | } | |
679 | ||
680 | int ionic_port_reset(struct ionic *ionic) | |
681 | { | |
682 | struct ionic_dev *idev = &ionic->idev; | |
b8fd0271 | 683 | int err = 0; |
04436595 SN |
684 | |
685 | if (!idev->port_info) | |
686 | return 0; | |
687 | ||
b8fd0271 BC |
688 | if (ionic_is_fw_running(idev)) { |
689 | mutex_lock(&ionic->dev_cmd_lock); | |
690 | ionic_dev_cmd_port_reset(idev); | |
691 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
692 | mutex_unlock(&ionic->dev_cmd_lock); | |
693 | } | |
04436595 SN |
694 | |
695 | dma_free_coherent(ionic->dev, idev->port_info_sz, | |
696 | idev->port_info, idev->port_info_pa); | |
697 | ||
698 | idev->port_info = NULL; | |
699 | idev->port_info_pa = 0; | |
700 | ||
04436595 SN |
701 | return err; |
702 | } | |
703 | ||
df69ba43 SN |
704 | static int __init ionic_init_module(void) |
705 | { | |
280c0f7c YC |
706 | int ret; |
707 | ||
fbfb8031 | 708 | ionic_debugfs_create(); |
280c0f7c YC |
709 | ret = ionic_bus_register_driver(); |
710 | if (ret) | |
711 | ionic_debugfs_destroy(); | |
712 | ||
713 | return ret; | |
df69ba43 SN |
714 | } |
715 | ||
716 | static void __exit ionic_cleanup_module(void) | |
717 | { | |
718 | ionic_bus_unregister_driver(); | |
fbfb8031 | 719 | ionic_debugfs_destroy(); |
df69ba43 SN |
720 | |
721 | pr_info("%s removed\n", IONIC_DRV_NAME); | |
722 | } | |
723 | ||
724 | module_init(ionic_init_module); | |
725 | module_exit(ionic_cleanup_module); |