Commit | Line | Data |
---|---|---|
d9e651bc | 1 | /* |
5d242f1c | 2 | * Copyright (C) 2003 - 2009 NetXen, Inc. |
13af7a6e | 3 | * Copyright (C) 2009 - QLogic Corporation. |
d9e651bc DP |
4 | * All rights reserved. |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
19 | * MA 02111-1307, USA. | |
20 | * | |
21 | * The full GNU General Public License is included in this distribution | |
4d21fef4 | 22 | * in the file called "COPYING". |
d9e651bc | 23 | * |
d9e651bc DP |
24 | */ |
25 | ||
26 | #include "netxen_nic_hw.h" | |
27 | #include "netxen_nic.h" | |
d9e651bc DP |
28 | |
29 | #define NXHAL_VERSION 1 | |
30 | ||
d9e651bc DP |
31 | static u32 |
32 | netxen_poll_rsp(struct netxen_adapter *adapter) | |
33 | { | |
2edbb454 | 34 | u32 rsp = NX_CDRP_RSP_OK; |
d9e651bc DP |
35 | int timeout = 0; |
36 | ||
37 | do { | |
38 | /* give atleast 1ms for firmware to respond */ | |
39 | msleep(1); | |
40 | ||
41 | if (++timeout > NX_OS_CRB_RETRY_COUNT) | |
42 | return NX_CDRP_RSP_TIMEOUT; | |
43 | ||
f98a9f69 | 44 | rsp = NXRD32(adapter, NX_CDRP_CRB_OFFSET); |
d9e651bc DP |
45 | } while (!NX_CDRP_IS_RSP(rsp)); |
46 | ||
47 | return rsp; | |
48 | } | |
49 | ||
50 | static u32 | |
51 | netxen_issue_cmd(struct netxen_adapter *adapter, | |
52 | u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd) | |
53 | { | |
54 | u32 rsp; | |
55 | u32 signature = 0; | |
56 | u32 rcode = NX_RCODE_SUCCESS; | |
57 | ||
58 | signature = NX_CDRP_SIGNATURE_MAKE(pci_fn, version); | |
59 | ||
60 | /* Acquire semaphore before accessing CRB */ | |
61 | if (netxen_api_lock(adapter)) | |
62 | return NX_RCODE_TIMEOUT; | |
63 | ||
f98a9f69 | 64 | NXWR32(adapter, NX_SIGN_CRB_OFFSET, signature); |
d9e651bc | 65 | |
f98a9f69 | 66 | NXWR32(adapter, NX_ARG1_CRB_OFFSET, arg1); |
d9e651bc | 67 | |
f98a9f69 | 68 | NXWR32(adapter, NX_ARG2_CRB_OFFSET, arg2); |
d9e651bc | 69 | |
f98a9f69 | 70 | NXWR32(adapter, NX_ARG3_CRB_OFFSET, arg3); |
d9e651bc | 71 | |
f98a9f69 | 72 | NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd)); |
d9e651bc DP |
73 | |
74 | rsp = netxen_poll_rsp(adapter); | |
75 | ||
76 | if (rsp == NX_CDRP_RSP_TIMEOUT) { | |
77 | printk(KERN_ERR "%s: card response timeout.\n", | |
78 | netxen_nic_driver_name); | |
79 | ||
80 | rcode = NX_RCODE_TIMEOUT; | |
81 | } else if (rsp == NX_CDRP_RSP_FAIL) { | |
f98a9f69 | 82 | rcode = NXRD32(adapter, NX_ARG1_CRB_OFFSET); |
d9e651bc DP |
83 | |
84 | printk(KERN_ERR "%s: failed card response code:0x%x\n", | |
85 | netxen_nic_driver_name, rcode); | |
86 | } | |
87 | ||
88 | /* Release semaphore */ | |
89 | netxen_api_unlock(adapter); | |
90 | ||
91 | return rcode; | |
92 | } | |
93 | ||
9ad27643 DP |
94 | int |
95 | nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu) | |
d9e651bc DP |
96 | { |
97 | u32 rcode = NX_RCODE_SUCCESS; | |
becf46a0 | 98 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; |
d9e651bc DP |
99 | |
100 | if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE) | |
101 | rcode = netxen_issue_cmd(adapter, | |
102 | adapter->ahw.pci_func, | |
103 | NXHAL_VERSION, | |
104 | recv_ctx->context_id, | |
105 | mtu, | |
106 | 0, | |
107 | NX_CDRP_CMD_SET_MTU); | |
108 | ||
9ad27643 DP |
109 | if (rcode != NX_RCODE_SUCCESS) |
110 | return -EIO; | |
111 | ||
112 | return 0; | |
d9e651bc DP |
113 | } |
114 | ||
bfd823bd SC |
115 | int |
116 | nx_fw_cmd_set_gbe_port(struct netxen_adapter *adapter, | |
117 | u32 speed, u32 duplex, u32 autoneg) | |
118 | { | |
119 | ||
120 | return netxen_issue_cmd(adapter, | |
121 | adapter->ahw.pci_func, | |
122 | NXHAL_VERSION, | |
123 | speed, | |
124 | duplex, | |
125 | autoneg, | |
126 | NX_CDRP_CMD_CONFIG_GBE_PORT); | |
127 | ||
128 | } | |
129 | ||
d9e651bc DP |
130 | static int |
131 | nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) | |
132 | { | |
133 | void *addr; | |
134 | nx_hostrq_rx_ctx_t *prq; | |
135 | nx_cardrsp_rx_ctx_t *prsp; | |
136 | nx_hostrq_rds_ring_t *prq_rds; | |
137 | nx_hostrq_sds_ring_t *prq_sds; | |
138 | nx_cardrsp_rds_ring_t *prsp_rds; | |
139 | nx_cardrsp_sds_ring_t *prsp_sds; | |
140 | struct nx_host_rds_ring *rds_ring; | |
d8b100c5 | 141 | struct nx_host_sds_ring *sds_ring; |
d9e651bc DP |
142 | |
143 | dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; | |
144 | u64 phys_addr; | |
145 | ||
146 | int i, nrds_rings, nsds_rings; | |
147 | size_t rq_size, rsp_size; | |
2edbb454 | 148 | u32 cap, reg, val; |
d9e651bc DP |
149 | |
150 | int err; | |
151 | ||
becf46a0 | 152 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; |
d9e651bc | 153 | |
d9e651bc | 154 | nrds_rings = adapter->max_rds_rings; |
d8b100c5 | 155 | nsds_rings = adapter->max_sds_rings; |
d9e651bc DP |
156 | |
157 | rq_size = | |
158 | SIZEOF_HOSTRQ_RX(nx_hostrq_rx_ctx_t, nrds_rings, nsds_rings); | |
159 | rsp_size = | |
160 | SIZEOF_CARDRSP_RX(nx_cardrsp_rx_ctx_t, nrds_rings, nsds_rings); | |
161 | ||
162 | addr = pci_alloc_consistent(adapter->pdev, | |
163 | rq_size, &hostrq_phys_addr); | |
164 | if (addr == NULL) | |
165 | return -ENOMEM; | |
166 | prq = (nx_hostrq_rx_ctx_t *)addr; | |
167 | ||
168 | addr = pci_alloc_consistent(adapter->pdev, | |
169 | rsp_size, &cardrsp_phys_addr); | |
170 | if (addr == NULL) { | |
171 | err = -ENOMEM; | |
172 | goto out_free_rq; | |
173 | } | |
174 | prsp = (nx_cardrsp_rx_ctx_t *)addr; | |
175 | ||
176 | prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr); | |
177 | ||
178 | cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); | |
179 | cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); | |
180 | ||
181 | prq->capabilities[0] = cpu_to_le32(cap); | |
182 | prq->host_int_crb_mode = | |
183 | cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED); | |
184 | prq->host_rds_crb_mode = | |
185 | cpu_to_le32(NX_HOST_RDS_CRB_MODE_UNIQUE); | |
186 | ||
187 | prq->num_rds_rings = cpu_to_le16(nrds_rings); | |
188 | prq->num_sds_rings = cpu_to_le16(nsds_rings); | |
2edbb454 DP |
189 | prq->rds_ring_offset = cpu_to_le32(0); |
190 | ||
191 | val = le32_to_cpu(prq->rds_ring_offset) + | |
d9e651bc | 192 | (sizeof(nx_hostrq_rds_ring_t) * nrds_rings); |
2edbb454 | 193 | prq->sds_ring_offset = cpu_to_le32(val); |
d9e651bc | 194 | |
2edbb454 DP |
195 | prq_rds = (nx_hostrq_rds_ring_t *)(prq->data + |
196 | le32_to_cpu(prq->rds_ring_offset)); | |
d9e651bc DP |
197 | |
198 | for (i = 0; i < nrds_rings; i++) { | |
199 | ||
200 | rds_ring = &recv_ctx->rds_rings[i]; | |
201 | ||
202 | prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr); | |
438627c7 | 203 | prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc); |
d9e651bc DP |
204 | prq_rds[i].ring_kind = cpu_to_le32(i); |
205 | prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size); | |
206 | } | |
207 | ||
2edbb454 DP |
208 | prq_sds = (nx_hostrq_sds_ring_t *)(prq->data + |
209 | le32_to_cpu(prq->sds_ring_offset)); | |
d9e651bc | 210 | |
d8b100c5 DP |
211 | for (i = 0; i < nsds_rings; i++) { |
212 | ||
213 | sds_ring = &recv_ctx->sds_rings[i]; | |
214 | ||
215 | prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr); | |
216 | prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc); | |
217 | prq_sds[i].msi_index = cpu_to_le16(i); | |
218 | } | |
d9e651bc DP |
219 | |
220 | phys_addr = hostrq_phys_addr; | |
221 | err = netxen_issue_cmd(adapter, | |
222 | adapter->ahw.pci_func, | |
223 | NXHAL_VERSION, | |
224 | (u32)(phys_addr >> 32), | |
225 | (u32)(phys_addr & 0xffffffff), | |
226 | rq_size, | |
227 | NX_CDRP_CMD_CREATE_RX_CTX); | |
228 | if (err) { | |
229 | printk(KERN_WARNING | |
230 | "Failed to create rx ctx in firmware%d\n", err); | |
231 | goto out_free_rsp; | |
232 | } | |
233 | ||
234 | ||
235 | prsp_rds = ((nx_cardrsp_rds_ring_t *) | |
2edbb454 | 236 | &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]); |
d9e651bc | 237 | |
2edbb454 | 238 | for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) { |
d9e651bc DP |
239 | rds_ring = &recv_ctx->rds_rings[i]; |
240 | ||
241 | reg = le32_to_cpu(prsp_rds[i].host_producer_crb); | |
195c5f98 AKS |
242 | rds_ring->crb_rcv_producer = netxen_get_ioaddr(adapter, |
243 | NETXEN_NIC_REG(reg - 0x200)); | |
d9e651bc DP |
244 | } |
245 | ||
246 | prsp_sds = ((nx_cardrsp_sds_ring_t *) | |
2edbb454 | 247 | &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]); |
d9e651bc | 248 | |
d8b100c5 DP |
249 | for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) { |
250 | sds_ring = &recv_ctx->sds_rings[i]; | |
251 | ||
252 | reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); | |
195c5f98 AKS |
253 | sds_ring->crb_sts_consumer = netxen_get_ioaddr(adapter, |
254 | NETXEN_NIC_REG(reg - 0x200)); | |
d8b100c5 DP |
255 | |
256 | reg = le32_to_cpu(prsp_sds[i].interrupt_crb); | |
195c5f98 AKS |
257 | sds_ring->crb_intr_mask = netxen_get_ioaddr(adapter, |
258 | NETXEN_NIC_REG(reg - 0x200)); | |
d8b100c5 | 259 | } |
d9e651bc DP |
260 | |
261 | recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); | |
262 | recv_ctx->context_id = le16_to_cpu(prsp->context_id); | |
2edbb454 | 263 | recv_ctx->virt_port = prsp->virt_port; |
d9e651bc DP |
264 | |
265 | out_free_rsp: | |
266 | pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); | |
267 | out_free_rq: | |
268 | pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); | |
269 | return err; | |
270 | } | |
271 | ||
272 | static void | |
273 | nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter) | |
274 | { | |
becf46a0 | 275 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; |
d9e651bc DP |
276 | |
277 | if (netxen_issue_cmd(adapter, | |
278 | adapter->ahw.pci_func, | |
279 | NXHAL_VERSION, | |
280 | recv_ctx->context_id, | |
281 | NX_DESTROY_CTX_RESET, | |
282 | 0, | |
283 | NX_CDRP_CMD_DESTROY_RX_CTX)) { | |
284 | ||
285 | printk(KERN_WARNING | |
286 | "%s: Failed to destroy rx ctx in firmware\n", | |
287 | netxen_nic_driver_name); | |
288 | } | |
289 | } | |
290 | ||
291 | static int | |
292 | nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) | |
293 | { | |
294 | nx_hostrq_tx_ctx_t *prq; | |
295 | nx_hostrq_cds_ring_t *prq_cds; | |
296 | nx_cardrsp_tx_ctx_t *prsp; | |
297 | void *rq_addr, *rsp_addr; | |
298 | size_t rq_size, rsp_size; | |
299 | u32 temp; | |
300 | int err = 0; | |
301 | u64 offset, phys_addr; | |
302 | dma_addr_t rq_phys_addr, rsp_phys_addr; | |
4ea528a1 DP |
303 | struct nx_host_tx_ring *tx_ring = adapter->tx_ring; |
304 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; | |
d9e651bc DP |
305 | |
306 | rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t); | |
307 | rq_addr = pci_alloc_consistent(adapter->pdev, | |
308 | rq_size, &rq_phys_addr); | |
309 | if (!rq_addr) | |
310 | return -ENOMEM; | |
311 | ||
312 | rsp_size = SIZEOF_CARDRSP_TX(nx_cardrsp_tx_ctx_t); | |
313 | rsp_addr = pci_alloc_consistent(adapter->pdev, | |
314 | rsp_size, &rsp_phys_addr); | |
315 | if (!rsp_addr) { | |
316 | err = -ENOMEM; | |
317 | goto out_free_rq; | |
318 | } | |
319 | ||
320 | memset(rq_addr, 0, rq_size); | |
321 | prq = (nx_hostrq_tx_ctx_t *)rq_addr; | |
322 | ||
323 | memset(rsp_addr, 0, rsp_size); | |
324 | prsp = (nx_cardrsp_tx_ctx_t *)rsp_addr; | |
325 | ||
326 | prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr); | |
327 | ||
328 | temp = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN | NX_CAP0_LSO); | |
329 | prq->capabilities[0] = cpu_to_le32(temp); | |
330 | ||
331 | prq->host_int_crb_mode = | |
332 | cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED); | |
333 | ||
334 | prq->interrupt_ctl = 0; | |
335 | prq->msi_index = 0; | |
336 | ||
337 | prq->dummy_dma_addr = cpu_to_le64(adapter->dummy_dma.phys_addr); | |
338 | ||
4ea528a1 | 339 | offset = recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx); |
d9e651bc DP |
340 | prq->cmd_cons_dma_addr = cpu_to_le64(offset); |
341 | ||
342 | prq_cds = &prq->cds_ring; | |
343 | ||
d877f1e3 DP |
344 | prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); |
345 | prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); | |
d9e651bc DP |
346 | |
347 | phys_addr = rq_phys_addr; | |
348 | err = netxen_issue_cmd(adapter, | |
349 | adapter->ahw.pci_func, | |
350 | NXHAL_VERSION, | |
351 | (u32)(phys_addr >> 32), | |
352 | ((u32)phys_addr & 0xffffffff), | |
353 | rq_size, | |
354 | NX_CDRP_CMD_CREATE_TX_CTX); | |
355 | ||
356 | if (err == NX_RCODE_SUCCESS) { | |
357 | temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); | |
195c5f98 AKS |
358 | tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter, |
359 | NETXEN_NIC_REG(temp - 0x200)); | |
d9e651bc DP |
360 | #if 0 |
361 | adapter->tx_state = | |
362 | le32_to_cpu(prsp->host_ctx_state); | |
363 | #endif | |
364 | adapter->tx_context_id = | |
365 | le16_to_cpu(prsp->context_id); | |
366 | } else { | |
367 | printk(KERN_WARNING | |
368 | "Failed to create tx ctx in firmware%d\n", err); | |
369 | err = -EIO; | |
370 | } | |
371 | ||
372 | pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); | |
373 | ||
374 | out_free_rq: | |
375 | pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); | |
376 | ||
377 | return err; | |
378 | } | |
379 | ||
380 | static void | |
381 | nx_fw_cmd_destroy_tx_ctx(struct netxen_adapter *adapter) | |
382 | { | |
383 | if (netxen_issue_cmd(adapter, | |
384 | adapter->ahw.pci_func, | |
385 | NXHAL_VERSION, | |
386 | adapter->tx_context_id, | |
387 | NX_DESTROY_CTX_RESET, | |
388 | 0, | |
389 | NX_CDRP_CMD_DESTROY_TX_CTX)) { | |
390 | ||
391 | printk(KERN_WARNING | |
392 | "%s: Failed to destroy tx ctx in firmware\n", | |
393 | netxen_nic_driver_name); | |
394 | } | |
395 | } | |
396 | ||
3ad4467c DP |
397 | int |
398 | nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val) | |
399 | { | |
400 | u32 rcode; | |
401 | ||
402 | rcode = netxen_issue_cmd(adapter, | |
403 | adapter->ahw.pci_func, | |
404 | NXHAL_VERSION, | |
405 | reg, | |
406 | 0, | |
407 | 0, | |
408 | NX_CDRP_CMD_READ_PHY); | |
409 | ||
410 | if (rcode != NX_RCODE_SUCCESS) | |
411 | return -EIO; | |
412 | ||
413 | return NXRD32(adapter, NX_ARG1_CRB_OFFSET); | |
414 | } | |
415 | ||
416 | int | |
417 | nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val) | |
418 | { | |
419 | u32 rcode; | |
420 | ||
421 | rcode = netxen_issue_cmd(adapter, | |
422 | adapter->ahw.pci_func, | |
423 | NXHAL_VERSION, | |
424 | reg, | |
425 | val, | |
426 | 0, | |
427 | NX_CDRP_CMD_WRITE_PHY); | |
428 | ||
429 | if (rcode != NX_RCODE_SUCCESS) | |
430 | return -EIO; | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
d9e651bc DP |
435 | static u64 ctx_addr_sig_regs[][3] = { |
436 | {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, | |
437 | {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, | |
438 | {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, | |
439 | {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} | |
440 | }; | |
441 | ||
442 | #define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0]) | |
443 | #define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2]) | |
444 | #define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1]) | |
445 | ||
446 | #define lower32(x) ((u32)((x) & 0xffffffff)) | |
447 | #define upper32(x) ((u32)(((u64)(x) >> 32) & 0xffffffff)) | |
448 | ||
449 | static struct netxen_recv_crb recv_crb_registers[] = { | |
450 | /* Instance 0 */ | |
451 | { | |
452 | /* crb_rcv_producer: */ | |
453 | { | |
454 | NETXEN_NIC_REG(0x100), | |
455 | /* Jumbo frames */ | |
456 | NETXEN_NIC_REG(0x110), | |
457 | /* LRO */ | |
458 | NETXEN_NIC_REG(0x120) | |
459 | }, | |
460 | /* crb_sts_consumer: */ | |
f6d21f44 DP |
461 | { |
462 | NETXEN_NIC_REG(0x138), | |
463 | NETXEN_NIC_REG_2(0x000), | |
464 | NETXEN_NIC_REG_2(0x004), | |
465 | NETXEN_NIC_REG_2(0x008), | |
466 | }, | |
467 | /* sw_int_mask */ | |
468 | { | |
469 | CRB_SW_INT_MASK_0, | |
470 | NETXEN_NIC_REG_2(0x044), | |
471 | NETXEN_NIC_REG_2(0x048), | |
472 | NETXEN_NIC_REG_2(0x04c), | |
473 | }, | |
d9e651bc DP |
474 | }, |
475 | /* Instance 1 */ | |
476 | { | |
477 | /* crb_rcv_producer: */ | |
478 | { | |
479 | NETXEN_NIC_REG(0x144), | |
480 | /* Jumbo frames */ | |
481 | NETXEN_NIC_REG(0x154), | |
482 | /* LRO */ | |
483 | NETXEN_NIC_REG(0x164) | |
484 | }, | |
485 | /* crb_sts_consumer: */ | |
f6d21f44 DP |
486 | { |
487 | NETXEN_NIC_REG(0x17c), | |
488 | NETXEN_NIC_REG_2(0x020), | |
489 | NETXEN_NIC_REG_2(0x024), | |
490 | NETXEN_NIC_REG_2(0x028), | |
491 | }, | |
492 | /* sw_int_mask */ | |
493 | { | |
494 | CRB_SW_INT_MASK_1, | |
495 | NETXEN_NIC_REG_2(0x064), | |
496 | NETXEN_NIC_REG_2(0x068), | |
497 | NETXEN_NIC_REG_2(0x06c), | |
498 | }, | |
d9e651bc DP |
499 | }, |
500 | /* Instance 2 */ | |
501 | { | |
502 | /* crb_rcv_producer: */ | |
503 | { | |
504 | NETXEN_NIC_REG(0x1d8), | |
505 | /* Jumbo frames */ | |
506 | NETXEN_NIC_REG(0x1f8), | |
507 | /* LRO */ | |
508 | NETXEN_NIC_REG(0x208) | |
509 | }, | |
510 | /* crb_sts_consumer: */ | |
f6d21f44 DP |
511 | { |
512 | NETXEN_NIC_REG(0x220), | |
513 | NETXEN_NIC_REG_2(0x03c), | |
514 | NETXEN_NIC_REG_2(0x03c), | |
515 | NETXEN_NIC_REG_2(0x03c), | |
516 | }, | |
517 | /* sw_int_mask */ | |
518 | { | |
519 | CRB_SW_INT_MASK_2, | |
520 | NETXEN_NIC_REG_2(0x03c), | |
521 | NETXEN_NIC_REG_2(0x03c), | |
522 | NETXEN_NIC_REG_2(0x03c), | |
523 | }, | |
d9e651bc DP |
524 | }, |
525 | /* Instance 3 */ | |
526 | { | |
527 | /* crb_rcv_producer: */ | |
528 | { | |
529 | NETXEN_NIC_REG(0x22c), | |
530 | /* Jumbo frames */ | |
531 | NETXEN_NIC_REG(0x23c), | |
532 | /* LRO */ | |
533 | NETXEN_NIC_REG(0x24c) | |
534 | }, | |
535 | /* crb_sts_consumer: */ | |
f6d21f44 DP |
536 | { |
537 | NETXEN_NIC_REG(0x264), | |
538 | NETXEN_NIC_REG_2(0x03c), | |
539 | NETXEN_NIC_REG_2(0x03c), | |
540 | NETXEN_NIC_REG_2(0x03c), | |
541 | }, | |
542 | /* sw_int_mask */ | |
543 | { | |
544 | CRB_SW_INT_MASK_3, | |
545 | NETXEN_NIC_REG_2(0x03c), | |
546 | NETXEN_NIC_REG_2(0x03c), | |
547 | NETXEN_NIC_REG_2(0x03c), | |
548 | }, | |
d9e651bc DP |
549 | }, |
550 | }; | |
551 | ||
552 | static int | |
553 | netxen_init_old_ctx(struct netxen_adapter *adapter) | |
554 | { | |
555 | struct netxen_recv_context *recv_ctx; | |
556 | struct nx_host_rds_ring *rds_ring; | |
d8b100c5 | 557 | struct nx_host_sds_ring *sds_ring; |
d877f1e3 | 558 | struct nx_host_tx_ring *tx_ring; |
becf46a0 | 559 | int ring; |
f6d21f44 | 560 | int port = adapter->portnum; |
4ea528a1 | 561 | struct netxen_ring_ctx *hwctx; |
f6d21f44 | 562 | u32 signature; |
d9e651bc | 563 | |
4ea528a1 DP |
564 | tx_ring = adapter->tx_ring; |
565 | recv_ctx = &adapter->recv_ctx; | |
566 | hwctx = recv_ctx->hwctx; | |
567 | ||
f6d21f44 DP |
568 | hwctx->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); |
569 | hwctx->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); | |
d9e651bc | 570 | |
d9e651bc | 571 | |
becf46a0 DP |
572 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { |
573 | rds_ring = &recv_ctx->rds_rings[ring]; | |
d9e651bc | 574 | |
f6d21f44 | 575 | hwctx->rcv_rings[ring].addr = |
becf46a0 | 576 | cpu_to_le64(rds_ring->phys_addr); |
f6d21f44 | 577 | hwctx->rcv_rings[ring].size = |
438627c7 | 578 | cpu_to_le32(rds_ring->num_desc); |
d9e651bc DP |
579 | } |
580 | ||
f6d21f44 DP |
581 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
582 | sds_ring = &recv_ctx->sds_rings[ring]; | |
583 | ||
584 | if (ring == 0) { | |
585 | hwctx->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); | |
586 | hwctx->sts_ring_size = cpu_to_le32(sds_ring->num_desc); | |
587 | } | |
588 | hwctx->sts_rings[ring].addr = cpu_to_le64(sds_ring->phys_addr); | |
589 | hwctx->sts_rings[ring].size = cpu_to_le32(sds_ring->num_desc); | |
590 | hwctx->sts_rings[ring].msi_index = cpu_to_le16(ring); | |
591 | } | |
592 | hwctx->sts_ring_count = cpu_to_le32(adapter->max_sds_rings); | |
593 | ||
594 | signature = (adapter->max_sds_rings > 1) ? | |
595 | NETXEN_CTX_SIGNATURE_V2 : NETXEN_CTX_SIGNATURE; | |
596 | ||
597 | NXWR32(adapter, CRB_CTX_ADDR_REG_LO(port), | |
4ea528a1 | 598 | lower32(recv_ctx->phys_addr)); |
f6d21f44 | 599 | NXWR32(adapter, CRB_CTX_ADDR_REG_HI(port), |
4ea528a1 | 600 | upper32(recv_ctx->phys_addr)); |
f6d21f44 DP |
601 | NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), |
602 | signature | port); | |
d9e651bc DP |
603 | return 0; |
604 | } | |
605 | ||
d9e651bc DP |
606 | int netxen_alloc_hw_resources(struct netxen_adapter *adapter) |
607 | { | |
d9e651bc DP |
608 | void *addr; |
609 | int err = 0; | |
becf46a0 | 610 | int ring; |
d9e651bc DP |
611 | struct netxen_recv_context *recv_ctx; |
612 | struct nx_host_rds_ring *rds_ring; | |
d8b100c5 | 613 | struct nx_host_sds_ring *sds_ring; |
4ea528a1 | 614 | struct nx_host_tx_ring *tx_ring; |
d8b100c5 DP |
615 | |
616 | struct pci_dev *pdev = adapter->pdev; | |
617 | struct net_device *netdev = adapter->netdev; | |
f6d21f44 | 618 | int port = adapter->portnum; |
d9e651bc | 619 | |
4ea528a1 DP |
620 | recv_ctx = &adapter->recv_ctx; |
621 | tx_ring = adapter->tx_ring; | |
622 | ||
d8b100c5 | 623 | addr = pci_alloc_consistent(pdev, |
d9e651bc | 624 | sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), |
4ea528a1 | 625 | &recv_ctx->phys_addr); |
d9e651bc | 626 | if (addr == NULL) { |
d8b100c5 | 627 | dev_err(&pdev->dev, "failed to allocate hw context\n"); |
d9e651bc DP |
628 | return -ENOMEM; |
629 | } | |
4ea528a1 | 630 | |
d9e651bc | 631 | memset(addr, 0, sizeof(struct netxen_ring_ctx)); |
4ea528a1 DP |
632 | recv_ctx->hwctx = (struct netxen_ring_ctx *)addr; |
633 | recv_ctx->hwctx->ctx_id = cpu_to_le32(port); | |
634 | recv_ctx->hwctx->cmd_consumer_offset = | |
635 | cpu_to_le64(recv_ctx->phys_addr + | |
d9e651bc | 636 | sizeof(struct netxen_ring_ctx)); |
d877f1e3 | 637 | tx_ring->hw_consumer = |
d9e651bc DP |
638 | (__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx)); |
639 | ||
640 | /* cmd desc ring */ | |
d877f1e3 DP |
641 | addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), |
642 | &tx_ring->phys_addr); | |
d9e651bc DP |
643 | |
644 | if (addr == NULL) { | |
d8b100c5 DP |
645 | dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n", |
646 | netdev->name); | |
bf445080 AKS |
647 | err = -ENOMEM; |
648 | goto err_out_free; | |
d9e651bc DP |
649 | } |
650 | ||
d877f1e3 | 651 | tx_ring->desc_head = (struct cmd_desc_type0 *)addr; |
d9e651bc | 652 | |
becf46a0 | 653 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { |
becf46a0 | 654 | rds_ring = &recv_ctx->rds_rings[ring]; |
d9e651bc | 655 | addr = pci_alloc_consistent(adapter->pdev, |
d8b100c5 | 656 | RCV_DESC_RINGSIZE(rds_ring), |
becf46a0 | 657 | &rds_ring->phys_addr); |
d9e651bc | 658 | if (addr == NULL) { |
d8b100c5 DP |
659 | dev_err(&pdev->dev, |
660 | "%s: failed to allocate rds ring [%d]\n", | |
661 | netdev->name, ring); | |
d9e651bc DP |
662 | err = -ENOMEM; |
663 | goto err_out_free; | |
664 | } | |
becf46a0 | 665 | rds_ring->desc_head = (struct rcv_desc *)addr; |
d9e651bc | 666 | |
4f96b988 | 667 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) |
becf46a0 | 668 | rds_ring->crb_rcv_producer = |
195c5f98 AKS |
669 | netxen_get_ioaddr(adapter, |
670 | recv_crb_registers[port].crb_rcv_producer[ring]); | |
d9e651bc DP |
671 | } |
672 | ||
d8b100c5 DP |
673 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
674 | sds_ring = &recv_ctx->sds_rings[ring]; | |
675 | ||
676 | addr = pci_alloc_consistent(adapter->pdev, | |
677 | STATUS_DESC_RINGSIZE(sds_ring), | |
678 | &sds_ring->phys_addr); | |
679 | if (addr == NULL) { | |
680 | dev_err(&pdev->dev, | |
681 | "%s: failed to allocate sds ring [%d]\n", | |
682 | netdev->name, ring); | |
683 | err = -ENOMEM; | |
684 | goto err_out_free; | |
685 | } | |
686 | sds_ring->desc_head = (struct status_desc *)addr; | |
f6d21f44 | 687 | |
77c55390 AKS |
688 | if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { |
689 | sds_ring->crb_sts_consumer = | |
690 | netxen_get_ioaddr(adapter, | |
691 | recv_crb_registers[port].crb_sts_consumer[ring]); | |
f6d21f44 | 692 | |
77c55390 AKS |
693 | sds_ring->crb_intr_mask = |
694 | netxen_get_ioaddr(adapter, | |
695 | recv_crb_registers[port].sw_int_mask[ring]); | |
696 | } | |
becf46a0 | 697 | } |
becf46a0 | 698 | |
becf46a0 | 699 | |
4f96b988 | 700 | if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { |
6a581e93 DP |
701 | if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state)) |
702 | goto done; | |
d9e651bc DP |
703 | err = nx_fw_cmd_create_rx_ctx(adapter); |
704 | if (err) | |
705 | goto err_out_free; | |
706 | err = nx_fw_cmd_create_tx_ctx(adapter); | |
707 | if (err) | |
708 | goto err_out_free; | |
709 | } else { | |
d9e651bc | 710 | err = netxen_init_old_ctx(adapter); |
cf981ffb DP |
711 | if (err) |
712 | goto err_out_free; | |
d9e651bc DP |
713 | } |
714 | ||
6a581e93 | 715 | done: |
d9e651bc DP |
716 | return 0; |
717 | ||
718 | err_out_free: | |
719 | netxen_free_hw_resources(adapter); | |
720 | return err; | |
721 | } | |
722 | ||
723 | void netxen_free_hw_resources(struct netxen_adapter *adapter) | |
724 | { | |
725 | struct netxen_recv_context *recv_ctx; | |
726 | struct nx_host_rds_ring *rds_ring; | |
d8b100c5 | 727 | struct nx_host_sds_ring *sds_ring; |
d877f1e3 | 728 | struct nx_host_tx_ring *tx_ring; |
becf46a0 | 729 | int ring; |
d9e651bc | 730 | |
f6d21f44 DP |
731 | int port = adapter->portnum; |
732 | ||
4f96b988 | 733 | if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { |
6a581e93 DP |
734 | if (!test_and_clear_bit(__NX_FW_ATTACHED, &adapter->state)) |
735 | goto done; | |
736 | ||
d9e651bc | 737 | nx_fw_cmd_destroy_rx_ctx(adapter); |
cf981ffb | 738 | nx_fw_cmd_destroy_tx_ctx(adapter); |
f6d21f44 DP |
739 | } else { |
740 | netxen_api_lock(adapter); | |
741 | NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), | |
cf981ffb | 742 | NETXEN_CTX_D3_RESET | port); |
f6d21f44 | 743 | netxen_api_unlock(adapter); |
d9e651bc DP |
744 | } |
745 | ||
cf981ffb DP |
746 | /* Allow dma queues to drain after context reset */ |
747 | msleep(20); | |
748 | ||
6a581e93 | 749 | done: |
4ea528a1 DP |
750 | recv_ctx = &adapter->recv_ctx; |
751 | ||
752 | if (recv_ctx->hwctx != NULL) { | |
d9e651bc DP |
753 | pci_free_consistent(adapter->pdev, |
754 | sizeof(struct netxen_ring_ctx) + | |
755 | sizeof(uint32_t), | |
4ea528a1 DP |
756 | recv_ctx->hwctx, |
757 | recv_ctx->phys_addr); | |
758 | recv_ctx->hwctx = NULL; | |
d9e651bc DP |
759 | } |
760 | ||
4ea528a1 | 761 | tx_ring = adapter->tx_ring; |
d877f1e3 | 762 | if (tx_ring->desc_head != NULL) { |
d9e651bc | 763 | pci_free_consistent(adapter->pdev, |
d877f1e3 DP |
764 | TX_DESC_RINGSIZE(tx_ring), |
765 | tx_ring->desc_head, tx_ring->phys_addr); | |
766 | tx_ring->desc_head = NULL; | |
d9e651bc DP |
767 | } |
768 | ||
becf46a0 DP |
769 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { |
770 | rds_ring = &recv_ctx->rds_rings[ring]; | |
d9e651bc | 771 | |
becf46a0 | 772 | if (rds_ring->desc_head != NULL) { |
d9e651bc | 773 | pci_free_consistent(adapter->pdev, |
d8b100c5 | 774 | RCV_DESC_RINGSIZE(rds_ring), |
becf46a0 DP |
775 | rds_ring->desc_head, |
776 | rds_ring->phys_addr); | |
777 | rds_ring->desc_head = NULL; | |
d9e651bc DP |
778 | } |
779 | } | |
becf46a0 | 780 | |
d8b100c5 DP |
781 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { |
782 | sds_ring = &recv_ctx->sds_rings[ring]; | |
783 | ||
784 | if (sds_ring->desc_head != NULL) { | |
785 | pci_free_consistent(adapter->pdev, | |
786 | STATUS_DESC_RINGSIZE(sds_ring), | |
787 | sds_ring->desc_head, | |
788 | sds_ring->phys_addr); | |
789 | sds_ring->desc_head = NULL; | |
790 | } | |
becf46a0 | 791 | } |
d9e651bc DP |
792 | } |
793 |