xref: /openbmc/linux/drivers/staging/qlge/qlge_mpi.c (revision e7fd1a5a)
1955315b0SBenjamin Poirier // SPDX-License-Identifier: GPL-2.0
2955315b0SBenjamin Poirier #include "qlge.h"
3955315b0SBenjamin Poirier 
qlge_unpause_mpi_risc(struct qlge_adapter * qdev)4f8c047beSCoiby Xu int qlge_unpause_mpi_risc(struct qlge_adapter *qdev)
5955315b0SBenjamin Poirier {
6955315b0SBenjamin Poirier 	u32 tmp;
7955315b0SBenjamin Poirier 
8955315b0SBenjamin Poirier 	/* Un-pause the RISC */
9f8c047beSCoiby Xu 	tmp = qlge_read32(qdev, CSR);
10955315b0SBenjamin Poirier 	if (!(tmp & CSR_RP))
11955315b0SBenjamin Poirier 		return -EIO;
12955315b0SBenjamin Poirier 
13f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_CLR_PAUSE);
14955315b0SBenjamin Poirier 	return 0;
15955315b0SBenjamin Poirier }
16955315b0SBenjamin Poirier 
qlge_pause_mpi_risc(struct qlge_adapter * qdev)17f8c047beSCoiby Xu int qlge_pause_mpi_risc(struct qlge_adapter *qdev)
18955315b0SBenjamin Poirier {
19955315b0SBenjamin Poirier 	u32 tmp;
2045170f10SSuraj Upadhyay 	int count;
21955315b0SBenjamin Poirier 
22955315b0SBenjamin Poirier 	/* Pause the RISC */
23f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_SET_PAUSE);
2445170f10SSuraj Upadhyay 	for (count = UDELAY_COUNT; count; count--) {
25f8c047beSCoiby Xu 		tmp = qlge_read32(qdev, CSR);
26955315b0SBenjamin Poirier 		if (tmp & CSR_RP)
27955315b0SBenjamin Poirier 			break;
28955315b0SBenjamin Poirier 		mdelay(UDELAY_DELAY);
2945170f10SSuraj Upadhyay 	}
30955315b0SBenjamin Poirier 	return (count == 0) ? -ETIMEDOUT : 0;
31955315b0SBenjamin Poirier }
32955315b0SBenjamin Poirier 
qlge_hard_reset_mpi_risc(struct qlge_adapter * qdev)33f8c047beSCoiby Xu int qlge_hard_reset_mpi_risc(struct qlge_adapter *qdev)
34955315b0SBenjamin Poirier {
35955315b0SBenjamin Poirier 	u32 tmp;
3645170f10SSuraj Upadhyay 	int count;
37955315b0SBenjamin Poirier 
38955315b0SBenjamin Poirier 	/* Reset the RISC */
39f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_SET_RST);
4045170f10SSuraj Upadhyay 	for (count = UDELAY_COUNT; count; count--) {
41f8c047beSCoiby Xu 		tmp = qlge_read32(qdev, CSR);
42955315b0SBenjamin Poirier 		if (tmp & CSR_RR) {
43f8c047beSCoiby Xu 			qlge_write32(qdev, CSR, CSR_CMD_CLR_RST);
44955315b0SBenjamin Poirier 			break;
45955315b0SBenjamin Poirier 		}
46955315b0SBenjamin Poirier 		mdelay(UDELAY_DELAY);
4745170f10SSuraj Upadhyay 	}
48955315b0SBenjamin Poirier 	return (count == 0) ? -ETIMEDOUT : 0;
49955315b0SBenjamin Poirier }
50955315b0SBenjamin Poirier 
qlge_read_mpi_reg(struct qlge_adapter * qdev,u32 reg,u32 * data)51f8c047beSCoiby Xu int qlge_read_mpi_reg(struct qlge_adapter *qdev, u32 reg, u32 *data)
52955315b0SBenjamin Poirier {
53955315b0SBenjamin Poirier 	int status;
54955315b0SBenjamin Poirier 	/* wait for reg to come ready */
55f8c047beSCoiby Xu 	status = qlge_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
56955315b0SBenjamin Poirier 	if (status)
57955315b0SBenjamin Poirier 		goto exit;
58955315b0SBenjamin Poirier 	/* set up for reg read */
59f8c047beSCoiby Xu 	qlge_write32(qdev, PROC_ADDR, reg | PROC_ADDR_R);
60955315b0SBenjamin Poirier 	/* wait for reg to come ready */
61f8c047beSCoiby Xu 	status = qlge_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
62955315b0SBenjamin Poirier 	if (status)
63955315b0SBenjamin Poirier 		goto exit;
64955315b0SBenjamin Poirier 	/* get the data */
65f8c047beSCoiby Xu 	*data = qlge_read32(qdev, PROC_DATA);
66955315b0SBenjamin Poirier exit:
67955315b0SBenjamin Poirier 	return status;
68955315b0SBenjamin Poirier }
69955315b0SBenjamin Poirier 
qlge_write_mpi_reg(struct qlge_adapter * qdev,u32 reg,u32 data)70f8c047beSCoiby Xu int qlge_write_mpi_reg(struct qlge_adapter *qdev, u32 reg, u32 data)
71955315b0SBenjamin Poirier {
72955315b0SBenjamin Poirier 	int status = 0;
73955315b0SBenjamin Poirier 	/* wait for reg to come ready */
74f8c047beSCoiby Xu 	status = qlge_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
75955315b0SBenjamin Poirier 	if (status)
76955315b0SBenjamin Poirier 		goto exit;
77955315b0SBenjamin Poirier 	/* write the data to the data reg */
78f8c047beSCoiby Xu 	qlge_write32(qdev, PROC_DATA, data);
79955315b0SBenjamin Poirier 	/* trigger the write */
80f8c047beSCoiby Xu 	qlge_write32(qdev, PROC_ADDR, reg);
81955315b0SBenjamin Poirier 	/* wait for reg to come ready */
82f8c047beSCoiby Xu 	status = qlge_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
83955315b0SBenjamin Poirier 	if (status)
84955315b0SBenjamin Poirier 		goto exit;
85955315b0SBenjamin Poirier exit:
86955315b0SBenjamin Poirier 	return status;
87955315b0SBenjamin Poirier }
88955315b0SBenjamin Poirier 
qlge_soft_reset_mpi_risc(struct qlge_adapter * qdev)89f8c047beSCoiby Xu int qlge_soft_reset_mpi_risc(struct qlge_adapter *qdev)
90955315b0SBenjamin Poirier {
91f8c047beSCoiby Xu 	return qlge_write_mpi_reg(qdev, 0x00001010, 1);
92955315b0SBenjamin Poirier }
93955315b0SBenjamin Poirier 
9487e6059dSElena Afanasova /* Determine if we are in charge of the firmware. If
95955315b0SBenjamin Poirier  * we are the lower of the 2 NIC pcie functions, or if
96955315b0SBenjamin Poirier  * we are the higher function and the lower function
97955315b0SBenjamin Poirier  * is not enabled.
98955315b0SBenjamin Poirier  */
qlge_own_firmware(struct qlge_adapter * qdev)99f8c047beSCoiby Xu int qlge_own_firmware(struct qlge_adapter *qdev)
100955315b0SBenjamin Poirier {
101955315b0SBenjamin Poirier 	u32 temp;
102955315b0SBenjamin Poirier 
103955315b0SBenjamin Poirier 	/* If we are the lower of the 2 NIC functions
104955315b0SBenjamin Poirier 	 * on the chip the we are responsible for
105955315b0SBenjamin Poirier 	 * core dump and firmware reset after an error.
106955315b0SBenjamin Poirier 	 */
107955315b0SBenjamin Poirier 	if (qdev->func < qdev->alt_func)
108955315b0SBenjamin Poirier 		return 1;
109955315b0SBenjamin Poirier 
110955315b0SBenjamin Poirier 	/* If we are the higher of the 2 NIC functions
111955315b0SBenjamin Poirier 	 * on the chip and the lower function is not
112955315b0SBenjamin Poirier 	 * enabled, then we are responsible for
113955315b0SBenjamin Poirier 	 * core dump and firmware reset after an error.
114955315b0SBenjamin Poirier 	 */
115f8c047beSCoiby Xu 	temp =  qlge_read32(qdev, STS);
116955315b0SBenjamin Poirier 	if (!(temp & (1 << (8 + qdev->alt_func))))
117955315b0SBenjamin Poirier 		return 1;
118955315b0SBenjamin Poirier 
119955315b0SBenjamin Poirier 	return 0;
120955315b0SBenjamin Poirier }
121955315b0SBenjamin Poirier 
qlge_get_mb_sts(struct qlge_adapter * qdev,struct mbox_params * mbcp)122f8c047beSCoiby Xu static int qlge_get_mb_sts(struct qlge_adapter *qdev, struct mbox_params *mbcp)
123955315b0SBenjamin Poirier {
124955315b0SBenjamin Poirier 	int i, status;
125955315b0SBenjamin Poirier 
126f8c047beSCoiby Xu 	status = qlge_sem_spinlock(qdev, SEM_PROC_REG_MASK);
127955315b0SBenjamin Poirier 	if (status)
128955315b0SBenjamin Poirier 		return -EBUSY;
129955315b0SBenjamin Poirier 	for (i = 0; i < mbcp->out_count; i++) {
130955315b0SBenjamin Poirier 		status =
131f8c047beSCoiby Xu 		    qlge_read_mpi_reg(qdev, qdev->mailbox_out + i,
132955315b0SBenjamin Poirier 				      &mbcp->mbox_out[i]);
133955315b0SBenjamin Poirier 		if (status) {
134955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev, "Failed mailbox read.\n");
135955315b0SBenjamin Poirier 			break;
136955315b0SBenjamin Poirier 		}
137955315b0SBenjamin Poirier 	}
138f8c047beSCoiby Xu 	qlge_sem_unlock(qdev, SEM_PROC_REG_MASK);	/* does flush too */
139955315b0SBenjamin Poirier 	return status;
140955315b0SBenjamin Poirier }
141955315b0SBenjamin Poirier 
142955315b0SBenjamin Poirier /* Wait for a single mailbox command to complete.
143955315b0SBenjamin Poirier  * Returns zero on success.
144955315b0SBenjamin Poirier  */
qlge_wait_mbx_cmd_cmplt(struct qlge_adapter * qdev)145f8c047beSCoiby Xu static int qlge_wait_mbx_cmd_cmplt(struct qlge_adapter *qdev)
146955315b0SBenjamin Poirier {
14745170f10SSuraj Upadhyay 	int count;
148955315b0SBenjamin Poirier 	u32 value;
149955315b0SBenjamin Poirier 
15045170f10SSuraj Upadhyay 	for (count = 100; count; count--) {
151f8c047beSCoiby Xu 		value = qlge_read32(qdev, STS);
152955315b0SBenjamin Poirier 		if (value & STS_PI)
153955315b0SBenjamin Poirier 			return 0;
154955315b0SBenjamin Poirier 		mdelay(UDELAY_DELAY); /* 100ms */
15545170f10SSuraj Upadhyay 	}
156955315b0SBenjamin Poirier 	return -ETIMEDOUT;
157955315b0SBenjamin Poirier }
158955315b0SBenjamin Poirier 
159955315b0SBenjamin Poirier /* Execute a single mailbox command.
160955315b0SBenjamin Poirier  * Caller must hold PROC_ADDR semaphore.
161955315b0SBenjamin Poirier  */
qlge_exec_mb_cmd(struct qlge_adapter * qdev,struct mbox_params * mbcp)162f8c047beSCoiby Xu static int qlge_exec_mb_cmd(struct qlge_adapter *qdev, struct mbox_params *mbcp)
163955315b0SBenjamin Poirier {
164955315b0SBenjamin Poirier 	int i, status;
165955315b0SBenjamin Poirier 
166955315b0SBenjamin Poirier 	/*
167955315b0SBenjamin Poirier 	 * Make sure there's nothing pending.
168955315b0SBenjamin Poirier 	 * This shouldn't happen.
169955315b0SBenjamin Poirier 	 */
170f8c047beSCoiby Xu 	if (qlge_read32(qdev, CSR) & CSR_HRI)
171955315b0SBenjamin Poirier 		return -EIO;
172955315b0SBenjamin Poirier 
173f8c047beSCoiby Xu 	status = qlge_sem_spinlock(qdev, SEM_PROC_REG_MASK);
174955315b0SBenjamin Poirier 	if (status)
175955315b0SBenjamin Poirier 		return status;
176955315b0SBenjamin Poirier 
177955315b0SBenjamin Poirier 	/*
178955315b0SBenjamin Poirier 	 * Fill the outbound mailboxes.
179955315b0SBenjamin Poirier 	 */
180955315b0SBenjamin Poirier 	for (i = 0; i < mbcp->in_count; i++) {
181f8c047beSCoiby Xu 		status = qlge_write_mpi_reg(qdev, qdev->mailbox_in + i,
182955315b0SBenjamin Poirier 					    mbcp->mbox_in[i]);
183955315b0SBenjamin Poirier 		if (status)
184955315b0SBenjamin Poirier 			goto end;
185955315b0SBenjamin Poirier 	}
186955315b0SBenjamin Poirier 	/*
187955315b0SBenjamin Poirier 	 * Wake up the MPI firmware.
188955315b0SBenjamin Poirier 	 */
189f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_SET_H2R_INT);
190955315b0SBenjamin Poirier end:
191f8c047beSCoiby Xu 	qlge_sem_unlock(qdev, SEM_PROC_REG_MASK);
192955315b0SBenjamin Poirier 	return status;
193955315b0SBenjamin Poirier }
194955315b0SBenjamin Poirier 
195955315b0SBenjamin Poirier /* We are being asked by firmware to accept
196955315b0SBenjamin Poirier  * a change to the port.  This is only
197955315b0SBenjamin Poirier  * a change to max frame sizes (Tx/Rx), pause
198955315b0SBenjamin Poirier  * parameters, or loopback mode. We wake up a worker
199955315b0SBenjamin Poirier  * to handler processing this since a mailbox command
200955315b0SBenjamin Poirier  * will need to be sent to ACK the request.
201955315b0SBenjamin Poirier  */
qlge_idc_req_aen(struct qlge_adapter * qdev)202f8c047beSCoiby Xu static int qlge_idc_req_aen(struct qlge_adapter *qdev)
203955315b0SBenjamin Poirier {
204955315b0SBenjamin Poirier 	int status;
205955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &qdev->idc_mbc;
206955315b0SBenjamin Poirier 
207955315b0SBenjamin Poirier 	netif_err(qdev, drv, qdev->ndev, "Enter!\n");
208955315b0SBenjamin Poirier 	/* Get the status data and start up a thread to
209955315b0SBenjamin Poirier 	 * handle the request.
210955315b0SBenjamin Poirier 	 */
211955315b0SBenjamin Poirier 	mbcp->out_count = 4;
212f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
213955315b0SBenjamin Poirier 	if (status) {
214955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
215955315b0SBenjamin Poirier 			  "Could not read MPI, resetting ASIC!\n");
216f8c047beSCoiby Xu 		qlge_queue_asic_error(qdev);
217955315b0SBenjamin Poirier 	} else	{
218955315b0SBenjamin Poirier 		/* Begin polled mode early so
219955315b0SBenjamin Poirier 		 * we don't get another interrupt
220955315b0SBenjamin Poirier 		 * when we leave mpi_worker.
221955315b0SBenjamin Poirier 		 */
222f8c047beSCoiby Xu 		qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
223955315b0SBenjamin Poirier 		queue_delayed_work(qdev->workqueue, &qdev->mpi_idc_work, 0);
224955315b0SBenjamin Poirier 	}
225955315b0SBenjamin Poirier 	return status;
226955315b0SBenjamin Poirier }
227955315b0SBenjamin Poirier 
228955315b0SBenjamin Poirier /* Process an inter-device event completion.
229955315b0SBenjamin Poirier  * If good, signal the caller's completion.
230955315b0SBenjamin Poirier  */
qlge_idc_cmplt_aen(struct qlge_adapter * qdev)231f8c047beSCoiby Xu static int qlge_idc_cmplt_aen(struct qlge_adapter *qdev)
232955315b0SBenjamin Poirier {
233955315b0SBenjamin Poirier 	int status;
234955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &qdev->idc_mbc;
2357d508880SCarlos Henrique Lima Melara 
236955315b0SBenjamin Poirier 	mbcp->out_count = 4;
237f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
238955315b0SBenjamin Poirier 	if (status) {
239955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
240955315b0SBenjamin Poirier 			  "Could not read MPI, resetting RISC!\n");
241f8c047beSCoiby Xu 		qlge_queue_fw_error(qdev);
242608a911bSSebastian Fuentes 	} else {
243955315b0SBenjamin Poirier 		/* Wake up the sleeping mpi_idc_work thread that is
244955315b0SBenjamin Poirier 		 * waiting for this event.
245955315b0SBenjamin Poirier 		 */
246955315b0SBenjamin Poirier 		complete(&qdev->ide_completion);
247608a911bSSebastian Fuentes 	}
248955315b0SBenjamin Poirier 	return status;
249955315b0SBenjamin Poirier }
250955315b0SBenjamin Poirier 
qlge_link_up(struct qlge_adapter * qdev,struct mbox_params * mbcp)251f8c047beSCoiby Xu static void qlge_link_up(struct qlge_adapter *qdev, struct mbox_params *mbcp)
252955315b0SBenjamin Poirier {
253955315b0SBenjamin Poirier 	int status;
2547d508880SCarlos Henrique Lima Melara 
255955315b0SBenjamin Poirier 	mbcp->out_count = 2;
256955315b0SBenjamin Poirier 
257f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
258955315b0SBenjamin Poirier 	if (status) {
259955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
260955315b0SBenjamin Poirier 			  "%s: Could not get mailbox status.\n", __func__);
261955315b0SBenjamin Poirier 		return;
262955315b0SBenjamin Poirier 	}
263955315b0SBenjamin Poirier 
264955315b0SBenjamin Poirier 	qdev->link_status = mbcp->mbox_out[1];
265955315b0SBenjamin Poirier 	netif_err(qdev, drv, qdev->ndev, "Link Up.\n");
266955315b0SBenjamin Poirier 
267955315b0SBenjamin Poirier 	/* If we're coming back from an IDC event
268955315b0SBenjamin Poirier 	 * then set up the CAM and frame routing.
269955315b0SBenjamin Poirier 	 */
270955315b0SBenjamin Poirier 	if (test_bit(QL_CAM_RT_SET, &qdev->flags)) {
271f8c047beSCoiby Xu 		status = qlge_cam_route_initialize(qdev);
272955315b0SBenjamin Poirier 		if (status) {
273955315b0SBenjamin Poirier 			netif_err(qdev, ifup, qdev->ndev,
274955315b0SBenjamin Poirier 				  "Failed to init CAM/Routing tables.\n");
275955315b0SBenjamin Poirier 			return;
276e42f623cSCoiby Xu 		}
277955315b0SBenjamin Poirier 		clear_bit(QL_CAM_RT_SET, &qdev->flags);
278955315b0SBenjamin Poirier 	}
279955315b0SBenjamin Poirier 
280955315b0SBenjamin Poirier 	/* Queue up a worker to check the frame
281955315b0SBenjamin Poirier 	 * size information, and fix it if it's not
282955315b0SBenjamin Poirier 	 * to our liking.
283955315b0SBenjamin Poirier 	 */
284955315b0SBenjamin Poirier 	if (!test_bit(QL_PORT_CFG, &qdev->flags)) {
285955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Queue Port Config Worker!\n");
286955315b0SBenjamin Poirier 		set_bit(QL_PORT_CFG, &qdev->flags);
287955315b0SBenjamin Poirier 		/* Begin polled mode early so
288955315b0SBenjamin Poirier 		 * we don't get another interrupt
289955315b0SBenjamin Poirier 		 * when we leave mpi_worker dpc.
290955315b0SBenjamin Poirier 		 */
291f8c047beSCoiby Xu 		qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
292955315b0SBenjamin Poirier 		queue_delayed_work(qdev->workqueue,
293955315b0SBenjamin Poirier 				   &qdev->mpi_port_cfg_work, 0);
294955315b0SBenjamin Poirier 	}
295955315b0SBenjamin Poirier 
296f8c047beSCoiby Xu 	qlge_link_on(qdev);
297955315b0SBenjamin Poirier }
298955315b0SBenjamin Poirier 
qlge_link_down(struct qlge_adapter * qdev,struct mbox_params * mbcp)299f8c047beSCoiby Xu static void qlge_link_down(struct qlge_adapter *qdev, struct mbox_params *mbcp)
300955315b0SBenjamin Poirier {
301955315b0SBenjamin Poirier 	int status;
302955315b0SBenjamin Poirier 
303955315b0SBenjamin Poirier 	mbcp->out_count = 3;
304955315b0SBenjamin Poirier 
305f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
306955315b0SBenjamin Poirier 	if (status)
307955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Link down AEN broken!\n");
308955315b0SBenjamin Poirier 
309f8c047beSCoiby Xu 	qlge_link_off(qdev);
310955315b0SBenjamin Poirier }
311955315b0SBenjamin Poirier 
qlge_sfp_in(struct qlge_adapter * qdev,struct mbox_params * mbcp)312f8c047beSCoiby Xu static int qlge_sfp_in(struct qlge_adapter *qdev, struct mbox_params *mbcp)
313955315b0SBenjamin Poirier {
314955315b0SBenjamin Poirier 	int status;
315955315b0SBenjamin Poirier 
316955315b0SBenjamin Poirier 	mbcp->out_count = 5;
317955315b0SBenjamin Poirier 
318f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
319955315b0SBenjamin Poirier 	if (status)
320955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "SFP in AEN broken!\n");
321955315b0SBenjamin Poirier 	else
322955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "SFP insertion detected.\n");
323955315b0SBenjamin Poirier 
324955315b0SBenjamin Poirier 	return status;
325955315b0SBenjamin Poirier }
326955315b0SBenjamin Poirier 
qlge_sfp_out(struct qlge_adapter * qdev,struct mbox_params * mbcp)327f8c047beSCoiby Xu static int qlge_sfp_out(struct qlge_adapter *qdev, struct mbox_params *mbcp)
328955315b0SBenjamin Poirier {
329955315b0SBenjamin Poirier 	int status;
330955315b0SBenjamin Poirier 
331955315b0SBenjamin Poirier 	mbcp->out_count = 1;
332955315b0SBenjamin Poirier 
333f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
334955315b0SBenjamin Poirier 	if (status)
335955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "SFP out AEN broken!\n");
336955315b0SBenjamin Poirier 	else
337955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "SFP removal detected.\n");
338955315b0SBenjamin Poirier 
339955315b0SBenjamin Poirier 	return status;
340955315b0SBenjamin Poirier }
341955315b0SBenjamin Poirier 
qlge_aen_lost(struct qlge_adapter * qdev,struct mbox_params * mbcp)342f8c047beSCoiby Xu static int qlge_aen_lost(struct qlge_adapter *qdev, struct mbox_params *mbcp)
343955315b0SBenjamin Poirier {
344955315b0SBenjamin Poirier 	int status;
345955315b0SBenjamin Poirier 
346955315b0SBenjamin Poirier 	mbcp->out_count = 6;
347955315b0SBenjamin Poirier 
348f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
349608a911bSSebastian Fuentes 	if (status) {
350955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Lost AEN broken!\n");
351608a911bSSebastian Fuentes 	} else {
352955315b0SBenjamin Poirier 		int i;
3537d508880SCarlos Henrique Lima Melara 
354955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Lost AEN detected.\n");
355955315b0SBenjamin Poirier 		for (i = 0; i < mbcp->out_count; i++)
356955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev, "mbox_out[%d] = 0x%.08x.\n",
357955315b0SBenjamin Poirier 				  i, mbcp->mbox_out[i]);
358955315b0SBenjamin Poirier 	}
359955315b0SBenjamin Poirier 
360955315b0SBenjamin Poirier 	return status;
361955315b0SBenjamin Poirier }
362955315b0SBenjamin Poirier 
qlge_init_fw_done(struct qlge_adapter * qdev,struct mbox_params * mbcp)363f8c047beSCoiby Xu static void qlge_init_fw_done(struct qlge_adapter *qdev, struct mbox_params *mbcp)
364955315b0SBenjamin Poirier {
365955315b0SBenjamin Poirier 	int status;
366955315b0SBenjamin Poirier 
367955315b0SBenjamin Poirier 	mbcp->out_count = 2;
368955315b0SBenjamin Poirier 
369f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
370955315b0SBenjamin Poirier 	if (status) {
371955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Firmware did not initialize!\n");
372955315b0SBenjamin Poirier 	} else {
373955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Firmware Revision  = 0x%.08x.\n",
374955315b0SBenjamin Poirier 			  mbcp->mbox_out[1]);
375955315b0SBenjamin Poirier 		qdev->fw_rev_id = mbcp->mbox_out[1];
376f8c047beSCoiby Xu 		status = qlge_cam_route_initialize(qdev);
377955315b0SBenjamin Poirier 		if (status)
378955315b0SBenjamin Poirier 			netif_err(qdev, ifup, qdev->ndev,
379955315b0SBenjamin Poirier 				  "Failed to init CAM/Routing tables.\n");
380955315b0SBenjamin Poirier 	}
381955315b0SBenjamin Poirier }
382955315b0SBenjamin Poirier 
383955315b0SBenjamin Poirier /* Process an async event and clear it unless it's an
384955315b0SBenjamin Poirier  * error condition.
385955315b0SBenjamin Poirier  *  This can get called iteratively from the mpi_work thread
386955315b0SBenjamin Poirier  *  when events arrive via an interrupt.
387955315b0SBenjamin Poirier  *  It also gets called when a mailbox command is polling for
3881113c90cSCoiby Xu  *  it's completion.
3891113c90cSCoiby Xu  */
qlge_mpi_handler(struct qlge_adapter * qdev,struct mbox_params * mbcp)390f8c047beSCoiby Xu static int qlge_mpi_handler(struct qlge_adapter *qdev, struct mbox_params *mbcp)
391955315b0SBenjamin Poirier {
392955315b0SBenjamin Poirier 	int status;
393955315b0SBenjamin Poirier 	int orig_count = mbcp->out_count;
394955315b0SBenjamin Poirier 
395955315b0SBenjamin Poirier 	/* Just get mailbox zero for now. */
396955315b0SBenjamin Poirier 	mbcp->out_count = 1;
397f8c047beSCoiby Xu 	status = qlge_get_mb_sts(qdev, mbcp);
398955315b0SBenjamin Poirier 	if (status) {
399955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
400955315b0SBenjamin Poirier 			  "Could not read MPI, resetting ASIC!\n");
401f8c047beSCoiby Xu 		qlge_queue_asic_error(qdev);
402955315b0SBenjamin Poirier 		goto end;
403955315b0SBenjamin Poirier 	}
404955315b0SBenjamin Poirier 
405955315b0SBenjamin Poirier 	switch (mbcp->mbox_out[0]) {
406955315b0SBenjamin Poirier 		/* This case is only active when we arrive here
407955315b0SBenjamin Poirier 		 * as a result of issuing a mailbox command to
408955315b0SBenjamin Poirier 		 * the firmware.
409955315b0SBenjamin Poirier 		 */
410955315b0SBenjamin Poirier 	case MB_CMD_STS_INTRMDT:
411955315b0SBenjamin Poirier 	case MB_CMD_STS_GOOD:
412955315b0SBenjamin Poirier 	case MB_CMD_STS_INVLD_CMD:
413955315b0SBenjamin Poirier 	case MB_CMD_STS_XFC_ERR:
414955315b0SBenjamin Poirier 	case MB_CMD_STS_CSUM_ERR:
415955315b0SBenjamin Poirier 	case MB_CMD_STS_ERR:
416955315b0SBenjamin Poirier 	case MB_CMD_STS_PARAM_ERR:
417955315b0SBenjamin Poirier 		/* We can only get mailbox status if we're polling from an
418955315b0SBenjamin Poirier 		 * unfinished command.  Get the rest of the status data and
419955315b0SBenjamin Poirier 		 * return back to the caller.
420955315b0SBenjamin Poirier 		 * We only end up here when we're polling for a mailbox
421955315b0SBenjamin Poirier 		 * command completion.
422955315b0SBenjamin Poirier 		 */
423955315b0SBenjamin Poirier 		mbcp->out_count = orig_count;
424f8c047beSCoiby Xu 		status = qlge_get_mb_sts(qdev, mbcp);
425955315b0SBenjamin Poirier 		return status;
426955315b0SBenjamin Poirier 
427955315b0SBenjamin Poirier 		/* We are being asked by firmware to accept
428955315b0SBenjamin Poirier 		 * a change to the port.  This is only
429955315b0SBenjamin Poirier 		 * a change to max frame sizes (Tx/Rx), pause
430955315b0SBenjamin Poirier 		 * parameters, or loopback mode.
431955315b0SBenjamin Poirier 		 */
432955315b0SBenjamin Poirier 	case AEN_IDC_REQ:
433f8c047beSCoiby Xu 		status = qlge_idc_req_aen(qdev);
434955315b0SBenjamin Poirier 		break;
435955315b0SBenjamin Poirier 
436955315b0SBenjamin Poirier 		/* Process and inbound IDC event.
437955315b0SBenjamin Poirier 		 * This will happen when we're trying to
438955315b0SBenjamin Poirier 		 * change tx/rx max frame size, change pause
439955315b0SBenjamin Poirier 		 * parameters or loopback mode.
440955315b0SBenjamin Poirier 		 */
441955315b0SBenjamin Poirier 	case AEN_IDC_CMPLT:
442955315b0SBenjamin Poirier 	case AEN_IDC_EXT:
443f8c047beSCoiby Xu 		status = qlge_idc_cmplt_aen(qdev);
444955315b0SBenjamin Poirier 		break;
445955315b0SBenjamin Poirier 
446955315b0SBenjamin Poirier 	case AEN_LINK_UP:
447f8c047beSCoiby Xu 		qlge_link_up(qdev, mbcp);
448955315b0SBenjamin Poirier 		break;
449955315b0SBenjamin Poirier 
450955315b0SBenjamin Poirier 	case AEN_LINK_DOWN:
451f8c047beSCoiby Xu 		qlge_link_down(qdev, mbcp);
452955315b0SBenjamin Poirier 		break;
453955315b0SBenjamin Poirier 
454955315b0SBenjamin Poirier 	case AEN_FW_INIT_DONE:
455955315b0SBenjamin Poirier 		/* If we're in process on executing the firmware,
456955315b0SBenjamin Poirier 		 * then convert the status to normal mailbox status.
457955315b0SBenjamin Poirier 		 */
458955315b0SBenjamin Poirier 		if (mbcp->mbox_in[0] == MB_CMD_EX_FW) {
459955315b0SBenjamin Poirier 			mbcp->out_count = orig_count;
460f8c047beSCoiby Xu 			status = qlge_get_mb_sts(qdev, mbcp);
461955315b0SBenjamin Poirier 			mbcp->mbox_out[0] = MB_CMD_STS_GOOD;
462955315b0SBenjamin Poirier 			return status;
463955315b0SBenjamin Poirier 		}
464f8c047beSCoiby Xu 		qlge_init_fw_done(qdev, mbcp);
465955315b0SBenjamin Poirier 		break;
466955315b0SBenjamin Poirier 
467955315b0SBenjamin Poirier 	case AEN_AEN_SFP_IN:
468f8c047beSCoiby Xu 		qlge_sfp_in(qdev, mbcp);
469955315b0SBenjamin Poirier 		break;
470955315b0SBenjamin Poirier 
471955315b0SBenjamin Poirier 	case AEN_AEN_SFP_OUT:
472f8c047beSCoiby Xu 		qlge_sfp_out(qdev, mbcp);
473955315b0SBenjamin Poirier 		break;
474955315b0SBenjamin Poirier 
475955315b0SBenjamin Poirier 		/* This event can arrive at boot time or after an
476955315b0SBenjamin Poirier 		 * MPI reset if the firmware failed to initialize.
477955315b0SBenjamin Poirier 		 */
478955315b0SBenjamin Poirier 	case AEN_FW_INIT_FAIL:
479955315b0SBenjamin Poirier 		/* If we're in process on executing the firmware,
480955315b0SBenjamin Poirier 		 * then convert the status to normal mailbox status.
481955315b0SBenjamin Poirier 		 */
482955315b0SBenjamin Poirier 		if (mbcp->mbox_in[0] == MB_CMD_EX_FW) {
483955315b0SBenjamin Poirier 			mbcp->out_count = orig_count;
484f8c047beSCoiby Xu 			status = qlge_get_mb_sts(qdev, mbcp);
485955315b0SBenjamin Poirier 			mbcp->mbox_out[0] = MB_CMD_STS_ERR;
486955315b0SBenjamin Poirier 			return status;
487955315b0SBenjamin Poirier 		}
488955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
489955315b0SBenjamin Poirier 			  "Firmware initialization failed.\n");
490955315b0SBenjamin Poirier 		status = -EIO;
491f8c047beSCoiby Xu 		qlge_queue_fw_error(qdev);
492955315b0SBenjamin Poirier 		break;
493955315b0SBenjamin Poirier 
494955315b0SBenjamin Poirier 	case AEN_SYS_ERR:
495955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "System Error.\n");
496f8c047beSCoiby Xu 		qlge_queue_fw_error(qdev);
497955315b0SBenjamin Poirier 		status = -EIO;
498955315b0SBenjamin Poirier 		break;
499955315b0SBenjamin Poirier 
500955315b0SBenjamin Poirier 	case AEN_AEN_LOST:
501f8c047beSCoiby Xu 		qlge_aen_lost(qdev, mbcp);
502955315b0SBenjamin Poirier 		break;
503955315b0SBenjamin Poirier 
504955315b0SBenjamin Poirier 	case AEN_DCBX_CHG:
505955315b0SBenjamin Poirier 		/* Need to support AEN 8110 */
506955315b0SBenjamin Poirier 		break;
507955315b0SBenjamin Poirier 	default:
508955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
509955315b0SBenjamin Poirier 			  "Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
510955315b0SBenjamin Poirier 		/* Clear the MPI firmware status. */
511955315b0SBenjamin Poirier 	}
512955315b0SBenjamin Poirier end:
513f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
514955315b0SBenjamin Poirier 	/* Restore the original mailbox count to
515955315b0SBenjamin Poirier 	 * what the caller asked for.  This can get
516955315b0SBenjamin Poirier 	 * changed when a mailbox command is waiting
517955315b0SBenjamin Poirier 	 * for a response and an AEN arrives and
518955315b0SBenjamin Poirier 	 * is handled.
5191113c90cSCoiby Xu 	 */
520955315b0SBenjamin Poirier 	mbcp->out_count = orig_count;
521955315b0SBenjamin Poirier 	return status;
522955315b0SBenjamin Poirier }
523955315b0SBenjamin Poirier 
524955315b0SBenjamin Poirier /* Execute a single mailbox command.
525955315b0SBenjamin Poirier  * mbcp is a pointer to an array of u32.  Each
526955315b0SBenjamin Poirier  * element in the array contains the value for it's
527955315b0SBenjamin Poirier  * respective mailbox register.
528955315b0SBenjamin Poirier  */
qlge_mailbox_command(struct qlge_adapter * qdev,struct mbox_params * mbcp)529f8c047beSCoiby Xu static int qlge_mailbox_command(struct qlge_adapter *qdev, struct mbox_params *mbcp)
530955315b0SBenjamin Poirier {
531955315b0SBenjamin Poirier 	int status;
532955315b0SBenjamin Poirier 	unsigned long count;
533955315b0SBenjamin Poirier 
534955315b0SBenjamin Poirier 	mutex_lock(&qdev->mpi_mutex);
535955315b0SBenjamin Poirier 
536955315b0SBenjamin Poirier 	/* Begin polled mode for MPI */
537f8c047beSCoiby Xu 	qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
538955315b0SBenjamin Poirier 
539955315b0SBenjamin Poirier 	/* Load the mailbox registers and wake up MPI RISC. */
540f8c047beSCoiby Xu 	status = qlge_exec_mb_cmd(qdev, mbcp);
541955315b0SBenjamin Poirier 	if (status)
542955315b0SBenjamin Poirier 		goto end;
543955315b0SBenjamin Poirier 
544955315b0SBenjamin Poirier 	/* If we're generating a system error, then there's nothing
545955315b0SBenjamin Poirier 	 * to wait for.
546955315b0SBenjamin Poirier 	 */
547955315b0SBenjamin Poirier 	if (mbcp->mbox_in[0] == MB_CMD_MAKE_SYS_ERR)
548955315b0SBenjamin Poirier 		goto end;
549955315b0SBenjamin Poirier 
550955315b0SBenjamin Poirier 	/* Wait for the command to complete. We loop
551955315b0SBenjamin Poirier 	 * here because some AEN might arrive while
552955315b0SBenjamin Poirier 	 * we're waiting for the mailbox command to
553955315b0SBenjamin Poirier 	 * complete. If more than 5 seconds expire we can
5541113c90cSCoiby Xu 	 * assume something is wrong.
5551113c90cSCoiby Xu 	 */
556955315b0SBenjamin Poirier 	count = jiffies + HZ * MAILBOX_TIMEOUT;
557955315b0SBenjamin Poirier 	do {
558955315b0SBenjamin Poirier 		/* Wait for the interrupt to come in. */
559f8c047beSCoiby Xu 		status = qlge_wait_mbx_cmd_cmplt(qdev);
560955315b0SBenjamin Poirier 		if (status)
561955315b0SBenjamin Poirier 			continue;
562955315b0SBenjamin Poirier 
563955315b0SBenjamin Poirier 		/* Process the event.  If it's an AEN, it
564955315b0SBenjamin Poirier 		 * will be handled in-line or a worker
565955315b0SBenjamin Poirier 		 * will be spawned. If it's our completion
566955315b0SBenjamin Poirier 		 * we will catch it below.
567955315b0SBenjamin Poirier 		 */
568f8c047beSCoiby Xu 		status = qlge_mpi_handler(qdev, mbcp);
569955315b0SBenjamin Poirier 		if (status)
570955315b0SBenjamin Poirier 			goto end;
571955315b0SBenjamin Poirier 
572955315b0SBenjamin Poirier 		/* It's either the completion for our mailbox
573955315b0SBenjamin Poirier 		 * command complete or an AEN.  If it's our
574955315b0SBenjamin Poirier 		 * completion then get out.
575955315b0SBenjamin Poirier 		 */
576955315b0SBenjamin Poirier 		if (((mbcp->mbox_out[0] & 0x0000f000) ==
577955315b0SBenjamin Poirier 		     MB_CMD_STS_GOOD) ||
578955315b0SBenjamin Poirier 		    ((mbcp->mbox_out[0] & 0x0000f000) ==
579955315b0SBenjamin Poirier 		     MB_CMD_STS_INTRMDT))
580955315b0SBenjamin Poirier 			goto done;
581955315b0SBenjamin Poirier 	} while (time_before(jiffies, count));
582955315b0SBenjamin Poirier 
583955315b0SBenjamin Poirier 	netif_err(qdev, drv, qdev->ndev,
584955315b0SBenjamin Poirier 		  "Timed out waiting for mailbox complete.\n");
585955315b0SBenjamin Poirier 	status = -ETIMEDOUT;
586955315b0SBenjamin Poirier 	goto end;
587955315b0SBenjamin Poirier 
588955315b0SBenjamin Poirier done:
589955315b0SBenjamin Poirier 
590955315b0SBenjamin Poirier 	/* Now we can clear the interrupt condition
591955315b0SBenjamin Poirier 	 * and look at our status.
592955315b0SBenjamin Poirier 	 */
593f8c047beSCoiby Xu 	qlge_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
594955315b0SBenjamin Poirier 
595955315b0SBenjamin Poirier 	if (((mbcp->mbox_out[0] & 0x0000f000) !=
596955315b0SBenjamin Poirier 	     MB_CMD_STS_GOOD) &&
597955315b0SBenjamin Poirier 	    ((mbcp->mbox_out[0] & 0x0000f000) !=
598955315b0SBenjamin Poirier 	     MB_CMD_STS_INTRMDT)) {
599955315b0SBenjamin Poirier 		status = -EIO;
600955315b0SBenjamin Poirier 	}
601955315b0SBenjamin Poirier end:
602955315b0SBenjamin Poirier 	/* End polled mode for MPI */
603f8c047beSCoiby Xu 	qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
604955315b0SBenjamin Poirier 	mutex_unlock(&qdev->mpi_mutex);
605955315b0SBenjamin Poirier 	return status;
606955315b0SBenjamin Poirier }
607955315b0SBenjamin Poirier 
608955315b0SBenjamin Poirier /* Get MPI firmware version. This will be used for
609955315b0SBenjamin Poirier  * driver banner and for ethtool info.
610955315b0SBenjamin Poirier  * Returns zero on success.
611955315b0SBenjamin Poirier  */
qlge_mb_about_fw(struct qlge_adapter * qdev)612f8c047beSCoiby Xu int qlge_mb_about_fw(struct qlge_adapter *qdev)
613955315b0SBenjamin Poirier {
614955315b0SBenjamin Poirier 	struct mbox_params mbc;
615955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
616955315b0SBenjamin Poirier 	int status = 0;
617955315b0SBenjamin Poirier 
618955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
619955315b0SBenjamin Poirier 
620955315b0SBenjamin Poirier 	mbcp->in_count = 1;
621955315b0SBenjamin Poirier 	mbcp->out_count = 3;
622955315b0SBenjamin Poirier 
623955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_ABOUT_FW;
624955315b0SBenjamin Poirier 
625f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
626955315b0SBenjamin Poirier 	if (status)
627955315b0SBenjamin Poirier 		return status;
628955315b0SBenjamin Poirier 
629955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
630955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
631955315b0SBenjamin Poirier 			  "Failed about firmware command\n");
632955315b0SBenjamin Poirier 		status = -EIO;
633955315b0SBenjamin Poirier 	}
634955315b0SBenjamin Poirier 
635955315b0SBenjamin Poirier 	/* Store the firmware version */
636955315b0SBenjamin Poirier 	qdev->fw_rev_id = mbcp->mbox_out[1];
637955315b0SBenjamin Poirier 
638955315b0SBenjamin Poirier 	return status;
639955315b0SBenjamin Poirier }
640955315b0SBenjamin Poirier 
641955315b0SBenjamin Poirier /* Get functional state for MPI firmware.
642955315b0SBenjamin Poirier  * Returns zero on success.
643955315b0SBenjamin Poirier  */
qlge_mb_get_fw_state(struct qlge_adapter * qdev)644f8c047beSCoiby Xu int qlge_mb_get_fw_state(struct qlge_adapter *qdev)
645955315b0SBenjamin Poirier {
646955315b0SBenjamin Poirier 	struct mbox_params mbc;
647955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
648955315b0SBenjamin Poirier 	int status = 0;
649955315b0SBenjamin Poirier 
650955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
651955315b0SBenjamin Poirier 
652955315b0SBenjamin Poirier 	mbcp->in_count = 1;
653955315b0SBenjamin Poirier 	mbcp->out_count = 2;
654955315b0SBenjamin Poirier 
655955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_GET_FW_STATE;
656955315b0SBenjamin Poirier 
657f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
658955315b0SBenjamin Poirier 	if (status)
659955315b0SBenjamin Poirier 		return status;
660955315b0SBenjamin Poirier 
661955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
662955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
663955315b0SBenjamin Poirier 			  "Failed Get Firmware State.\n");
664955315b0SBenjamin Poirier 		status = -EIO;
665955315b0SBenjamin Poirier 	}
666955315b0SBenjamin Poirier 
667955315b0SBenjamin Poirier 	/* If bit zero is set in mbx 1 then the firmware is
668955315b0SBenjamin Poirier 	 * running, but not initialized.  This should never
669955315b0SBenjamin Poirier 	 * happen.
670955315b0SBenjamin Poirier 	 */
671955315b0SBenjamin Poirier 	if (mbcp->mbox_out[1] & 1) {
672955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
673955315b0SBenjamin Poirier 			  "Firmware waiting for initialization.\n");
674955315b0SBenjamin Poirier 		status = -EIO;
675955315b0SBenjamin Poirier 	}
676955315b0SBenjamin Poirier 
677955315b0SBenjamin Poirier 	return status;
678955315b0SBenjamin Poirier }
679955315b0SBenjamin Poirier 
680955315b0SBenjamin Poirier /* Send and ACK mailbox command to the firmware to
681955315b0SBenjamin Poirier  * let it continue with the change.
682955315b0SBenjamin Poirier  */
qlge_mb_idc_ack(struct qlge_adapter * qdev)683f8c047beSCoiby Xu static int qlge_mb_idc_ack(struct qlge_adapter *qdev)
684955315b0SBenjamin Poirier {
685955315b0SBenjamin Poirier 	struct mbox_params mbc;
686955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
687955315b0SBenjamin Poirier 	int status = 0;
688955315b0SBenjamin Poirier 
689955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
690955315b0SBenjamin Poirier 
691955315b0SBenjamin Poirier 	mbcp->in_count = 5;
692955315b0SBenjamin Poirier 	mbcp->out_count = 1;
693955315b0SBenjamin Poirier 
694955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_IDC_ACK;
695955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = qdev->idc_mbc.mbox_out[1];
696955315b0SBenjamin Poirier 	mbcp->mbox_in[2] = qdev->idc_mbc.mbox_out[2];
697955315b0SBenjamin Poirier 	mbcp->mbox_in[3] = qdev->idc_mbc.mbox_out[3];
698955315b0SBenjamin Poirier 	mbcp->mbox_in[4] = qdev->idc_mbc.mbox_out[4];
699955315b0SBenjamin Poirier 
700f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
701955315b0SBenjamin Poirier 	if (status)
702955315b0SBenjamin Poirier 		return status;
703955315b0SBenjamin Poirier 
704955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
705955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Failed IDC ACK send.\n");
706955315b0SBenjamin Poirier 		status = -EIO;
707955315b0SBenjamin Poirier 	}
708955315b0SBenjamin Poirier 	return status;
709955315b0SBenjamin Poirier }
710955315b0SBenjamin Poirier 
711955315b0SBenjamin Poirier /* Get link settings and maximum frame size settings
712955315b0SBenjamin Poirier  * for the current port.
713955315b0SBenjamin Poirier  * Most likely will block.
714955315b0SBenjamin Poirier  */
qlge_mb_set_port_cfg(struct qlge_adapter * qdev)715f8c047beSCoiby Xu int qlge_mb_set_port_cfg(struct qlge_adapter *qdev)
716955315b0SBenjamin Poirier {
717955315b0SBenjamin Poirier 	struct mbox_params mbc;
718955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
719955315b0SBenjamin Poirier 	int status = 0;
720955315b0SBenjamin Poirier 
721955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
722955315b0SBenjamin Poirier 
723955315b0SBenjamin Poirier 	mbcp->in_count = 3;
724955315b0SBenjamin Poirier 	mbcp->out_count = 1;
725955315b0SBenjamin Poirier 
726955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_SET_PORT_CFG;
727955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = qdev->link_config;
728955315b0SBenjamin Poirier 	mbcp->mbox_in[2] = qdev->max_frame_size;
729955315b0SBenjamin Poirier 
730f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
731955315b0SBenjamin Poirier 	if (status)
732955315b0SBenjamin Poirier 		return status;
733955315b0SBenjamin Poirier 
734955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) {
735955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
736955315b0SBenjamin Poirier 			  "Port Config sent, wait for IDC.\n");
737955315b0SBenjamin Poirier 	} else	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
738955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
739955315b0SBenjamin Poirier 			  "Failed Set Port Configuration.\n");
740955315b0SBenjamin Poirier 		status = -EIO;
741955315b0SBenjamin Poirier 	}
742955315b0SBenjamin Poirier 	return status;
743955315b0SBenjamin Poirier }
744955315b0SBenjamin Poirier 
qlge_mb_dump_ram(struct qlge_adapter * qdev,u64 req_dma,u32 addr,u32 size)745f8c047beSCoiby Xu static int qlge_mb_dump_ram(struct qlge_adapter *qdev, u64 req_dma, u32 addr,
746955315b0SBenjamin Poirier 			    u32 size)
747955315b0SBenjamin Poirier {
748955315b0SBenjamin Poirier 	int status = 0;
749955315b0SBenjamin Poirier 	struct mbox_params mbc;
750955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
751955315b0SBenjamin Poirier 
752955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
753955315b0SBenjamin Poirier 
754955315b0SBenjamin Poirier 	mbcp->in_count = 9;
755955315b0SBenjamin Poirier 	mbcp->out_count = 1;
756955315b0SBenjamin Poirier 
757955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM;
758955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = LSW(addr);
759955315b0SBenjamin Poirier 	mbcp->mbox_in[2] = MSW(req_dma);
760955315b0SBenjamin Poirier 	mbcp->mbox_in[3] = LSW(req_dma);
761955315b0SBenjamin Poirier 	mbcp->mbox_in[4] = MSW(size);
762955315b0SBenjamin Poirier 	mbcp->mbox_in[5] = LSW(size);
763955315b0SBenjamin Poirier 	mbcp->mbox_in[6] = MSW(MSD(req_dma));
764955315b0SBenjamin Poirier 	mbcp->mbox_in[7] = LSW(MSD(req_dma));
765955315b0SBenjamin Poirier 	mbcp->mbox_in[8] = MSW(addr);
766955315b0SBenjamin Poirier 
767f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
768955315b0SBenjamin Poirier 	if (status)
769955315b0SBenjamin Poirier 		return status;
770955315b0SBenjamin Poirier 
771955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
772955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Failed to dump risc RAM.\n");
773955315b0SBenjamin Poirier 		status = -EIO;
774955315b0SBenjamin Poirier 	}
775955315b0SBenjamin Poirier 	return status;
776955315b0SBenjamin Poirier }
777955315b0SBenjamin Poirier 
778955315b0SBenjamin Poirier /* Issue a mailbox command to dump RISC RAM. */
qlge_dump_risc_ram_area(struct qlge_adapter * qdev,void * buf,u32 ram_addr,int word_count)779f8c047beSCoiby Xu int qlge_dump_risc_ram_area(struct qlge_adapter *qdev, void *buf,
780955315b0SBenjamin Poirier 			    u32 ram_addr, int word_count)
781955315b0SBenjamin Poirier {
782955315b0SBenjamin Poirier 	int status;
783955315b0SBenjamin Poirier 	char *my_buf;
784955315b0SBenjamin Poirier 	dma_addr_t buf_dma;
785955315b0SBenjamin Poirier 
786ff98ca15SSuraj Upadhyay 	my_buf = dma_alloc_coherent(&qdev->pdev->dev,
787ff98ca15SSuraj Upadhyay 				    word_count * sizeof(u32), &buf_dma,
788ff98ca15SSuraj Upadhyay 				    GFP_ATOMIC);
789955315b0SBenjamin Poirier 	if (!my_buf)
790955315b0SBenjamin Poirier 		return -EIO;
791955315b0SBenjamin Poirier 
792f8c047beSCoiby Xu 	status = qlge_mb_dump_ram(qdev, buf_dma, ram_addr, word_count);
793955315b0SBenjamin Poirier 	if (!status)
794955315b0SBenjamin Poirier 		memcpy(buf, my_buf, word_count * sizeof(u32));
795955315b0SBenjamin Poirier 
796ff98ca15SSuraj Upadhyay 	dma_free_coherent(&qdev->pdev->dev, word_count * sizeof(u32), my_buf,
797955315b0SBenjamin Poirier 			  buf_dma);
798955315b0SBenjamin Poirier 	return status;
799955315b0SBenjamin Poirier }
800955315b0SBenjamin Poirier 
801955315b0SBenjamin Poirier /* Get link settings and maximum frame size settings
802955315b0SBenjamin Poirier  * for the current port.
803955315b0SBenjamin Poirier  * Most likely will block.
804955315b0SBenjamin Poirier  */
qlge_mb_get_port_cfg(struct qlge_adapter * qdev)805f8c047beSCoiby Xu int qlge_mb_get_port_cfg(struct qlge_adapter *qdev)
806955315b0SBenjamin Poirier {
807955315b0SBenjamin Poirier 	struct mbox_params mbc;
808955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
809955315b0SBenjamin Poirier 	int status = 0;
810955315b0SBenjamin Poirier 
811955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
812955315b0SBenjamin Poirier 
813955315b0SBenjamin Poirier 	mbcp->in_count = 1;
814955315b0SBenjamin Poirier 	mbcp->out_count = 3;
815955315b0SBenjamin Poirier 
816955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_GET_PORT_CFG;
817955315b0SBenjamin Poirier 
818f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
819955315b0SBenjamin Poirier 	if (status)
820955315b0SBenjamin Poirier 		return status;
821955315b0SBenjamin Poirier 
822955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
823955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
824955315b0SBenjamin Poirier 			  "Failed Get Port Configuration.\n");
825955315b0SBenjamin Poirier 		status = -EIO;
826955315b0SBenjamin Poirier 	} else	{
827955315b0SBenjamin Poirier 		netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
828955315b0SBenjamin Poirier 			     "Passed Get Port Configuration.\n");
829955315b0SBenjamin Poirier 		qdev->link_config = mbcp->mbox_out[1];
830955315b0SBenjamin Poirier 		qdev->max_frame_size = mbcp->mbox_out[2];
831955315b0SBenjamin Poirier 	}
832955315b0SBenjamin Poirier 	return status;
833955315b0SBenjamin Poirier }
834955315b0SBenjamin Poirier 
qlge_mb_wol_mode(struct qlge_adapter * qdev,u32 wol)835f8c047beSCoiby Xu int qlge_mb_wol_mode(struct qlge_adapter *qdev, u32 wol)
836955315b0SBenjamin Poirier {
837955315b0SBenjamin Poirier 	struct mbox_params mbc;
838955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
839955315b0SBenjamin Poirier 	int status;
840955315b0SBenjamin Poirier 
841955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
842955315b0SBenjamin Poirier 
843955315b0SBenjamin Poirier 	mbcp->in_count = 2;
844955315b0SBenjamin Poirier 	mbcp->out_count = 1;
845955315b0SBenjamin Poirier 
846955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_SET_WOL_MODE;
847955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = wol;
848955315b0SBenjamin Poirier 
849f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
850955315b0SBenjamin Poirier 	if (status)
851955315b0SBenjamin Poirier 		return status;
852955315b0SBenjamin Poirier 
853955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
854955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n");
855955315b0SBenjamin Poirier 		status = -EIO;
856955315b0SBenjamin Poirier 	}
857955315b0SBenjamin Poirier 	return status;
858955315b0SBenjamin Poirier }
859955315b0SBenjamin Poirier 
qlge_mb_wol_set_magic(struct qlge_adapter * qdev,u32 enable_wol)860f8c047beSCoiby Xu int qlge_mb_wol_set_magic(struct qlge_adapter *qdev, u32 enable_wol)
861955315b0SBenjamin Poirier {
862955315b0SBenjamin Poirier 	struct mbox_params mbc;
863955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
864955315b0SBenjamin Poirier 	int status;
865*e7fd1a5aSJakub Kicinski 	const u8 *addr = qdev->ndev->dev_addr;
866955315b0SBenjamin Poirier 
867955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
868955315b0SBenjamin Poirier 
869955315b0SBenjamin Poirier 	mbcp->in_count = 8;
870955315b0SBenjamin Poirier 	mbcp->out_count = 1;
871955315b0SBenjamin Poirier 
872955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_SET_WOL_MAGIC;
873955315b0SBenjamin Poirier 	if (enable_wol) {
874955315b0SBenjamin Poirier 		mbcp->mbox_in[1] = (u32)addr[0];
875955315b0SBenjamin Poirier 		mbcp->mbox_in[2] = (u32)addr[1];
876955315b0SBenjamin Poirier 		mbcp->mbox_in[3] = (u32)addr[2];
877955315b0SBenjamin Poirier 		mbcp->mbox_in[4] = (u32)addr[3];
878955315b0SBenjamin Poirier 		mbcp->mbox_in[5] = (u32)addr[4];
879955315b0SBenjamin Poirier 		mbcp->mbox_in[6] = (u32)addr[5];
880955315b0SBenjamin Poirier 		mbcp->mbox_in[7] = 0;
881955315b0SBenjamin Poirier 	} else {
882955315b0SBenjamin Poirier 		mbcp->mbox_in[1] = 0;
883955315b0SBenjamin Poirier 		mbcp->mbox_in[2] = 1;
884955315b0SBenjamin Poirier 		mbcp->mbox_in[3] = 1;
885955315b0SBenjamin Poirier 		mbcp->mbox_in[4] = 1;
886955315b0SBenjamin Poirier 		mbcp->mbox_in[5] = 1;
887955315b0SBenjamin Poirier 		mbcp->mbox_in[6] = 1;
888955315b0SBenjamin Poirier 		mbcp->mbox_in[7] = 0;
889955315b0SBenjamin Poirier 	}
890955315b0SBenjamin Poirier 
891f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
892955315b0SBenjamin Poirier 	if (status)
893955315b0SBenjamin Poirier 		return status;
894955315b0SBenjamin Poirier 
895955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
896955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Failed to set WOL mode.\n");
897955315b0SBenjamin Poirier 		status = -EIO;
898955315b0SBenjamin Poirier 	}
899955315b0SBenjamin Poirier 	return status;
900955315b0SBenjamin Poirier }
901955315b0SBenjamin Poirier 
902955315b0SBenjamin Poirier /* IDC - Inter Device Communication...
903955315b0SBenjamin Poirier  * Some firmware commands require consent of adjacent FCOE
904955315b0SBenjamin Poirier  * function.  This function waits for the OK, or a
905955315b0SBenjamin Poirier  * counter-request for a little more time.i
906955315b0SBenjamin Poirier  * The firmware will complete the request if the other
907955315b0SBenjamin Poirier  * function doesn't respond.
908955315b0SBenjamin Poirier  */
qlge_idc_wait(struct qlge_adapter * qdev)909f8c047beSCoiby Xu static int qlge_idc_wait(struct qlge_adapter *qdev)
910955315b0SBenjamin Poirier {
911955315b0SBenjamin Poirier 	int status = -ETIMEDOUT;
912955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &qdev->idc_mbc;
91345170f10SSuraj Upadhyay 	long wait_time;
9147d508880SCarlos Henrique Lima Melara 
91545170f10SSuraj Upadhyay 	for (wait_time = 1 * HZ; wait_time;) {
916955315b0SBenjamin Poirier 		/* Wait here for the command to complete
917955315b0SBenjamin Poirier 		 * via the IDC process.
918955315b0SBenjamin Poirier 		 */
919955315b0SBenjamin Poirier 		wait_time =
920955315b0SBenjamin Poirier 			wait_for_completion_timeout(&qdev->ide_completion,
921955315b0SBenjamin Poirier 						    wait_time);
922955315b0SBenjamin Poirier 		if (!wait_time) {
923955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev, "IDC Timeout.\n");
924955315b0SBenjamin Poirier 			break;
925955315b0SBenjamin Poirier 		}
926955315b0SBenjamin Poirier 		/* Now examine the response from the IDC process.
927955315b0SBenjamin Poirier 		 * We might have a good completion or a request for
928955315b0SBenjamin Poirier 		 * more wait time.
929955315b0SBenjamin Poirier 		 */
930955315b0SBenjamin Poirier 		if (mbcp->mbox_out[0] == AEN_IDC_EXT) {
931955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev,
932955315b0SBenjamin Poirier 				  "IDC Time Extension from function.\n");
933955315b0SBenjamin Poirier 			wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f;
934955315b0SBenjamin Poirier 		} else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) {
935955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev, "IDC Success.\n");
936955315b0SBenjamin Poirier 			status = 0;
937955315b0SBenjamin Poirier 			break;
938955315b0SBenjamin Poirier 		} else {
939955315b0SBenjamin Poirier 			netif_err(qdev, drv, qdev->ndev,
940955315b0SBenjamin Poirier 				  "IDC: Invalid State 0x%.04x.\n",
941955315b0SBenjamin Poirier 				  mbcp->mbox_out[0]);
942955315b0SBenjamin Poirier 			status = -EIO;
943955315b0SBenjamin Poirier 			break;
944955315b0SBenjamin Poirier 		}
94545170f10SSuraj Upadhyay 	}
946955315b0SBenjamin Poirier 
947955315b0SBenjamin Poirier 	return status;
948955315b0SBenjamin Poirier }
949955315b0SBenjamin Poirier 
qlge_mb_set_led_cfg(struct qlge_adapter * qdev,u32 led_config)950f8c047beSCoiby Xu int qlge_mb_set_led_cfg(struct qlge_adapter *qdev, u32 led_config)
951955315b0SBenjamin Poirier {
952955315b0SBenjamin Poirier 	struct mbox_params mbc;
953955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
954955315b0SBenjamin Poirier 	int status;
955955315b0SBenjamin Poirier 
956955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
957955315b0SBenjamin Poirier 
958955315b0SBenjamin Poirier 	mbcp->in_count = 2;
959955315b0SBenjamin Poirier 	mbcp->out_count = 1;
960955315b0SBenjamin Poirier 
961955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_SET_LED_CFG;
962955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = led_config;
963955315b0SBenjamin Poirier 
964f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
965955315b0SBenjamin Poirier 	if (status)
966955315b0SBenjamin Poirier 		return status;
967955315b0SBenjamin Poirier 
968955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
969955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
970955315b0SBenjamin Poirier 			  "Failed to set LED Configuration.\n");
971955315b0SBenjamin Poirier 		status = -EIO;
972955315b0SBenjamin Poirier 	}
973955315b0SBenjamin Poirier 
974955315b0SBenjamin Poirier 	return status;
975955315b0SBenjamin Poirier }
976955315b0SBenjamin Poirier 
qlge_mb_get_led_cfg(struct qlge_adapter * qdev)977f8c047beSCoiby Xu int qlge_mb_get_led_cfg(struct qlge_adapter *qdev)
978955315b0SBenjamin Poirier {
979955315b0SBenjamin Poirier 	struct mbox_params mbc;
980955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
981955315b0SBenjamin Poirier 	int status;
982955315b0SBenjamin Poirier 
983955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
984955315b0SBenjamin Poirier 
985955315b0SBenjamin Poirier 	mbcp->in_count = 1;
986955315b0SBenjamin Poirier 	mbcp->out_count = 2;
987955315b0SBenjamin Poirier 
988955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_GET_LED_CFG;
989955315b0SBenjamin Poirier 
990f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
991955315b0SBenjamin Poirier 	if (status)
992955315b0SBenjamin Poirier 		return status;
993955315b0SBenjamin Poirier 
994955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
995955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
996955315b0SBenjamin Poirier 			  "Failed to get LED Configuration.\n");
997955315b0SBenjamin Poirier 		status = -EIO;
998608a911bSSebastian Fuentes 	} else {
999955315b0SBenjamin Poirier 		qdev->led_config = mbcp->mbox_out[1];
1000608a911bSSebastian Fuentes 	}
1001955315b0SBenjamin Poirier 	return status;
1002955315b0SBenjamin Poirier }
1003955315b0SBenjamin Poirier 
qlge_mb_set_mgmnt_traffic_ctl(struct qlge_adapter * qdev,u32 control)1004f8c047beSCoiby Xu int qlge_mb_set_mgmnt_traffic_ctl(struct qlge_adapter *qdev, u32 control)
1005955315b0SBenjamin Poirier {
1006955315b0SBenjamin Poirier 	struct mbox_params mbc;
1007955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
1008955315b0SBenjamin Poirier 	int status;
1009955315b0SBenjamin Poirier 
1010955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
1011955315b0SBenjamin Poirier 
1012955315b0SBenjamin Poirier 	mbcp->in_count = 1;
1013955315b0SBenjamin Poirier 	mbcp->out_count = 2;
1014955315b0SBenjamin Poirier 
1015955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_SET_MGMNT_TFK_CTL;
1016955315b0SBenjamin Poirier 	mbcp->mbox_in[1] = control;
1017955315b0SBenjamin Poirier 
1018f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
1019955315b0SBenjamin Poirier 	if (status)
1020955315b0SBenjamin Poirier 		return status;
1021955315b0SBenjamin Poirier 
1022955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD)
1023955315b0SBenjamin Poirier 		return status;
1024955315b0SBenjamin Poirier 
1025955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
1026955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1027955315b0SBenjamin Poirier 			  "Command not supported by firmware.\n");
1028955315b0SBenjamin Poirier 		status = -EINVAL;
1029955315b0SBenjamin Poirier 	} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
1030955315b0SBenjamin Poirier 		/* This indicates that the firmware is
1031955315b0SBenjamin Poirier 		 * already in the state we are trying to
1032955315b0SBenjamin Poirier 		 * change it to.
1033955315b0SBenjamin Poirier 		 */
1034955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1035955315b0SBenjamin Poirier 			  "Command parameters make no change.\n");
1036955315b0SBenjamin Poirier 	}
1037955315b0SBenjamin Poirier 	return status;
1038955315b0SBenjamin Poirier }
1039955315b0SBenjamin Poirier 
1040955315b0SBenjamin Poirier /* Returns a negative error code or the mailbox command status. */
qlge_mb_get_mgmnt_traffic_ctl(struct qlge_adapter * qdev,u32 * control)1041f8c047beSCoiby Xu static int qlge_mb_get_mgmnt_traffic_ctl(struct qlge_adapter *qdev, u32 *control)
1042955315b0SBenjamin Poirier {
1043955315b0SBenjamin Poirier 	struct mbox_params mbc;
1044955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
1045955315b0SBenjamin Poirier 	int status;
1046955315b0SBenjamin Poirier 
1047955315b0SBenjamin Poirier 	memset(mbcp, 0, sizeof(struct mbox_params));
1048955315b0SBenjamin Poirier 	*control = 0;
1049955315b0SBenjamin Poirier 
1050955315b0SBenjamin Poirier 	mbcp->in_count = 1;
1051955315b0SBenjamin Poirier 	mbcp->out_count = 1;
1052955315b0SBenjamin Poirier 
1053955315b0SBenjamin Poirier 	mbcp->mbox_in[0] = MB_CMD_GET_MGMNT_TFK_CTL;
1054955315b0SBenjamin Poirier 
1055f8c047beSCoiby Xu 	status = qlge_mailbox_command(qdev, mbcp);
1056955315b0SBenjamin Poirier 	if (status)
1057955315b0SBenjamin Poirier 		return status;
1058955315b0SBenjamin Poirier 
1059955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD) {
1060955315b0SBenjamin Poirier 		*control = mbcp->mbox_in[1];
1061955315b0SBenjamin Poirier 		return status;
1062955315b0SBenjamin Poirier 	}
1063955315b0SBenjamin Poirier 
1064955315b0SBenjamin Poirier 	if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
1065955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1066955315b0SBenjamin Poirier 			  "Command not supported by firmware.\n");
1067955315b0SBenjamin Poirier 		status = -EINVAL;
1068955315b0SBenjamin Poirier 	} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
1069955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1070955315b0SBenjamin Poirier 			  "Failed to get MPI traffic control.\n");
1071955315b0SBenjamin Poirier 		status = -EIO;
1072955315b0SBenjamin Poirier 	}
1073955315b0SBenjamin Poirier 	return status;
1074955315b0SBenjamin Poirier }
1075955315b0SBenjamin Poirier 
qlge_wait_fifo_empty(struct qlge_adapter * qdev)1076f8c047beSCoiby Xu int qlge_wait_fifo_empty(struct qlge_adapter *qdev)
1077955315b0SBenjamin Poirier {
107845170f10SSuraj Upadhyay 	int count;
1079955315b0SBenjamin Poirier 	u32 mgmnt_fifo_empty;
1080955315b0SBenjamin Poirier 	u32 nic_fifo_empty;
1081955315b0SBenjamin Poirier 
108245170f10SSuraj Upadhyay 	for (count = 6; count; count--) {
1083f8c047beSCoiby Xu 		nic_fifo_empty = qlge_read32(qdev, STS) & STS_NFE;
1084f8c047beSCoiby Xu 		qlge_mb_get_mgmnt_traffic_ctl(qdev, &mgmnt_fifo_empty);
1085955315b0SBenjamin Poirier 		mgmnt_fifo_empty &= MB_GET_MPI_TFK_FIFO_EMPTY;
1086955315b0SBenjamin Poirier 		if (nic_fifo_empty && mgmnt_fifo_empty)
1087955315b0SBenjamin Poirier 			return 0;
1088955315b0SBenjamin Poirier 		msleep(100);
108945170f10SSuraj Upadhyay 	}
1090955315b0SBenjamin Poirier 	return -ETIMEDOUT;
1091955315b0SBenjamin Poirier }
1092955315b0SBenjamin Poirier 
1093955315b0SBenjamin Poirier /* API called in work thread context to set new TX/RX
1094955315b0SBenjamin Poirier  * maximum frame size values to match MTU.
1095955315b0SBenjamin Poirier  */
qlge_set_port_cfg(struct qlge_adapter * qdev)1096f8c047beSCoiby Xu static int qlge_set_port_cfg(struct qlge_adapter *qdev)
1097955315b0SBenjamin Poirier {
1098955315b0SBenjamin Poirier 	int status;
10997d508880SCarlos Henrique Lima Melara 
1100f8c047beSCoiby Xu 	status = qlge_mb_set_port_cfg(qdev);
1101955315b0SBenjamin Poirier 	if (status)
1102955315b0SBenjamin Poirier 		return status;
1103f8c047beSCoiby Xu 	status = qlge_idc_wait(qdev);
1104955315b0SBenjamin Poirier 	return status;
1105955315b0SBenjamin Poirier }
1106955315b0SBenjamin Poirier 
1107955315b0SBenjamin Poirier /* The following routines are worker threads that process
1108955315b0SBenjamin Poirier  * events that may sleep waiting for completion.
1109955315b0SBenjamin Poirier  */
1110955315b0SBenjamin Poirier 
1111955315b0SBenjamin Poirier /* This thread gets the maximum TX and RX frame size values
1112955315b0SBenjamin Poirier  * from the firmware and, if necessary, changes them to match
1113955315b0SBenjamin Poirier  * the MTU setting.
1114955315b0SBenjamin Poirier  */
qlge_mpi_port_cfg_work(struct work_struct * work)1115f8c047beSCoiby Xu void qlge_mpi_port_cfg_work(struct work_struct *work)
1116955315b0SBenjamin Poirier {
1117f8c047beSCoiby Xu 	struct qlge_adapter *qdev =
1118f8c047beSCoiby Xu 		container_of(work, struct qlge_adapter, mpi_port_cfg_work.work);
1119955315b0SBenjamin Poirier 	int status;
1120955315b0SBenjamin Poirier 
1121f8c047beSCoiby Xu 	status = qlge_mb_get_port_cfg(qdev);
1122955315b0SBenjamin Poirier 	if (status) {
1123955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1124955315b0SBenjamin Poirier 			  "Bug: Failed to get port config data.\n");
1125955315b0SBenjamin Poirier 		goto err;
1126955315b0SBenjamin Poirier 	}
1127955315b0SBenjamin Poirier 
1128955315b0SBenjamin Poirier 	if (qdev->link_config & CFG_JUMBO_FRAME_SIZE &&
11291b998958SScott Schafer 	    qdev->max_frame_size == CFG_DEFAULT_MAX_FRAME_SIZE)
1130955315b0SBenjamin Poirier 		goto end;
1131955315b0SBenjamin Poirier 
1132955315b0SBenjamin Poirier 	qdev->link_config |=	CFG_JUMBO_FRAME_SIZE;
1133955315b0SBenjamin Poirier 	qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE;
1134f8c047beSCoiby Xu 	status = qlge_set_port_cfg(qdev);
1135955315b0SBenjamin Poirier 	if (status) {
1136955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1137955315b0SBenjamin Poirier 			  "Bug: Failed to set port config data.\n");
1138955315b0SBenjamin Poirier 		goto err;
1139955315b0SBenjamin Poirier 	}
1140955315b0SBenjamin Poirier end:
1141955315b0SBenjamin Poirier 	clear_bit(QL_PORT_CFG, &qdev->flags);
1142955315b0SBenjamin Poirier 	return;
1143955315b0SBenjamin Poirier err:
1144f8c047beSCoiby Xu 	qlge_queue_fw_error(qdev);
1145955315b0SBenjamin Poirier 	goto end;
1146955315b0SBenjamin Poirier }
1147955315b0SBenjamin Poirier 
1148955315b0SBenjamin Poirier /* Process an inter-device request.  This is issues by
1149955315b0SBenjamin Poirier  * the firmware in response to another function requesting
1150955315b0SBenjamin Poirier  * a change to the port. We set a flag to indicate a change
1151955315b0SBenjamin Poirier  * has been made and then send a mailbox command ACKing
1152955315b0SBenjamin Poirier  * the change request.
1153955315b0SBenjamin Poirier  */
qlge_mpi_idc_work(struct work_struct * work)1154f8c047beSCoiby Xu void qlge_mpi_idc_work(struct work_struct *work)
1155955315b0SBenjamin Poirier {
1156f8c047beSCoiby Xu 	struct qlge_adapter *qdev =
1157f8c047beSCoiby Xu 		container_of(work, struct qlge_adapter, mpi_idc_work.work);
1158955315b0SBenjamin Poirier 	int status;
1159955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &qdev->idc_mbc;
1160955315b0SBenjamin Poirier 	u32 aen;
1161955315b0SBenjamin Poirier 	int timeout;
1162955315b0SBenjamin Poirier 
1163955315b0SBenjamin Poirier 	aen = mbcp->mbox_out[1] >> 16;
1164955315b0SBenjamin Poirier 	timeout = (mbcp->mbox_out[1] >> 8) & 0xf;
1165955315b0SBenjamin Poirier 
1166955315b0SBenjamin Poirier 	switch (aen) {
1167955315b0SBenjamin Poirier 	default:
1168955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev,
1169955315b0SBenjamin Poirier 			  "Bug: Unhandled IDC action.\n");
1170955315b0SBenjamin Poirier 		break;
1171955315b0SBenjamin Poirier 	case MB_CMD_PORT_RESET:
1172955315b0SBenjamin Poirier 	case MB_CMD_STOP_FW:
1173f8c047beSCoiby Xu 		qlge_link_off(qdev);
117402a25c9bSGustavo A. R. Silva 		fallthrough;
1175955315b0SBenjamin Poirier 	case MB_CMD_SET_PORT_CFG:
1176955315b0SBenjamin Poirier 		/* Signal the resulting link up AEN
1177955315b0SBenjamin Poirier 		 * that the frame routing and mac addr
1178955315b0SBenjamin Poirier 		 * needs to be set.
11791113c90cSCoiby Xu 		 */
1180955315b0SBenjamin Poirier 		set_bit(QL_CAM_RT_SET, &qdev->flags);
1181955315b0SBenjamin Poirier 		/* Do ACK if required */
1182955315b0SBenjamin Poirier 		if (timeout) {
1183f8c047beSCoiby Xu 			status = qlge_mb_idc_ack(qdev);
1184955315b0SBenjamin Poirier 			if (status)
1185955315b0SBenjamin Poirier 				netif_err(qdev, drv, qdev->ndev,
1186955315b0SBenjamin Poirier 					  "Bug: No pending IDC!\n");
1187955315b0SBenjamin Poirier 		} else {
1188955315b0SBenjamin Poirier 			netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
1189955315b0SBenjamin Poirier 				     "IDC ACK not required\n");
1190955315b0SBenjamin Poirier 			status = 0; /* success */
1191955315b0SBenjamin Poirier 		}
1192955315b0SBenjamin Poirier 		break;
1193955315b0SBenjamin Poirier 
1194955315b0SBenjamin Poirier 		/* These sub-commands issued by another (FCoE)
1195955315b0SBenjamin Poirier 		 * function are requesting to do an operation
1196955315b0SBenjamin Poirier 		 * on the shared resource (MPI environment).
1197955315b0SBenjamin Poirier 		 * We currently don't issue these so we just
1198955315b0SBenjamin Poirier 		 * ACK the request.
1199955315b0SBenjamin Poirier 		 */
1200955315b0SBenjamin Poirier 	case MB_CMD_IOP_RESTART_MPI:
1201955315b0SBenjamin Poirier 	case MB_CMD_IOP_PREP_LINK_DOWN:
1202955315b0SBenjamin Poirier 		/* Drop the link, reload the routing
1203955315b0SBenjamin Poirier 		 * table when link comes up.
1204955315b0SBenjamin Poirier 		 */
1205f8c047beSCoiby Xu 		qlge_link_off(qdev);
1206955315b0SBenjamin Poirier 		set_bit(QL_CAM_RT_SET, &qdev->flags);
120702a25c9bSGustavo A. R. Silva 		fallthrough;
1208955315b0SBenjamin Poirier 	case MB_CMD_IOP_DVR_START:
1209955315b0SBenjamin Poirier 	case MB_CMD_IOP_FLASH_ACC:
1210955315b0SBenjamin Poirier 	case MB_CMD_IOP_CORE_DUMP_MPI:
1211955315b0SBenjamin Poirier 	case MB_CMD_IOP_PREP_UPDATE_MPI:
1212955315b0SBenjamin Poirier 	case MB_CMD_IOP_COMP_UPDATE_MPI:
1213955315b0SBenjamin Poirier 	case MB_CMD_IOP_NONE:	/*  an IDC without params */
1214955315b0SBenjamin Poirier 		/* Do ACK if required */
1215955315b0SBenjamin Poirier 		if (timeout) {
1216f8c047beSCoiby Xu 			status = qlge_mb_idc_ack(qdev);
1217955315b0SBenjamin Poirier 			if (status)
1218955315b0SBenjamin Poirier 				netif_err(qdev, drv, qdev->ndev,
1219955315b0SBenjamin Poirier 					  "Bug: No pending IDC!\n");
1220955315b0SBenjamin Poirier 		} else {
1221955315b0SBenjamin Poirier 			netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
1222955315b0SBenjamin Poirier 				     "IDC ACK not required\n");
1223955315b0SBenjamin Poirier 			status = 0; /* success */
1224955315b0SBenjamin Poirier 		}
1225955315b0SBenjamin Poirier 		break;
1226955315b0SBenjamin Poirier 	}
1227955315b0SBenjamin Poirier }
1228955315b0SBenjamin Poirier 
qlge_mpi_work(struct work_struct * work)1229f8c047beSCoiby Xu void qlge_mpi_work(struct work_struct *work)
1230955315b0SBenjamin Poirier {
1231f8c047beSCoiby Xu 	struct qlge_adapter *qdev =
1232f8c047beSCoiby Xu 		container_of(work, struct qlge_adapter, mpi_work.work);
1233955315b0SBenjamin Poirier 	struct mbox_params mbc;
1234955315b0SBenjamin Poirier 	struct mbox_params *mbcp = &mbc;
1235955315b0SBenjamin Poirier 	int err = 0;
1236955315b0SBenjamin Poirier 
1237955315b0SBenjamin Poirier 	mutex_lock(&qdev->mpi_mutex);
1238955315b0SBenjamin Poirier 	/* Begin polled mode for MPI */
1239f8c047beSCoiby Xu 	qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
1240955315b0SBenjamin Poirier 
1241f8c047beSCoiby Xu 	while (qlge_read32(qdev, STS) & STS_PI) {
1242955315b0SBenjamin Poirier 		memset(mbcp, 0, sizeof(struct mbox_params));
1243955315b0SBenjamin Poirier 		mbcp->out_count = 1;
1244955315b0SBenjamin Poirier 		/* Don't continue if an async event
1245955315b0SBenjamin Poirier 		 * did not complete properly.
1246955315b0SBenjamin Poirier 		 */
1247f8c047beSCoiby Xu 		err = qlge_mpi_handler(qdev, mbcp);
1248955315b0SBenjamin Poirier 		if (err)
1249955315b0SBenjamin Poirier 			break;
1250955315b0SBenjamin Poirier 	}
1251955315b0SBenjamin Poirier 
1252955315b0SBenjamin Poirier 	/* End polled mode for MPI */
1253f8c047beSCoiby Xu 	qlge_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
1254955315b0SBenjamin Poirier 	mutex_unlock(&qdev->mpi_mutex);
1255955315b0SBenjamin Poirier }
1256955315b0SBenjamin Poirier 
qlge_mpi_reset_work(struct work_struct * work)1257f8c047beSCoiby Xu void qlge_mpi_reset_work(struct work_struct *work)
1258955315b0SBenjamin Poirier {
1259f8c047beSCoiby Xu 	struct qlge_adapter *qdev =
1260f8c047beSCoiby Xu 		container_of(work, struct qlge_adapter, mpi_reset_work.work);
1261955315b0SBenjamin Poirier 	cancel_delayed_work_sync(&qdev->mpi_work);
1262955315b0SBenjamin Poirier 	cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
1263955315b0SBenjamin Poirier 	cancel_delayed_work_sync(&qdev->mpi_idc_work);
1264955315b0SBenjamin Poirier 	/* If we're not the dominant NIC function,
1265955315b0SBenjamin Poirier 	 * then there is nothing to do.
1266955315b0SBenjamin Poirier 	 */
1267f8c047beSCoiby Xu 	if (!qlge_own_firmware(qdev)) {
1268955315b0SBenjamin Poirier 		netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n");
1269955315b0SBenjamin Poirier 		return;
1270955315b0SBenjamin Poirier 	}
1271955315b0SBenjamin Poirier 
1272f8c047beSCoiby Xu 	qlge_soft_reset_mpi_risc(qdev);
1273955315b0SBenjamin Poirier }
1274