blob: a4b810d0d3d1aa0ae9365a98c6bf9fd409c60f08 [file] [log] [blame]
Ron Mercerc4e84bd2008-09-18 11:56:28 -04001#include "qlge.h"
2
Ron Mercera2e809b2009-02-26 10:08:33 +00003int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
Ron Mercerc4e84bd2008-09-18 11:56:28 -04004{
5 int status;
6 /* wait for reg to come ready */
7 status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
8 if (status)
9 goto exit;
10 /* set up for reg read */
11 ql_write32(qdev, PROC_ADDR, reg | PROC_ADDR_R);
12 /* wait for reg to come ready */
13 status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
14 if (status)
15 goto exit;
16 /* get the data */
17 *data = ql_read32(qdev, PROC_DATA);
18exit:
19 return status;
20}
21
Ron Mercera2e809b2009-02-26 10:08:33 +000022int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data)
23{
24 int status = 0;
25 /* wait for reg to come ready */
26 status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
27 if (status)
28 goto exit;
29 /* write the data to the data reg */
30 ql_write32(qdev, PROC_DATA, data);
31 /* trigger the write */
32 ql_write32(qdev, PROC_ADDR, reg);
33 /* wait for reg to come ready */
34 status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
35 if (status)
36 goto exit;
37exit:
38 return status;
39}
40
41int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
42{
43 int status;
44 status = ql_write_mpi_reg(qdev, 0x00001010, 1);
45 return status;
46}
47
Hannes Eder2f22d222008-12-26 00:04:53 -080048static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
Ron Mercerc4e84bd2008-09-18 11:56:28 -040049{
50 int i, status;
51
52 status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
53 if (status)
54 return -EBUSY;
55 for (i = 0; i < mbcp->out_count; i++) {
56 status =
Ron Mercera2e809b2009-02-26 10:08:33 +000057 ql_read_mpi_reg(qdev, qdev->mailbox_out + i,
Ron Mercerc4e84bd2008-09-18 11:56:28 -040058 &mbcp->mbox_out[i]);
59 if (status) {
60 QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n");
61 break;
62 }
63 }
64 ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
65 return status;
66}
67
68static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
69{
70 mbcp->out_count = 2;
71
72 if (ql_get_mb_sts(qdev, mbcp))
73 goto exit;
74
75 qdev->link_status = mbcp->mbox_out[1];
76 QPRINTK(qdev, DRV, ERR, "Link Up.\n");
77 QPRINTK(qdev, DRV, INFO, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
78 if (!netif_carrier_ok(qdev->ndev)) {
79 QPRINTK(qdev, LINK, INFO, "Link is Up.\n");
80 netif_carrier_on(qdev->ndev);
81 netif_wake_queue(qdev->ndev);
82 }
83exit:
84 /* Clear the MPI firmware status. */
85 ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
86}
87
88static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
89{
90 mbcp->out_count = 3;
91
92 if (ql_get_mb_sts(qdev, mbcp)) {
93 QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
94 goto exit;
95 }
96
97 if (netif_carrier_ok(qdev->ndev)) {
98 QPRINTK(qdev, LINK, INFO, "Link is Down.\n");
99 netif_carrier_off(qdev->ndev);
100 netif_stop_queue(qdev->ndev);
101 }
102 QPRINTK(qdev, DRV, ERR, "Link Down.\n");
103 QPRINTK(qdev, DRV, ERR, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
104exit:
105 /* Clear the MPI firmware status. */
106 ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
107}
108
109static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
110{
111 mbcp->out_count = 2;
112
113 if (ql_get_mb_sts(qdev, mbcp)) {
114 QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
115 goto exit;
116 }
117 QPRINTK(qdev, DRV, ERR, "Firmware initialized!\n");
118 QPRINTK(qdev, DRV, ERR, "Firmware status = 0x%.08x.\n",
119 mbcp->mbox_out[0]);
120 QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n",
121 mbcp->mbox_out[1]);
122exit:
123 /* Clear the MPI firmware status. */
124 ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
125}
126
Ron Mercer125844e2009-02-26 10:08:34 +0000127/* Process an async event and clear it unless it's an
128 * error condition.
129 * This can get called iteratively from the mpi_work thread
130 * when events arrive via an interrupt.
131 * It also gets called when a mailbox command is polling for
132 * it's completion. */
133static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
134{
135 int status;
136
137 /* Just get mailbox zero for now. */
138 mbcp->out_count = 1;
139 status = ql_get_mb_sts(qdev, mbcp);
140 if (status) {
141 QPRINTK(qdev, DRV, ERR,
142 "Could not read MPI, resetting ASIC!\n");
143 ql_queue_asic_error(qdev);
144 goto end;
145 }
146
147 switch (mbcp->mbox_out[0]) {
148
149 case AEN_LINK_UP:
150 ql_link_up(qdev, mbcp);
151 break;
152
153 case AEN_LINK_DOWN:
154 ql_link_down(qdev, mbcp);
155 break;
156
157 case AEN_FW_INIT_DONE:
158 ql_init_fw_done(qdev, mbcp);
159 break;
160
161 case MB_CMD_STS_GOOD:
162 break;
163
164 case AEN_FW_INIT_FAIL:
165 case AEN_SYS_ERR:
166 case MB_CMD_STS_ERR:
167 ql_queue_fw_error(qdev);
168 break;
169
170 default:
171 QPRINTK(qdev, DRV, ERR,
172 "Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
173 /* Clear the MPI firmware status. */
174 }
175end:
176 ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
177 return status;
178}
179
Ron Mercerc4e84bd2008-09-18 11:56:28 -0400180void ql_mpi_work(struct work_struct *work)
181{
182 struct ql_adapter *qdev =
183 container_of(work, struct ql_adapter, mpi_work.work);
184 struct mbox_params mbc;
185 struct mbox_params *mbcp = &mbc;
Ron Mercer125844e2009-02-26 10:08:34 +0000186
187 mutex_lock(&qdev->mpi_mutex);
Ron Mercerc4e84bd2008-09-18 11:56:28 -0400188
189 while (ql_read32(qdev, STS) & STS_PI) {
Ron Mercer125844e2009-02-26 10:08:34 +0000190 memset(mbcp, 0, sizeof(struct mbox_params));
191 mbcp->out_count = 1;
192 ql_mpi_handler(qdev, mbcp);
Ron Mercerc4e84bd2008-09-18 11:56:28 -0400193 }
Ron Mercer125844e2009-02-26 10:08:34 +0000194
195 mutex_unlock(&qdev->mpi_mutex);
Ron Mercerc4e84bd2008-09-18 11:56:28 -0400196 ql_enable_completion_interrupt(qdev, 0);
197}
198
199void ql_mpi_reset_work(struct work_struct *work)
200{
201 struct ql_adapter *qdev =
202 container_of(work, struct ql_adapter, mpi_reset_work.work);
Ron Mercera2e809b2009-02-26 10:08:33 +0000203 ql_soft_reset_mpi_risc(qdev);
Ron Mercerc4e84bd2008-09-18 11:56:28 -0400204}