]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/net/qlge/qlge_mpi.c
qlge: Move firmware event handler.
[linux-2.6-omap-h63xx.git] / drivers / net / qlge / qlge_mpi.c
1 #include "qlge.h"
2
3 int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
4 {
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);
18 exit:
19         return status;
20 }
21
22 int 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;
37 exit:
38         return status;
39 }
40
41 int 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
48 static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
49 {
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 =
57                     ql_read_mpi_reg(qdev, qdev->mailbox_out + i,
58                                      &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
68 static 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         }
83 exit:
84         /* Clear the MPI firmware status. */
85         ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
86 }
87
88 static 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]);
104 exit:
105         /* Clear the MPI firmware status. */
106         ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
107 }
108
109 static 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]);
122 exit:
123         /* Clear the MPI firmware status. */
124         ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
125 }
126
127 /* 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. */
133 static 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         }
175 end:
176         ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
177         return status;
178 }
179
180 void 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;
186
187         mutex_lock(&qdev->mpi_mutex);
188
189         while (ql_read32(qdev, STS) & STS_PI) {
190                 memset(mbcp, 0, sizeof(struct mbox_params));
191                 mbcp->out_count = 1;
192                 ql_mpi_handler(qdev, mbcp);
193         }
194
195         mutex_unlock(&qdev->mpi_mutex);
196         ql_enable_completion_interrupt(qdev, 0);
197 }
198
199 void 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);
203         ql_soft_reset_mpi_risc(qdev);
204 }