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