xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/pensando/ionic/ionic_main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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