diff options
author | Ron Mercer <ron.mercer@qlogic.com> | 2009-03-02 03:07:30 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-03 01:45:23 -0500 |
commit | ca0413b66ab44ee0ea40d04eab44ff0fdaf32a1d (patch) | |
tree | 1658a9db70189e590ab85a3759a4460e0e2c61a7 /drivers/net/qlge/qlge_mpi.c | |
parent | ee7537b63a28b42b22e48842dfeedc66d96b71f1 (diff) |
qlge: Add support for firmware mailbox commands.
This interface will be used for setting things like maximum
frame size, setting WOL, and ACKing changes requested by the FCOE
function.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlge/qlge_mpi.c')
-rw-r--r-- | drivers/net/qlge/qlge_mpi.c | 222 |
1 files changed, 218 insertions, 4 deletions
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index a4b810d0d3d1..11102bec36b2 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c | |||
@@ -1,5 +1,25 @@ | |||
1 | #include "qlge.h" | 1 | #include "qlge.h" |
2 | 2 | ||
3 | static void ql_display_mb_sts(struct ql_adapter *qdev, | ||
4 | struct mbox_params *mbcp) | ||
5 | { | ||
6 | int i; | ||
7 | static char *err_sts[] = { | ||
8 | "Command Complete", | ||
9 | "Command Not Supported", | ||
10 | "Host Interface Error", | ||
11 | "Checksum Error", | ||
12 | "Unused Completion Status", | ||
13 | "Test Failed", | ||
14 | "Command Parameter Error"}; | ||
15 | |||
16 | QPRINTK(qdev, DRV, DEBUG, "%s.\n", | ||
17 | err_sts[mbcp->mbox_out[0] & 0x0000000f]); | ||
18 | for (i = 0; i < mbcp->out_count; i++) | ||
19 | QPRINTK(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n", | ||
20 | i, mbcp->mbox_out[i]); | ||
21 | } | ||
22 | |||
3 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) | 23 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) |
4 | { | 24 | { |
5 | int status; | 25 | int status; |
@@ -65,6 +85,59 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) | |||
65 | return status; | 85 | return status; |
66 | } | 86 | } |
67 | 87 | ||
88 | /* Wait for a single mailbox command to complete. | ||
89 | * Returns zero on success. | ||
90 | */ | ||
91 | static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev) | ||
92 | { | ||
93 | int count = 50; /* TODO: arbitrary for now. */ | ||
94 | u32 value; | ||
95 | |||
96 | do { | ||
97 | value = ql_read32(qdev, STS); | ||
98 | if (value & STS_PI) | ||
99 | return 0; | ||
100 | udelay(UDELAY_DELAY); /* 10us */ | ||
101 | } while (--count); | ||
102 | return -ETIMEDOUT; | ||
103 | } | ||
104 | |||
105 | /* Execute a single mailbox command. | ||
106 | * Caller must hold PROC_ADDR semaphore. | ||
107 | */ | ||
108 | static int ql_exec_mb_cmd(struct ql_adapter *qdev, struct mbox_params *mbcp) | ||
109 | { | ||
110 | int i, status; | ||
111 | |||
112 | /* | ||
113 | * Make sure there's nothing pending. | ||
114 | * This shouldn't happen. | ||
115 | */ | ||
116 | if (ql_read32(qdev, CSR) & CSR_HRI) | ||
117 | return -EIO; | ||
118 | |||
119 | status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); | ||
120 | if (status) | ||
121 | return status; | ||
122 | |||
123 | /* | ||
124 | * Fill the outbound mailboxes. | ||
125 | */ | ||
126 | for (i = 0; i < mbcp->in_count; i++) { | ||
127 | status = ql_write_mpi_reg(qdev, qdev->mailbox_in + i, | ||
128 | mbcp->mbox_in[i]); | ||
129 | if (status) | ||
130 | goto end; | ||
131 | } | ||
132 | /* | ||
133 | * Wake up the MPI firmware. | ||
134 | */ | ||
135 | ql_write32(qdev, CSR, CSR_CMD_SET_H2R_INT); | ||
136 | end: | ||
137 | ql_sem_unlock(qdev, SEM_PROC_REG_MASK); | ||
138 | return status; | ||
139 | } | ||
140 | |||
68 | static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) | 141 | static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) |
69 | { | 142 | { |
70 | mbcp->out_count = 2; | 143 | mbcp->out_count = 2; |
@@ -133,6 +206,7 @@ exit: | |||
133 | static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) | 206 | static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) |
134 | { | 207 | { |
135 | int status; | 208 | int status; |
209 | int orig_count = mbcp->out_count; | ||
136 | 210 | ||
137 | /* Just get mailbox zero for now. */ | 211 | /* Just get mailbox zero for now. */ |
138 | mbcp->out_count = 1; | 212 | mbcp->out_count = 1; |
@@ -146,6 +220,27 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) | |||
146 | 220 | ||
147 | switch (mbcp->mbox_out[0]) { | 221 | switch (mbcp->mbox_out[0]) { |
148 | 222 | ||
223 | /* This case is only active when we arrive here | ||
224 | * as a result of issuing a mailbox command to | ||
225 | * the firmware. | ||
226 | */ | ||
227 | case MB_CMD_STS_INTRMDT: | ||
228 | case MB_CMD_STS_GOOD: | ||
229 | case MB_CMD_STS_INVLD_CMD: | ||
230 | case MB_CMD_STS_XFC_ERR: | ||
231 | case MB_CMD_STS_CSUM_ERR: | ||
232 | case MB_CMD_STS_ERR: | ||
233 | case MB_CMD_STS_PARAM_ERR: | ||
234 | /* We can only get mailbox status if we're polling from an | ||
235 | * unfinished command. Get the rest of the status data and | ||
236 | * return back to the caller. | ||
237 | * We only end up here when we're polling for a mailbox | ||
238 | * command completion. | ||
239 | */ | ||
240 | mbcp->out_count = orig_count; | ||
241 | status = ql_get_mb_sts(qdev, mbcp); | ||
242 | return status; | ||
243 | |||
149 | case AEN_LINK_UP: | 244 | case AEN_LINK_UP: |
150 | ql_link_up(qdev, mbcp); | 245 | ql_link_up(qdev, mbcp); |
151 | break; | 246 | break; |
@@ -158,12 +253,8 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) | |||
158 | ql_init_fw_done(qdev, mbcp); | 253 | ql_init_fw_done(qdev, mbcp); |
159 | break; | 254 | break; |
160 | 255 | ||
161 | case MB_CMD_STS_GOOD: | ||
162 | break; | ||
163 | |||
164 | case AEN_FW_INIT_FAIL: | 256 | case AEN_FW_INIT_FAIL: |
165 | case AEN_SYS_ERR: | 257 | case AEN_SYS_ERR: |
166 | case MB_CMD_STS_ERR: | ||
167 | ql_queue_fw_error(qdev); | 258 | ql_queue_fw_error(qdev); |
168 | break; | 259 | break; |
169 | 260 | ||
@@ -177,6 +268,129 @@ end: | |||
177 | return status; | 268 | return status; |
178 | } | 269 | } |
179 | 270 | ||
271 | /* Execute a single mailbox command. | ||
272 | * mbcp is a pointer to an array of u32. Each | ||
273 | * element in the array contains the value for it's | ||
274 | * respective mailbox register. | ||
275 | */ | ||
276 | static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp) | ||
277 | { | ||
278 | int status, count; | ||
279 | |||
280 | mutex_lock(&qdev->mpi_mutex); | ||
281 | |||
282 | /* Begin polled mode for MPI */ | ||
283 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); | ||
284 | |||
285 | /* Load the mailbox registers and wake up MPI RISC. */ | ||
286 | status = ql_exec_mb_cmd(qdev, mbcp); | ||
287 | if (status) | ||
288 | goto end; | ||
289 | |||
290 | |||
291 | /* If we're generating a system error, then there's nothing | ||
292 | * to wait for. | ||
293 | */ | ||
294 | if (mbcp->mbox_in[0] == MB_CMD_MAKE_SYS_ERR) | ||
295 | goto end; | ||
296 | |||
297 | /* Wait for the command to complete. We loop | ||
298 | * here because some AEN might arrive while | ||
299 | * we're waiting for the mailbox command to | ||
300 | * complete. If more than 5 arrive then we can | ||
301 | * assume something is wrong. */ | ||
302 | count = 5; | ||
303 | do { | ||
304 | /* Wait for the interrupt to come in. */ | ||
305 | status = ql_wait_mbx_cmd_cmplt(qdev); | ||
306 | if (status) | ||
307 | goto end; | ||
308 | |||
309 | /* Process the event. If it's an AEN, it | ||
310 | * will be handled in-line or a worker | ||
311 | * will be spawned. If it's our completion | ||
312 | * we will catch it below. | ||
313 | */ | ||
314 | status = ql_mpi_handler(qdev, mbcp); | ||
315 | if (status) | ||
316 | goto end; | ||
317 | |||
318 | /* It's either the completion for our mailbox | ||
319 | * command complete or an AEN. If it's our | ||
320 | * completion then get out. | ||
321 | */ | ||
322 | if (((mbcp->mbox_out[0] & 0x0000f000) == | ||
323 | MB_CMD_STS_GOOD) || | ||
324 | ((mbcp->mbox_out[0] & 0x0000f000) == | ||
325 | MB_CMD_STS_INTRMDT)) | ||
326 | break; | ||
327 | } while (--count); | ||
328 | |||
329 | if (!count) { | ||
330 | QPRINTK(qdev, DRV, ERR, | ||
331 | "Timed out waiting for mailbox complete.\n"); | ||
332 | status = -ETIMEDOUT; | ||
333 | goto end; | ||
334 | } | ||
335 | |||
336 | /* Now we can clear the interrupt condition | ||
337 | * and look at our status. | ||
338 | */ | ||
339 | ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); | ||
340 | |||
341 | if (((mbcp->mbox_out[0] & 0x0000f000) != | ||
342 | MB_CMD_STS_GOOD) && | ||
343 | ((mbcp->mbox_out[0] & 0x0000f000) != | ||
344 | MB_CMD_STS_INTRMDT)) { | ||
345 | ql_display_mb_sts(qdev, mbcp); | ||
346 | status = -EIO; | ||
347 | } | ||
348 | end: | ||
349 | mutex_unlock(&qdev->mpi_mutex); | ||
350 | /* End polled mode for MPI */ | ||
351 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); | ||
352 | return status; | ||
353 | } | ||
354 | |||
355 | /* Get functional state for MPI firmware. | ||
356 | * Returns zero on success. | ||
357 | */ | ||
358 | int ql_mb_get_fw_state(struct ql_adapter *qdev) | ||
359 | { | ||
360 | struct mbox_params mbc; | ||
361 | struct mbox_params *mbcp = &mbc; | ||
362 | int status = 0; | ||
363 | |||
364 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
365 | |||
366 | mbcp->in_count = 1; | ||
367 | mbcp->out_count = 2; | ||
368 | |||
369 | mbcp->mbox_in[0] = MB_CMD_GET_FW_STATE; | ||
370 | |||
371 | status = ql_mailbox_command(qdev, mbcp); | ||
372 | if (status) | ||
373 | return status; | ||
374 | |||
375 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
376 | QPRINTK(qdev, DRV, ERR, | ||
377 | "Failed Get Firmware State.\n"); | ||
378 | status = -EIO; | ||
379 | } | ||
380 | |||
381 | /* If bit zero is set in mbx 1 then the firmware is | ||
382 | * running, but not initialized. This should never | ||
383 | * happen. | ||
384 | */ | ||
385 | if (mbcp->mbox_out[1] & 1) { | ||
386 | QPRINTK(qdev, DRV, ERR, | ||
387 | "Firmware waiting for initialization.\n"); | ||
388 | status = -EIO; | ||
389 | } | ||
390 | |||
391 | return status; | ||
392 | } | ||
393 | |||
180 | void ql_mpi_work(struct work_struct *work) | 394 | void ql_mpi_work(struct work_struct *work) |
181 | { | 395 | { |
182 | struct ql_adapter *qdev = | 396 | struct ql_adapter *qdev = |