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