]>
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> | |
1fcbebf1 | 9 | #include <linux/vermagic.h> |
df69ba43 SN |
10 | |
11 | #include "ionic.h" | |
12 | #include "ionic_bus.h" | |
1a58e196 | 13 | #include "ionic_lif.h" |
fbfb8031 | 14 | #include "ionic_debugfs.h" |
df69ba43 SN |
15 | |
16 | MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION); | |
17 | MODULE_AUTHOR("Pensando Systems, Inc"); | |
18 | MODULE_LICENSE("GPL"); | |
df69ba43 | 19 | |
fbfb8031 SN |
20 | static const char *ionic_error_to_str(enum ionic_status_code code) |
21 | { | |
22 | switch (code) { | |
23 | case IONIC_RC_SUCCESS: | |
24 | return "IONIC_RC_SUCCESS"; | |
25 | case IONIC_RC_EVERSION: | |
26 | return "IONIC_RC_EVERSION"; | |
27 | case IONIC_RC_EOPCODE: | |
28 | return "IONIC_RC_EOPCODE"; | |
29 | case IONIC_RC_EIO: | |
30 | return "IONIC_RC_EIO"; | |
31 | case IONIC_RC_EPERM: | |
32 | return "IONIC_RC_EPERM"; | |
33 | case IONIC_RC_EQID: | |
34 | return "IONIC_RC_EQID"; | |
35 | case IONIC_RC_EQTYPE: | |
36 | return "IONIC_RC_EQTYPE"; | |
37 | case IONIC_RC_ENOENT: | |
38 | return "IONIC_RC_ENOENT"; | |
39 | case IONIC_RC_EINTR: | |
40 | return "IONIC_RC_EINTR"; | |
41 | case IONIC_RC_EAGAIN: | |
42 | return "IONIC_RC_EAGAIN"; | |
43 | case IONIC_RC_ENOMEM: | |
44 | return "IONIC_RC_ENOMEM"; | |
45 | case IONIC_RC_EFAULT: | |
46 | return "IONIC_RC_EFAULT"; | |
47 | case IONIC_RC_EBUSY: | |
48 | return "IONIC_RC_EBUSY"; | |
49 | case IONIC_RC_EEXIST: | |
50 | return "IONIC_RC_EEXIST"; | |
51 | case IONIC_RC_EINVAL: | |
52 | return "IONIC_RC_EINVAL"; | |
53 | case IONIC_RC_ENOSPC: | |
54 | return "IONIC_RC_ENOSPC"; | |
55 | case IONIC_RC_ERANGE: | |
56 | return "IONIC_RC_ERANGE"; | |
57 | case IONIC_RC_BAD_ADDR: | |
58 | return "IONIC_RC_BAD_ADDR"; | |
59 | case IONIC_RC_DEV_CMD: | |
60 | return "IONIC_RC_DEV_CMD"; | |
b2133d8d SN |
61 | case IONIC_RC_ENOSUPP: |
62 | return "IONIC_RC_ENOSUPP"; | |
fbfb8031 SN |
63 | case IONIC_RC_ERROR: |
64 | return "IONIC_RC_ERROR"; | |
65 | case IONIC_RC_ERDMA: | |
66 | return "IONIC_RC_ERDMA"; | |
67 | default: | |
68 | return "IONIC_RC_UNKNOWN"; | |
69 | } | |
70 | } | |
71 | ||
72 | static int ionic_error_to_errno(enum ionic_status_code code) | |
73 | { | |
74 | switch (code) { | |
75 | case IONIC_RC_SUCCESS: | |
76 | return 0; | |
77 | case IONIC_RC_EVERSION: | |
78 | case IONIC_RC_EQTYPE: | |
79 | case IONIC_RC_EQID: | |
80 | case IONIC_RC_EINVAL: | |
b2133d8d | 81 | case IONIC_RC_ENOSUPP: |
fbfb8031 SN |
82 | return -EINVAL; |
83 | case IONIC_RC_EPERM: | |
84 | return -EPERM; | |
85 | case IONIC_RC_ENOENT: | |
86 | return -ENOENT; | |
87 | case IONIC_RC_EAGAIN: | |
88 | return -EAGAIN; | |
89 | case IONIC_RC_ENOMEM: | |
90 | return -ENOMEM; | |
91 | case IONIC_RC_EFAULT: | |
92 | return -EFAULT; | |
93 | case IONIC_RC_EBUSY: | |
94 | return -EBUSY; | |
95 | case IONIC_RC_EEXIST: | |
96 | return -EEXIST; | |
97 | case IONIC_RC_ENOSPC: | |
98 | return -ENOSPC; | |
99 | case IONIC_RC_ERANGE: | |
100 | return -ERANGE; | |
101 | case IONIC_RC_BAD_ADDR: | |
102 | return -EFAULT; | |
103 | case IONIC_RC_EOPCODE: | |
104 | case IONIC_RC_EINTR: | |
105 | case IONIC_RC_DEV_CMD: | |
106 | case IONIC_RC_ERROR: | |
107 | case IONIC_RC_ERDMA: | |
108 | case IONIC_RC_EIO: | |
109 | default: | |
110 | return -EIO; | |
111 | } | |
112 | } | |
113 | ||
114 | static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode) | |
115 | { | |
116 | switch (opcode) { | |
117 | case IONIC_CMD_NOP: | |
118 | return "IONIC_CMD_NOP"; | |
119 | case IONIC_CMD_INIT: | |
120 | return "IONIC_CMD_INIT"; | |
121 | case IONIC_CMD_RESET: | |
122 | return "IONIC_CMD_RESET"; | |
123 | case IONIC_CMD_IDENTIFY: | |
124 | return "IONIC_CMD_IDENTIFY"; | |
125 | case IONIC_CMD_GETATTR: | |
126 | return "IONIC_CMD_GETATTR"; | |
127 | case IONIC_CMD_SETATTR: | |
128 | return "IONIC_CMD_SETATTR"; | |
129 | case IONIC_CMD_PORT_IDENTIFY: | |
130 | return "IONIC_CMD_PORT_IDENTIFY"; | |
131 | case IONIC_CMD_PORT_INIT: | |
132 | return "IONIC_CMD_PORT_INIT"; | |
133 | case IONIC_CMD_PORT_RESET: | |
134 | return "IONIC_CMD_PORT_RESET"; | |
135 | case IONIC_CMD_PORT_GETATTR: | |
136 | return "IONIC_CMD_PORT_GETATTR"; | |
137 | case IONIC_CMD_PORT_SETATTR: | |
138 | return "IONIC_CMD_PORT_SETATTR"; | |
139 | case IONIC_CMD_LIF_INIT: | |
140 | return "IONIC_CMD_LIF_INIT"; | |
141 | case IONIC_CMD_LIF_RESET: | |
142 | return "IONIC_CMD_LIF_RESET"; | |
143 | case IONIC_CMD_LIF_IDENTIFY: | |
144 | return "IONIC_CMD_LIF_IDENTIFY"; | |
145 | case IONIC_CMD_LIF_SETATTR: | |
146 | return "IONIC_CMD_LIF_SETATTR"; | |
147 | case IONIC_CMD_LIF_GETATTR: | |
148 | return "IONIC_CMD_LIF_GETATTR"; | |
149 | case IONIC_CMD_RX_MODE_SET: | |
150 | return "IONIC_CMD_RX_MODE_SET"; | |
151 | case IONIC_CMD_RX_FILTER_ADD: | |
152 | return "IONIC_CMD_RX_FILTER_ADD"; | |
153 | case IONIC_CMD_RX_FILTER_DEL: | |
154 | return "IONIC_CMD_RX_FILTER_DEL"; | |
155 | case IONIC_CMD_Q_INIT: | |
156 | return "IONIC_CMD_Q_INIT"; | |
157 | case IONIC_CMD_Q_CONTROL: | |
158 | return "IONIC_CMD_Q_CONTROL"; | |
159 | case IONIC_CMD_RDMA_RESET_LIF: | |
160 | return "IONIC_CMD_RDMA_RESET_LIF"; | |
161 | case IONIC_CMD_RDMA_CREATE_EQ: | |
162 | return "IONIC_CMD_RDMA_CREATE_EQ"; | |
163 | case IONIC_CMD_RDMA_CREATE_CQ: | |
164 | return "IONIC_CMD_RDMA_CREATE_CQ"; | |
165 | case IONIC_CMD_RDMA_CREATE_ADMINQ: | |
166 | return "IONIC_CMD_RDMA_CREATE_ADMINQ"; | |
167 | case IONIC_CMD_FW_DOWNLOAD: | |
168 | return "IONIC_CMD_FW_DOWNLOAD"; | |
169 | case IONIC_CMD_FW_CONTROL: | |
170 | return "IONIC_CMD_FW_CONTROL"; | |
fbb39807 SN |
171 | case IONIC_CMD_VF_GETATTR: |
172 | return "IONIC_CMD_VF_GETATTR"; | |
173 | case IONIC_CMD_VF_SETATTR: | |
174 | return "IONIC_CMD_VF_SETATTR"; | |
fbfb8031 SN |
175 | default: |
176 | return "DEVCMD_UNKNOWN"; | |
177 | } | |
178 | } | |
179 | ||
938962d5 SN |
180 | static void ionic_adminq_flush(struct ionic_lif *lif) |
181 | { | |
182 | struct ionic_queue *adminq = &lif->adminqcq->q; | |
183 | ||
184 | spin_lock(&lif->adminq_lock); | |
185 | ||
186 | while (adminq->tail != adminq->head) { | |
187 | memset(adminq->tail->desc, 0, sizeof(union ionic_adminq_cmd)); | |
188 | adminq->tail->cb = NULL; | |
189 | adminq->tail->cb_arg = NULL; | |
190 | adminq->tail = adminq->tail->next; | |
191 | } | |
192 | spin_unlock(&lif->adminq_lock); | |
193 | } | |
194 | ||
195 | static int ionic_adminq_check_err(struct ionic_lif *lif, | |
196 | struct ionic_admin_ctx *ctx, | |
197 | bool timeout) | |
198 | { | |
199 | struct net_device *netdev = lif->netdev; | |
200 | const char *opcode_str; | |
201 | const char *status_str; | |
202 | int err = 0; | |
203 | ||
204 | if (ctx->comp.comp.status || timeout) { | |
205 | opcode_str = ionic_opcode_to_str(ctx->cmd.cmd.opcode); | |
206 | status_str = ionic_error_to_str(ctx->comp.comp.status); | |
207 | err = timeout ? -ETIMEDOUT : | |
208 | ionic_error_to_errno(ctx->comp.comp.status); | |
209 | ||
210 | netdev_err(netdev, "%s (%d) failed: %s (%d)\n", | |
211 | opcode_str, ctx->cmd.cmd.opcode, | |
212 | timeout ? "TIMEOUT" : status_str, err); | |
213 | ||
214 | if (timeout) | |
215 | ionic_adminq_flush(lif); | |
216 | } | |
217 | ||
218 | return err; | |
219 | } | |
220 | ||
221 | static void ionic_adminq_cb(struct ionic_queue *q, | |
222 | struct ionic_desc_info *desc_info, | |
223 | struct ionic_cq_info *cq_info, void *cb_arg) | |
224 | { | |
225 | struct ionic_admin_ctx *ctx = cb_arg; | |
226 | struct ionic_admin_comp *comp; | |
227 | struct device *dev; | |
228 | ||
229 | if (!ctx) | |
230 | return; | |
231 | ||
232 | comp = cq_info->cq_desc; | |
233 | dev = &q->lif->netdev->dev; | |
234 | ||
235 | memcpy(&ctx->comp, comp, sizeof(*comp)); | |
236 | ||
237 | dev_dbg(dev, "comp admin queue command:\n"); | |
238 | dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1, | |
239 | &ctx->comp, sizeof(ctx->comp), true); | |
240 | ||
241 | complete_all(&ctx->work); | |
242 | } | |
243 | ||
244 | static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) | |
245 | { | |
a4674f34 | 246 | struct ionic_queue *adminq; |
938962d5 SN |
247 | int err = 0; |
248 | ||
249 | WARN_ON(in_interrupt()); | |
250 | ||
a4674f34 SN |
251 | if (!lif->adminqcq) |
252 | return -EIO; | |
253 | ||
254 | adminq = &lif->adminqcq->q; | |
255 | ||
938962d5 SN |
256 | spin_lock(&lif->adminq_lock); |
257 | if (!ionic_q_has_space(adminq, 1)) { | |
258 | err = -ENOSPC; | |
259 | goto err_out; | |
260 | } | |
261 | ||
97ca4865 SN |
262 | err = ionic_heartbeat_check(lif->ionic); |
263 | if (err) | |
264 | goto err_out; | |
265 | ||
938962d5 SN |
266 | memcpy(adminq->head->desc, &ctx->cmd, sizeof(ctx->cmd)); |
267 | ||
268 | dev_dbg(&lif->netdev->dev, "post admin queue command:\n"); | |
269 | dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, | |
270 | &ctx->cmd, sizeof(ctx->cmd), true); | |
271 | ||
272 | ionic_q_post(adminq, true, ionic_adminq_cb, ctx); | |
273 | ||
274 | err_out: | |
275 | spin_unlock(&lif->adminq_lock); | |
276 | ||
277 | return err; | |
278 | } | |
279 | ||
280 | int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) | |
281 | { | |
282 | struct net_device *netdev = lif->netdev; | |
283 | unsigned long remaining; | |
284 | const char *name; | |
285 | int err; | |
286 | ||
287 | err = ionic_adminq_post(lif, ctx); | |
288 | if (err) { | |
c672412f SN |
289 | if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { |
290 | name = ionic_opcode_to_str(ctx->cmd.cmd.opcode); | |
291 | netdev_err(netdev, "Posting of %s (%d) failed: %d\n", | |
292 | name, ctx->cmd.cmd.opcode, err); | |
293 | } | |
938962d5 SN |
294 | return err; |
295 | } | |
296 | ||
297 | remaining = wait_for_completion_timeout(&ctx->work, | |
298 | HZ * (ulong)DEVCMD_TIMEOUT); | |
299 | return ionic_adminq_check_err(lif, ctx, (remaining == 0)); | |
300 | } | |
301 | ||
1d062b7b SN |
302 | int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb, |
303 | ionic_cq_done_cb done_cb, void *done_arg) | |
304 | { | |
305 | struct ionic_qcq *qcq = napi_to_qcq(napi); | |
306 | struct ionic_cq *cq = &qcq->cq; | |
307 | u32 work_done, flags = 0; | |
308 | ||
309 | work_done = ionic_cq_service(cq, budget, cb, done_cb, done_arg); | |
310 | ||
311 | if (work_done < budget && napi_complete_done(napi, work_done)) { | |
312 | flags |= IONIC_INTR_CRED_UNMASK; | |
313 | DEBUG_STATS_INTR_REARM(cq->bound_intr); | |
314 | } | |
315 | ||
316 | if (work_done || flags) { | |
317 | flags |= IONIC_INTR_CRED_RESET_COALESCE; | |
318 | ionic_intr_credits(cq->lif->ionic->idev.intr_ctrl, | |
319 | cq->bound_intr->index, | |
320 | work_done, flags); | |
321 | } | |
322 | ||
323 | DEBUG_STATS_NAPI_POLL(qcq, work_done); | |
324 | ||
325 | return work_done; | |
326 | } | |
327 | ||
97ca4865 SN |
328 | static void ionic_dev_cmd_clean(struct ionic *ionic) |
329 | { | |
330 | union ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; | |
331 | ||
332 | iowrite32(0, ®s->doorbell); | |
333 | memset_io(®s->cmd, 0, sizeof(regs->cmd)); | |
334 | } | |
335 | ||
fbfb8031 SN |
336 | int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) |
337 | { | |
338 | struct ionic_dev *idev = &ionic->idev; | |
339 | unsigned long start_time; | |
340 | unsigned long max_wait; | |
341 | unsigned long duration; | |
342 | int opcode; | |
6be1a5ce | 343 | int hb = 0; |
fbfb8031 SN |
344 | int done; |
345 | int err; | |
346 | ||
347 | WARN_ON(in_interrupt()); | |
348 | ||
349 | /* Wait for dev cmd to complete, retrying if we get EAGAIN, | |
350 | * but don't wait any longer than max_seconds. | |
351 | */ | |
352 | max_wait = jiffies + (max_seconds * HZ); | |
353 | try_again: | |
354 | start_time = jiffies; | |
355 | do { | |
356 | done = ionic_dev_cmd_done(idev); | |
357 | if (done) | |
358 | break; | |
359 | msleep(20); | |
97ca4865 SN |
360 | hb = ionic_heartbeat_check(ionic); |
361 | } while (!done && !hb && time_before(jiffies, max_wait)); | |
fbfb8031 SN |
362 | duration = jiffies - start_time; |
363 | ||
364 | opcode = idev->dev_cmd_regs->cmd.cmd.opcode; | |
365 | dev_dbg(ionic->dev, "DEVCMD %s (%d) done=%d took %ld secs (%ld jiffies)\n", | |
366 | ionic_opcode_to_str(opcode), opcode, | |
367 | done, duration / HZ, duration); | |
368 | ||
97ca4865 | 369 | if (!done && hb) { |
2530ba5a SN |
370 | /* It is possible (but unlikely) that FW was busy and missed a |
371 | * heartbeat check but is still alive and will process this | |
372 | * request, so don't clean the dev_cmd in this case. | |
373 | */ | |
97ca4865 SN |
374 | dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n", |
375 | ionic_opcode_to_str(opcode), opcode); | |
376 | return -ENXIO; | |
377 | } | |
378 | ||
fbfb8031 | 379 | if (!done && !time_before(jiffies, max_wait)) { |
97ca4865 | 380 | ionic_dev_cmd_clean(ionic); |
fbfb8031 SN |
381 | dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n", |
382 | ionic_opcode_to_str(opcode), opcode, max_seconds); | |
383 | return -ETIMEDOUT; | |
384 | } | |
385 | ||
386 | err = ionic_dev_cmd_status(&ionic->idev); | |
387 | if (err) { | |
388 | if (err == IONIC_RC_EAGAIN && !time_after(jiffies, max_wait)) { | |
389 | dev_err(ionic->dev, "DEV_CMD %s (%d) error, %s (%d) retrying...\n", | |
390 | ionic_opcode_to_str(opcode), opcode, | |
391 | ionic_error_to_str(err), err); | |
392 | ||
393 | msleep(1000); | |
394 | iowrite32(0, &idev->dev_cmd_regs->done); | |
395 | iowrite32(1, &idev->dev_cmd_regs->doorbell); | |
396 | goto try_again; | |
397 | } | |
398 | ||
399 | dev_err(ionic->dev, "DEV_CMD %s (%d) error, %s (%d) failed\n", | |
400 | ionic_opcode_to_str(opcode), opcode, | |
401 | ionic_error_to_str(err), err); | |
402 | ||
403 | return ionic_error_to_errno(err); | |
404 | } | |
405 | ||
406 | return 0; | |
407 | } | |
408 | ||
409 | int ionic_setup(struct ionic *ionic) | |
410 | { | |
411 | int err; | |
412 | ||
413 | err = ionic_dev_setup(ionic); | |
414 | if (err) | |
415 | return err; | |
416 | ||
417 | return 0; | |
418 | } | |
419 | ||
420 | int ionic_identify(struct ionic *ionic) | |
421 | { | |
422 | struct ionic_identity *ident = &ionic->ident; | |
423 | struct ionic_dev *idev = &ionic->idev; | |
424 | size_t sz; | |
425 | int err; | |
426 | ||
427 | memset(ident, 0, sizeof(*ident)); | |
428 | ||
429 | ident->drv.os_type = cpu_to_le32(IONIC_OS_TYPE_LINUX); | |
1fcbebf1 | 430 | strncpy(ident->drv.driver_ver_str, UTS_RELEASE, |
fbfb8031 SN |
431 | sizeof(ident->drv.driver_ver_str) - 1); |
432 | ||
433 | mutex_lock(&ionic->dev_cmd_lock); | |
434 | ||
435 | sz = min(sizeof(ident->drv), sizeof(idev->dev_cmd_regs->data)); | |
436 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->drv, sz); | |
437 | ||
438 | ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1); | |
439 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
440 | if (!err) { | |
441 | sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data)); | |
442 | memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz); | |
443 | } | |
444 | ||
445 | mutex_unlock(&ionic->dev_cmd_lock); | |
446 | ||
447 | if (err) | |
448 | goto err_out_unmap; | |
449 | ||
450 | ionic_debugfs_add_ident(ionic); | |
451 | ||
452 | return 0; | |
453 | ||
454 | err_out_unmap: | |
455 | return err; | |
456 | } | |
457 | ||
458 | int ionic_init(struct ionic *ionic) | |
459 | { | |
460 | struct ionic_dev *idev = &ionic->idev; | |
461 | int err; | |
462 | ||
463 | mutex_lock(&ionic->dev_cmd_lock); | |
464 | ionic_dev_cmd_init(idev); | |
465 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
466 | mutex_unlock(&ionic->dev_cmd_lock); | |
467 | ||
468 | return err; | |
469 | } | |
470 | ||
471 | int ionic_reset(struct ionic *ionic) | |
472 | { | |
473 | struct ionic_dev *idev = &ionic->idev; | |
474 | int err; | |
475 | ||
476 | mutex_lock(&ionic->dev_cmd_lock); | |
477 | ionic_dev_cmd_reset(idev); | |
478 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
479 | mutex_unlock(&ionic->dev_cmd_lock); | |
480 | ||
481 | return err; | |
482 | } | |
483 | ||
04436595 SN |
484 | int ionic_port_identify(struct ionic *ionic) |
485 | { | |
486 | struct ionic_identity *ident = &ionic->ident; | |
487 | struct ionic_dev *idev = &ionic->idev; | |
488 | size_t sz; | |
489 | int err; | |
490 | ||
491 | mutex_lock(&ionic->dev_cmd_lock); | |
492 | ||
493 | ionic_dev_cmd_port_identify(idev); | |
494 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
495 | if (!err) { | |
496 | sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data)); | |
497 | memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz); | |
498 | } | |
499 | ||
500 | mutex_unlock(&ionic->dev_cmd_lock); | |
501 | ||
502 | return err; | |
503 | } | |
504 | ||
505 | int ionic_port_init(struct ionic *ionic) | |
506 | { | |
507 | struct ionic_identity *ident = &ionic->ident; | |
508 | struct ionic_dev *idev = &ionic->idev; | |
509 | size_t sz; | |
510 | int err; | |
511 | ||
04436595 | 512 | if (!idev->port_info) { |
ddc5911b SN |
513 | idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE); |
514 | idev->port_info = dma_alloc_coherent(ionic->dev, | |
515 | idev->port_info_sz, | |
516 | &idev->port_info_pa, | |
517 | GFP_KERNEL); | |
518 | if (!idev->port_info) { | |
519 | dev_err(ionic->dev, "Failed to allocate port info\n"); | |
520 | return -ENOMEM; | |
521 | } | |
04436595 SN |
522 | } |
523 | ||
524 | sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data)); | |
525 | ||
526 | mutex_lock(&ionic->dev_cmd_lock); | |
527 | ||
528 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz); | |
529 | ionic_dev_cmd_port_init(idev); | |
530 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
531 | ||
532 | ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP); | |
533 | (void)ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
534 | ||
535 | mutex_unlock(&ionic->dev_cmd_lock); | |
536 | if (err) { | |
537 | dev_err(ionic->dev, "Failed to init port\n"); | |
538 | dma_free_coherent(ionic->dev, idev->port_info_sz, | |
539 | idev->port_info, idev->port_info_pa); | |
540 | idev->port_info = NULL; | |
541 | idev->port_info_pa = 0; | |
542 | } | |
543 | ||
544 | return err; | |
545 | } | |
546 | ||
547 | int ionic_port_reset(struct ionic *ionic) | |
548 | { | |
549 | struct ionic_dev *idev = &ionic->idev; | |
550 | int err; | |
551 | ||
552 | if (!idev->port_info) | |
553 | return 0; | |
554 | ||
555 | mutex_lock(&ionic->dev_cmd_lock); | |
556 | ionic_dev_cmd_port_reset(idev); | |
557 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); | |
558 | mutex_unlock(&ionic->dev_cmd_lock); | |
559 | ||
560 | dma_free_coherent(ionic->dev, idev->port_info_sz, | |
561 | idev->port_info, idev->port_info_pa); | |
562 | ||
563 | idev->port_info = NULL; | |
564 | idev->port_info_pa = 0; | |
565 | ||
566 | if (err) | |
567 | dev_err(ionic->dev, "Failed to reset port\n"); | |
568 | ||
569 | return err; | |
570 | } | |
571 | ||
df69ba43 SN |
572 | static int __init ionic_init_module(void) |
573 | { | |
fbfb8031 | 574 | ionic_debugfs_create(); |
df69ba43 SN |
575 | return ionic_bus_register_driver(); |
576 | } | |
577 | ||
578 | static void __exit ionic_cleanup_module(void) | |
579 | { | |
580 | ionic_bus_unregister_driver(); | |
fbfb8031 | 581 | ionic_debugfs_destroy(); |
df69ba43 SN |
582 | |
583 | pr_info("%s removed\n", IONIC_DRV_NAME); | |
584 | } | |
585 | ||
586 | module_init(ionic_init_module); | |
587 | module_exit(ionic_cleanup_module); |