FreeBSD/Linux Kernel Cross Reference
sys/dev/qlxge/qls_hw.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2013-2014 Qlogic Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * File: qls_hw.c
32 * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
33 * Content: Contains Hardware dependent functions
34 */
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "qls_os.h"
39 #include "qls_hw.h"
40 #include "qls_def.h"
41 #include "qls_inline.h"
42 #include "qls_ver.h"
43 #include "qls_glbl.h"
44 #include "qls_dbg.h"
45
46 /*
47 * Static Functions
48 */
49 static int qls_wait_for_mac_proto_idx_ready(qla_host_t *ha, uint32_t op);
50 static int qls_config_unicast_mac_addr(qla_host_t *ha, uint32_t add_mac);
51 static int qls_config_mcast_mac_addr(qla_host_t *ha, uint8_t *mac_addr,
52 uint32_t add_mac, uint32_t index);
53
54 static int qls_init_rss(qla_host_t *ha);
55 static int qls_init_comp_queue(qla_host_t *ha, int cid);
56 static int qls_init_work_queue(qla_host_t *ha, int wid);
57 static int qls_init_fw_routing_table(qla_host_t *ha);
58 static int qls_hw_add_all_mcast(qla_host_t *ha);
59 static int qls_hw_add_mcast(qla_host_t *ha, uint8_t *mta);
60 static int qls_hw_del_mcast(qla_host_t *ha, uint8_t *mta);
61 static int qls_wait_for_flash_ready(qla_host_t *ha);
62
63 static int qls_sem_lock(qla_host_t *ha, uint32_t mask, uint32_t value);
64 static void qls_sem_unlock(qla_host_t *ha, uint32_t mask);
65
66 static void qls_free_tx_dma(qla_host_t *ha);
67 static int qls_alloc_tx_dma(qla_host_t *ha);
68 static void qls_free_rx_dma(qla_host_t *ha);
69 static int qls_alloc_rx_dma(qla_host_t *ha);
70 static void qls_free_mpi_dma(qla_host_t *ha);
71 static int qls_alloc_mpi_dma(qla_host_t *ha);
72 static void qls_free_rss_dma(qla_host_t *ha);
73 static int qls_alloc_rss_dma(qla_host_t *ha);
74
75 static int qls_flash_validate(qla_host_t *ha, const char *signature);
76
77 static int qls_wait_for_proc_addr_ready(qla_host_t *ha);
78 static int qls_proc_addr_rd_reg(qla_host_t *ha, uint32_t addr_module,
79 uint32_t reg, uint32_t *data);
80 static int qls_proc_addr_wr_reg(qla_host_t *ha, uint32_t addr_module,
81 uint32_t reg, uint32_t data);
82
83 static int qls_hw_reset(qla_host_t *ha);
84
85 /*
86 * MPI Related Functions
87 */
88 static int qls_mbx_cmd(qla_host_t *ha, uint32_t *in_mbx, uint32_t i_count,
89 uint32_t *out_mbx, uint32_t o_count);
90 static int qls_mbx_set_mgmt_ctrl(qla_host_t *ha, uint32_t t_ctrl);
91 static int qls_mbx_get_mgmt_ctrl(qla_host_t *ha, uint32_t *t_status);
92 static void qls_mbx_get_link_status(qla_host_t *ha);
93 static void qls_mbx_about_fw(qla_host_t *ha);
94
95 int
96 qls_get_msix_count(qla_host_t *ha)
97 {
98 return (ha->num_rx_rings);
99 }
100
101 static int
102 qls_syctl_mpi_dump(SYSCTL_HANDLER_ARGS)
103 {
104 int err = 0, ret;
105 qla_host_t *ha;
106
107 err = sysctl_handle_int(oidp, &ret, 0, req);
108
109 if (err || !req->newptr)
110 return (err);
111
112 if (ret == 1) {
113 ha = (qla_host_t *)arg1;
114 qls_mpi_core_dump(ha);
115 }
116 return (err);
117 }
118
119 static int
120 qls_syctl_link_status(SYSCTL_HANDLER_ARGS)
121 {
122 int err = 0, ret;
123 qla_host_t *ha;
124
125 err = sysctl_handle_int(oidp, &ret, 0, req);
126
127 if (err || !req->newptr)
128 return (err);
129
130 if (ret == 1) {
131 ha = (qla_host_t *)arg1;
132 qls_mbx_get_link_status(ha);
133 qls_mbx_about_fw(ha);
134 }
135 return (err);
136 }
137
138 void
139 qls_hw_add_sysctls(qla_host_t *ha)
140 {
141 device_t dev;
142
143 dev = ha->pci_dev;
144
145 ha->num_rx_rings = MAX_RX_RINGS; ha->num_tx_rings = MAX_TX_RINGS;
146
147 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
148 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
149 OID_AUTO, "num_rx_rings", CTLFLAG_RD, &ha->num_rx_rings,
150 ha->num_rx_rings, "Number of Completion Queues");
151
152 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
153 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
154 OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->num_tx_rings,
155 ha->num_tx_rings, "Number of Transmit Rings");
156
157 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
158 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
159 OID_AUTO, "mpi_dump",
160 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
161 qls_syctl_mpi_dump, "I", "MPI Dump");
162
163 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
164 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
165 OID_AUTO, "link_status",
166 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
167 qls_syctl_link_status, "I", "Link Status");
168 }
169
170 /*
171 * Name: qls_free_dma
172 * Function: Frees the DMA'able memory allocated in qls_alloc_dma()
173 */
174 void
175 qls_free_dma(qla_host_t *ha)
176 {
177 qls_free_rss_dma(ha);
178 qls_free_mpi_dma(ha);
179 qls_free_tx_dma(ha);
180 qls_free_rx_dma(ha);
181 return;
182 }
183
184 /*
185 * Name: qls_alloc_dma
186 * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
187 */
188 int
189 qls_alloc_dma(qla_host_t *ha)
190 {
191 if (qls_alloc_rx_dma(ha))
192 return (-1);
193
194 if (qls_alloc_tx_dma(ha)) {
195 qls_free_rx_dma(ha);
196 return (-1);
197 }
198
199 if (qls_alloc_mpi_dma(ha)) {
200 qls_free_tx_dma(ha);
201 qls_free_rx_dma(ha);
202 return (-1);
203 }
204
205 if (qls_alloc_rss_dma(ha)) {
206 qls_free_mpi_dma(ha);
207 qls_free_tx_dma(ha);
208 qls_free_rx_dma(ha);
209 return (-1);
210 }
211
212 return (0);
213 }
214
215 static int
216 qls_wait_for_mac_proto_idx_ready(qla_host_t *ha, uint32_t op)
217 {
218 uint32_t data32;
219 uint32_t count = 3;
220
221 while (count--) {
222 data32 = READ_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX);
223
224 if (data32 & op)
225 return (0);
226
227 QLA_USEC_DELAY(100);
228 }
229 ha->qla_initiate_recovery = 1;
230 return (-1);
231 }
232
233 /*
234 * Name: qls_config_unicast_mac_addr
235 * Function: binds/unbinds a unicast MAC address to the interface.
236 */
237 static int
238 qls_config_unicast_mac_addr(qla_host_t *ha, uint32_t add_mac)
239 {
240 int ret = 0;
241 uint32_t mac_upper = 0;
242 uint32_t mac_lower = 0;
243 uint32_t value = 0, index;
244
245 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_MAC_SERDES,
246 Q81_CTL_SEM_SET_MAC_SERDES)) {
247 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
248 return(-1);
249 }
250
251 if (add_mac) {
252 mac_upper = (ha->mac_addr[0] << 8) | ha->mac_addr[1];
253 mac_lower = (ha->mac_addr[2] << 24) | (ha->mac_addr[3] << 16) |
254 (ha->mac_addr[4] << 8) | ha->mac_addr[5];
255 }
256 ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
257 if (ret)
258 goto qls_config_unicast_mac_addr_exit;
259
260 index = 128 * (ha->pci_func & 0x1); /* index */
261
262 value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
263 Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC;
264
265 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
266 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_lower);
267
268 ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
269 if (ret)
270 goto qls_config_unicast_mac_addr_exit;
271
272 value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
273 Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC | 0x1;
274
275 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
276 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_upper);
277
278 ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
279 if (ret)
280 goto qls_config_unicast_mac_addr_exit;
281
282 value = (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
283 Q81_CTL_MAC_PROTO_AI_TYPE_CAM_MAC | 0x2;
284
285 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
286
287 value = Q81_CAM_MAC_OFF2_ROUTE_NIC |
288 ((ha->pci_func & 0x1) << Q81_CAM_MAC_OFF2_FUNC_SHIFT) |
289 (0 << Q81_CAM_MAC_OFF2_CQID_SHIFT);
290
291 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, value);
292
293 qls_config_unicast_mac_addr_exit:
294 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_MAC_SERDES);
295 return (ret);
296 }
297
298 /*
299 * Name: qls_config_mcast_mac_addr
300 * Function: binds/unbinds a multicast MAC address to the interface.
301 */
302 static int
303 qls_config_mcast_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac,
304 uint32_t index)
305 {
306 int ret = 0;
307 uint32_t mac_upper = 0;
308 uint32_t mac_lower = 0;
309 uint32_t value = 0;
310
311 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_MAC_SERDES,
312 Q81_CTL_SEM_SET_MAC_SERDES)) {
313 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
314 return(-1);
315 }
316
317 if (add_mac) {
318 mac_upper = (mac_addr[0] << 8) | mac_addr[1];
319 mac_lower = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
320 (mac_addr[4] << 8) | mac_addr[5];
321 }
322 ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
323 if (ret)
324 goto qls_config_mcast_mac_addr_exit;
325
326 value = Q81_CTL_MAC_PROTO_AI_E |
327 (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
328 Q81_CTL_MAC_PROTO_AI_TYPE_MCAST ;
329
330 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
331 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_lower);
332
333 ret = qls_wait_for_mac_proto_idx_ready(ha, Q81_CTL_MAC_PROTO_AI_MW);
334 if (ret)
335 goto qls_config_mcast_mac_addr_exit;
336
337 value = Q81_CTL_MAC_PROTO_AI_E |
338 (index << Q81_CTL_MAC_PROTO_AI_IDX_SHIFT) |
339 Q81_CTL_MAC_PROTO_AI_TYPE_MCAST | 0x1;
340
341 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_INDEX, value);
342 WRITE_REG32(ha, Q81_CTL_MAC_PROTO_ADDR_DATA, mac_upper);
343
344 qls_config_mcast_mac_addr_exit:
345 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_MAC_SERDES);
346
347 return (ret);
348 }
349
350 /*
351 * Name: qls_set_mac_rcv_mode
352 * Function: Enable/Disable AllMulticast and Promiscuous Modes.
353 */
354 static int
355 qls_wait_for_route_idx_ready(qla_host_t *ha, uint32_t op)
356 {
357 uint32_t data32;
358 uint32_t count = 3;
359
360 while (count--) {
361 data32 = READ_REG32(ha, Q81_CTL_ROUTING_INDEX);
362
363 if (data32 & op)
364 return (0);
365
366 QLA_USEC_DELAY(100);
367 }
368 ha->qla_initiate_recovery = 1;
369 return (-1);
370 }
371
372 static int
373 qls_load_route_idx_reg(qla_host_t *ha, uint32_t index, uint32_t data)
374 {
375 int ret = 0;
376
377 ret = qls_wait_for_route_idx_ready(ha, Q81_CTL_RI_MW);
378
379 if (ret) {
380 device_printf(ha->pci_dev, "%s: [0x%08x, 0x%08x] failed\n",
381 __func__, index, data);
382 goto qls_load_route_idx_reg_exit;
383 }
384
385 WRITE_REG32(ha, Q81_CTL_ROUTING_INDEX, index);
386 WRITE_REG32(ha, Q81_CTL_ROUTING_DATA, data);
387
388 qls_load_route_idx_reg_exit:
389 return (ret);
390 }
391
392 static int
393 qls_load_route_idx_reg_locked(qla_host_t *ha, uint32_t index, uint32_t data)
394 {
395 int ret = 0;
396
397 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
398 Q81_CTL_SEM_SET_RIDX_DATAREG)) {
399 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
400 return(-1);
401 }
402
403 ret = qls_load_route_idx_reg(ha, index, data);
404
405 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
406
407 return (ret);
408 }
409
410 static int
411 qls_clear_routing_table(qla_host_t *ha)
412 {
413 int i, ret = 0;
414
415 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
416 Q81_CTL_SEM_SET_RIDX_DATAREG)) {
417 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
418 return(-1);
419 }
420
421 for (i = 0; i < 16; i++) {
422 ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_TYPE_NICQMASK|
423 (i << 8) | Q81_CTL_RI_DST_DFLTQ), 0);
424 if (ret)
425 break;
426 }
427
428 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
429
430 return (ret);
431 }
432
433 int
434 qls_set_promisc(qla_host_t *ha)
435 {
436 int ret;
437
438 ret = qls_load_route_idx_reg_locked(ha,
439 (Q81_CTL_RI_E | Q81_CTL_RI_TYPE_NICQMASK |
440 Q81_CTL_RI_IDX_PROMISCUOUS | Q81_CTL_RI_DST_DFLTQ),
441 Q81_CTL_RD_VALID_PKT);
442 return (ret);
443 }
444
445 void
446 qls_reset_promisc(qla_host_t *ha)
447 {
448 qls_load_route_idx_reg_locked(ha, (Q81_CTL_RI_TYPE_NICQMASK |
449 Q81_CTL_RI_IDX_PROMISCUOUS | Q81_CTL_RI_DST_DFLTQ), 0);
450 return;
451 }
452
453 int
454 qls_set_allmulti(qla_host_t *ha)
455 {
456 int ret;
457
458 ret = qls_load_route_idx_reg_locked(ha,
459 (Q81_CTL_RI_E | Q81_CTL_RI_TYPE_NICQMASK |
460 Q81_CTL_RI_IDX_ALLMULTI | Q81_CTL_RI_DST_DFLTQ),
461 Q81_CTL_RD_MCAST);
462 return (ret);
463 }
464
465 void
466 qls_reset_allmulti(qla_host_t *ha)
467 {
468 qls_load_route_idx_reg_locked(ha, (Q81_CTL_RI_TYPE_NICQMASK |
469 Q81_CTL_RI_IDX_ALLMULTI | Q81_CTL_RI_DST_DFLTQ), 0);
470 return;
471 }
472
473 static int
474 qls_init_fw_routing_table(qla_host_t *ha)
475 {
476 int ret = 0;
477
478 ret = qls_clear_routing_table(ha);
479 if (ret)
480 return (-1);
481
482 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG,
483 Q81_CTL_SEM_SET_RIDX_DATAREG)) {
484 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
485 return(-1);
486 }
487
488 ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DROP |
489 Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_ALL_ERROR),
490 Q81_CTL_RD_ERROR_PKT);
491 if (ret)
492 goto qls_init_fw_routing_table_exit;
493
494 ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
495 Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_BCAST),
496 Q81_CTL_RD_BCAST);
497 if (ret)
498 goto qls_init_fw_routing_table_exit;
499
500 if (ha->num_rx_rings > 1 ) {
501 ret = qls_load_route_idx_reg(ha,
502 (Q81_CTL_RI_E | Q81_CTL_RI_DST_RSS |
503 Q81_CTL_RI_TYPE_NICQMASK |
504 Q81_CTL_RI_IDX_RSS_MATCH),
505 Q81_CTL_RD_RSS_MATCH);
506 if (ret)
507 goto qls_init_fw_routing_table_exit;
508 }
509
510 ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
511 Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_MCAST_MATCH),
512 Q81_CTL_RD_MCAST_REG_MATCH);
513 if (ret)
514 goto qls_init_fw_routing_table_exit;
515
516 ret = qls_load_route_idx_reg(ha, (Q81_CTL_RI_E | Q81_CTL_RI_DST_DFLTQ |
517 Q81_CTL_RI_TYPE_NICQMASK | Q81_CTL_RI_IDX_CAM_HIT),
518 Q81_CTL_RD_CAM_HIT);
519 if (ret)
520 goto qls_init_fw_routing_table_exit;
521
522 qls_init_fw_routing_table_exit:
523 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_RIDX_DATAREG);
524 return (ret);
525 }
526
527 static int
528 qls_tx_tso_chksum(qla_host_t *ha, struct mbuf *mp, q81_tx_tso_t *tx_mac)
529 {
530 #if defined(INET) || defined(INET6)
531 struct ether_vlan_header *eh;
532 struct ip *ip;
533 #if defined(INET6)
534 struct ip6_hdr *ip6;
535 #endif
536 struct tcphdr *th;
537 uint32_t ehdrlen, ip_hlen;
538 int ret = 0;
539 uint16_t etype;
540 uint8_t buf[sizeof(struct ip6_hdr)];
541
542 eh = mtod(mp, struct ether_vlan_header *);
543
544 if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
545 ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
546 etype = ntohs(eh->evl_proto);
547 } else {
548 ehdrlen = ETHER_HDR_LEN;
549 etype = ntohs(eh->evl_encap_proto);
550 }
551
552 switch (etype) {
553 #ifdef INET
554 case ETHERTYPE_IP:
555 ip = (struct ip *)(mp->m_data + ehdrlen);
556
557 ip_hlen = sizeof (struct ip);
558
559 if (mp->m_len < (ehdrlen + ip_hlen)) {
560 m_copydata(mp, ehdrlen, sizeof(struct ip), buf);
561 ip = (struct ip *)buf;
562 }
563 tx_mac->opcode = Q81_IOCB_TX_TSO;
564 tx_mac->flags |= Q81_TX_TSO_FLAGS_IPV4 ;
565
566 tx_mac->phdr_offsets = ehdrlen;
567
568 tx_mac->phdr_offsets |= ((ehdrlen + ip_hlen) <<
569 Q81_TX_TSO_PHDR_SHIFT);
570
571 ip->ip_sum = 0;
572
573 if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
574 tx_mac->flags |= Q81_TX_TSO_FLAGS_LSO;
575
576 th = (struct tcphdr *)(ip + 1);
577
578 th->th_sum = in_pseudo(ip->ip_src.s_addr,
579 ip->ip_dst.s_addr,
580 htons(IPPROTO_TCP));
581 tx_mac->mss = mp->m_pkthdr.tso_segsz;
582 tx_mac->phdr_length = ip_hlen + ehdrlen +
583 (th->th_off << 2);
584 break;
585 }
586 tx_mac->vlan_off |= Q81_TX_TSO_VLAN_OFF_IC ;
587
588 if (ip->ip_p == IPPROTO_TCP) {
589 tx_mac->flags |= Q81_TX_TSO_FLAGS_TC;
590 } else if (ip->ip_p == IPPROTO_UDP) {
591 tx_mac->flags |= Q81_TX_TSO_FLAGS_UC;
592 }
593 break;
594 #endif
595
596 #ifdef INET6
597 case ETHERTYPE_IPV6:
598 ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
599
600 ip_hlen = sizeof(struct ip6_hdr);
601
602 if (mp->m_len < (ehdrlen + ip_hlen)) {
603 m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr),
604 buf);
605 ip6 = (struct ip6_hdr *)buf;
606 }
607
608 tx_mac->opcode = Q81_IOCB_TX_TSO;
609 tx_mac->flags |= Q81_TX_TSO_FLAGS_IPV6 ;
610 tx_mac->vlan_off |= Q81_TX_TSO_VLAN_OFF_IC ;
611
612 tx_mac->phdr_offsets = ehdrlen;
613 tx_mac->phdr_offsets |= ((ehdrlen + ip_hlen) <<
614 Q81_TX_TSO_PHDR_SHIFT);
615
616 if (ip6->ip6_nxt == IPPROTO_TCP) {
617 tx_mac->flags |= Q81_TX_TSO_FLAGS_TC;
618 } else if (ip6->ip6_nxt == IPPROTO_UDP) {
619 tx_mac->flags |= Q81_TX_TSO_FLAGS_UC;
620 }
621 break;
622 #endif
623
624 default:
625 ret = -1;
626 break;
627 }
628
629 return (ret);
630 #else
631 return (-1);
632 #endif
633 }
634
635 #define QLA_TX_MIN_FREE 2
636 int
637 qls_hw_tx_done(qla_host_t *ha, uint32_t txr_idx)
638 {
639 uint32_t txr_done, txr_next;
640
641 txr_done = ha->tx_ring[txr_idx].txr_done;
642 txr_next = ha->tx_ring[txr_idx].txr_next;
643
644 if (txr_done == txr_next) {
645 ha->tx_ring[txr_idx].txr_free = NUM_TX_DESCRIPTORS;
646 } else if (txr_done > txr_next) {
647 ha->tx_ring[txr_idx].txr_free = txr_done - txr_next;
648 } else {
649 ha->tx_ring[txr_idx].txr_free = NUM_TX_DESCRIPTORS +
650 txr_done - txr_next;
651 }
652
653 if (ha->tx_ring[txr_idx].txr_free <= QLA_TX_MIN_FREE)
654 return (-1);
655
656 return (0);
657 }
658
659 /*
660 * Name: qls_hw_send
661 * Function: Transmits a packet. It first checks if the packet is a
662 * candidate for Large TCP Segment Offload and then for UDP/TCP checksum
663 * offload. If either of these creteria are not met, it is transmitted
664 * as a regular ethernet frame.
665 */
666 int
667 qls_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
668 uint32_t txr_next, struct mbuf *mp, uint32_t txr_idx)
669 {
670 q81_tx_mac_t *tx_mac;
671 q81_txb_desc_t *tx_desc;
672 uint32_t total_length = 0;
673 uint32_t i;
674 device_t dev;
675 int ret = 0;
676
677 dev = ha->pci_dev;
678
679 total_length = mp->m_pkthdr.len;
680
681 if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
682 device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
683 __func__, total_length);
684 return (-1);
685 }
686
687 if (ha->tx_ring[txr_idx].txr_free <= (NUM_TX_DESCRIPTORS >> 2)) {
688 if (qls_hw_tx_done(ha, txr_idx)) {
689 device_printf(dev, "%s: tx_free[%d] = %d\n",
690 __func__, txr_idx,
691 ha->tx_ring[txr_idx].txr_free);
692 return (-1);
693 }
694 }
695
696 tx_mac = (q81_tx_mac_t *)&ha->tx_ring[txr_idx].wq_vaddr[txr_next];
697
698 bzero(tx_mac, sizeof(q81_tx_mac_t));
699
700 if ((mp->m_pkthdr.csum_flags &
701 (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO)) != 0) {
702 ret = qls_tx_tso_chksum(ha, mp, (q81_tx_tso_t *)tx_mac);
703 if (ret)
704 return (EINVAL);
705
706 if (mp->m_pkthdr.csum_flags & CSUM_TSO)
707 ha->tx_ring[txr_idx].tx_tso_frames++;
708 else
709 ha->tx_ring[txr_idx].tx_frames++;
710
711 } else {
712 tx_mac->opcode = Q81_IOCB_TX_MAC;
713 }
714
715 if (mp->m_flags & M_VLANTAG) {
716 tx_mac->vlan_tci = mp->m_pkthdr.ether_vtag;
717 tx_mac->vlan_off |= Q81_TX_MAC_VLAN_OFF_V;
718
719 ha->tx_ring[txr_idx].tx_vlan_frames++;
720 }
721
722 tx_mac->frame_length = total_length;
723
724 tx_mac->tid_lo = txr_next;
725
726 if (nsegs <= MAX_TX_MAC_DESC) {
727 QL_DPRINT2((dev, "%s: 1 [%d, %d]\n", __func__, total_length,
728 tx_mac->tid_lo));
729
730 for (i = 0; i < nsegs; i++) {
731 tx_mac->txd[i].baddr = segs->ds_addr;
732 tx_mac->txd[i].length = segs->ds_len;
733 segs++;
734 }
735 tx_mac->txd[(nsegs - 1)].flags = Q81_RXB_DESC_FLAGS_E;
736
737 } else {
738 QL_DPRINT2((dev, "%s: 2 [%d, %d]\n", __func__, total_length,
739 tx_mac->tid_lo));
740
741 tx_mac->txd[0].baddr =
742 ha->tx_ring[txr_idx].tx_buf[txr_next].oal_paddr;
743 tx_mac->txd[0].length =
744 nsegs * (sizeof(q81_txb_desc_t));
745 tx_mac->txd[0].flags = Q81_RXB_DESC_FLAGS_C;
746
747 tx_desc = ha->tx_ring[txr_idx].tx_buf[txr_next].oal_vaddr;
748
749 for (i = 0; i < nsegs; i++) {
750 tx_desc->baddr = segs->ds_addr;
751 tx_desc->length = segs->ds_len;
752
753 if (i == (nsegs -1))
754 tx_desc->flags = Q81_RXB_DESC_FLAGS_E;
755 else
756 tx_desc->flags = 0;
757
758 segs++;
759 tx_desc++;
760 }
761 }
762 txr_next = (txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
763 ha->tx_ring[txr_idx].txr_next = txr_next;
764
765 ha->tx_ring[txr_idx].txr_free--;
766
767 Q81_WR_WQ_PROD_IDX(txr_idx, txr_next);
768
769 return (0);
770 }
771
772 /*
773 * Name: qls_del_hw_if
774 * Function: Destroys the hardware specific entities corresponding to an
775 * Ethernet Interface
776 */
777 void
778 qls_del_hw_if(qla_host_t *ha)
779 {
780 uint32_t value;
781 int i;
782 //int count;
783
784 if (ha->hw_init == 0) {
785 qls_hw_reset(ha);
786 return;
787 }
788
789 for (i = 0; i < ha->num_tx_rings; i++) {
790 Q81_SET_WQ_INVALID(i);
791 }
792 for (i = 0; i < ha->num_rx_rings; i++) {
793 Q81_SET_CQ_INVALID(i);
794 }
795
796 for (i = 0; i < ha->num_rx_rings; i++) {
797 Q81_DISABLE_INTR(ha, i); /* MSI-x i */
798 }
799
800 value = (Q81_CTL_INTRE_IHD << Q81_CTL_INTRE_MASK_SHIFT);
801 WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
802
803 value = (Q81_CTL_INTRE_EI << Q81_CTL_INTRE_MASK_SHIFT);
804 WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
805 ha->flags.intr_enable = 0;
806
807 qls_hw_reset(ha);
808
809 return;
810 }
811
812 /*
813 * Name: qls_init_hw_if
814 * Function: Creates the hardware specific entities corresponding to an
815 * Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
816 * corresponding to the interface. Enables LRO if allowed.
817 */
818 int
819 qls_init_hw_if(qla_host_t *ha)
820 {
821 uint32_t value;
822 int ret = 0;
823 int i;
824
825 QL_DPRINT2((ha->pci_dev, "%s:enter\n", __func__));
826
827 ret = qls_hw_reset(ha);
828 if (ret)
829 goto qls_init_hw_if_exit;
830
831 ha->vm_pgsize = 4096;
832
833 /* Enable FAE and EFE bits in System Register */
834 value = Q81_CTL_SYSTEM_ENABLE_FAE | Q81_CTL_SYSTEM_ENABLE_EFE;
835 value = (value << Q81_CTL_SYSTEM_MASK_SHIFT) | value;
836
837 WRITE_REG32(ha, Q81_CTL_SYSTEM, value);
838
839 /* Set Default Completion Queue_ID in NIC Rcv Configuration Register */
840 value = (Q81_CTL_NIC_RCVC_DCQ_MASK << Q81_CTL_NIC_RCVC_MASK_SHIFT);
841 WRITE_REG32(ha, Q81_CTL_NIC_RCV_CONFIG, value);
842
843 /* Function Specific Control Register - Set Page Size and Enable NIC */
844 value = Q81_CTL_FUNC_SPECIFIC_FE |
845 Q81_CTL_FUNC_SPECIFIC_VM_PGSIZE_MASK |
846 Q81_CTL_FUNC_SPECIFIC_EPC_O |
847 Q81_CTL_FUNC_SPECIFIC_EPC_I |
848 Q81_CTL_FUNC_SPECIFIC_EC;
849 value = (value << Q81_CTL_FUNC_SPECIFIC_MASK_SHIFT) |
850 Q81_CTL_FUNC_SPECIFIC_FE |
851 Q81_CTL_FUNC_SPECIFIC_VM_PGSIZE_4K |
852 Q81_CTL_FUNC_SPECIFIC_EPC_O |
853 Q81_CTL_FUNC_SPECIFIC_EPC_I |
854 Q81_CTL_FUNC_SPECIFIC_EC;
855
856 WRITE_REG32(ha, Q81_CTL_FUNC_SPECIFIC, value);
857
858 /* Interrupt Mask Register */
859 value = Q81_CTL_INTRM_PI;
860 value = (value << Q81_CTL_INTRM_MASK_SHIFT) | value;
861
862 WRITE_REG32(ha, Q81_CTL_INTR_MASK, value);
863
864 /* Initialiatize Completion Queue */
865 for (i = 0; i < ha->num_rx_rings; i++) {
866 ret = qls_init_comp_queue(ha, i);
867 if (ret)
868 goto qls_init_hw_if_exit;
869 }
870
871 if (ha->num_rx_rings > 1 ) {
872 ret = qls_init_rss(ha);
873 if (ret)
874 goto qls_init_hw_if_exit;
875 }
876
877 /* Initialize Work Queue */
878
879 for (i = 0; i < ha->num_tx_rings; i++) {
880 ret = qls_init_work_queue(ha, i);
881 if (ret)
882 goto qls_init_hw_if_exit;
883 }
884
885 if (ret)
886 goto qls_init_hw_if_exit;
887
888 /* Set up CAM RAM with MAC Address */
889 ret = qls_config_unicast_mac_addr(ha, 1);
890 if (ret)
891 goto qls_init_hw_if_exit;
892
893 ret = qls_hw_add_all_mcast(ha);
894 if (ret)
895 goto qls_init_hw_if_exit;
896
897 /* Initialize Firmware Routing Table */
898 ret = qls_init_fw_routing_table(ha);
899 if (ret)
900 goto qls_init_hw_if_exit;
901
902 /* Get Chip Revision ID */
903 ha->rev_id = READ_REG32(ha, Q81_CTL_REV_ID);
904
905 /* Enable Global Interrupt */
906 value = Q81_CTL_INTRE_EI;
907 value = (value << Q81_CTL_INTRE_MASK_SHIFT) | value;
908
909 WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
910
911 /* Enable Interrupt Handshake Disable */
912 value = Q81_CTL_INTRE_IHD;
913 value = (value << Q81_CTL_INTRE_MASK_SHIFT) | value;
914
915 WRITE_REG32(ha, Q81_CTL_INTR_ENABLE, value);
916
917 /* Enable Completion Interrupt */
918
919 ha->flags.intr_enable = 1;
920
921 for (i = 0; i < ha->num_rx_rings; i++) {
922 Q81_ENABLE_INTR(ha, i); /* MSI-x i */
923 }
924
925 ha->hw_init = 1;
926
927 qls_mbx_get_link_status(ha);
928
929 QL_DPRINT2((ha->pci_dev, "%s:rxr [0x%08x]\n", __func__,
930 ha->rx_ring[0].cq_db_offset));
931 QL_DPRINT2((ha->pci_dev, "%s:txr [0x%08x]\n", __func__,
932 ha->tx_ring[0].wq_db_offset));
933
934 for (i = 0; i < ha->num_rx_rings; i++) {
935 Q81_WR_CQ_CONS_IDX(i, 0);
936 Q81_WR_LBQ_PROD_IDX(i, ha->rx_ring[i].lbq_in);
937 Q81_WR_SBQ_PROD_IDX(i, ha->rx_ring[i].sbq_in);
938
939 QL_DPRINT2((ha->pci_dev,
940 "%s: [wq_idx, cq_idx, lbq_idx, sbq_idx]"
941 "[0x%08x, 0x%08x, 0x%08x, 0x%08x]\n", __func__,
942 Q81_RD_WQ_IDX(i), Q81_RD_CQ_IDX(i), Q81_RD_LBQ_IDX(i),
943 Q81_RD_SBQ_IDX(i)));
944 }
945
946 for (i = 0; i < ha->num_rx_rings; i++) {
947 Q81_SET_CQ_VALID(i);
948 }
949
950 qls_init_hw_if_exit:
951 QL_DPRINT2((ha->pci_dev, "%s:exit\n", __func__));
952 return (ret);
953 }
954
955 static int
956 qls_wait_for_config_reg_bits(qla_host_t *ha, uint32_t bits, uint32_t value)
957 {
958 uint32_t data32;
959 uint32_t count = 3;
960
961 while (count--) {
962 data32 = READ_REG32(ha, Q81_CTL_CONFIG);
963
964 if ((data32 & bits) == value)
965 return (0);
966
967 QLA_USEC_DELAY(100);
968 }
969 ha->qla_initiate_recovery = 1;
970 device_printf(ha->pci_dev, "%s: failed\n", __func__);
971 return (-1);
972 }
973
974 static uint8_t q81_hash_key[] = {
975 0xda, 0x56, 0x5a, 0x6d,
976 0xc2, 0x0e, 0x5b, 0x25,
977 0x3d, 0x25, 0x67, 0x41,
978 0xb0, 0x8f, 0xa3, 0x43,
979 0xcb, 0x2b, 0xca, 0xd0,
980 0xb4, 0x30, 0x7b, 0xae,
981 0xa3, 0x2d, 0xcb, 0x77,
982 0x0c, 0xf2, 0x30, 0x80,
983 0x3b, 0xb7, 0x42, 0x6a,
984 0xfa, 0x01, 0xac, 0xbe };
985
986 static int
987 qls_init_rss(qla_host_t *ha)
988 {
989 q81_rss_icb_t *rss_icb;
990 int ret = 0;
991 int i;
992 uint32_t value;
993
994 rss_icb = ha->rss_dma.dma_b;
995
996 bzero(rss_icb, sizeof (q81_rss_icb_t));
997
998 rss_icb->flags_base_cq_num = Q81_RSS_ICB_FLAGS_L4K |
999 Q81_RSS_ICB_FLAGS_L6K | Q81_RSS_ICB_FLAGS_LI |
1000 Q81_RSS_ICB_FLAGS_LB | Q81_RSS_ICB_FLAGS_LM |
1001 Q81_RSS_ICB_FLAGS_RT4 | Q81_RSS_ICB_FLAGS_RT6;
1002
1003 rss_icb->mask = 0x3FF;
1004
1005 for (i = 0; i < Q81_RSS_ICB_NUM_INDTBL_ENTRIES; i++) {
1006 rss_icb->cq_id[i] = (i & (ha->num_rx_rings - 1));
1007 }
1008
1009 memcpy(rss_icb->ipv6_rss_hash_key, q81_hash_key, 40);
1010 memcpy(rss_icb->ipv4_rss_hash_key, q81_hash_key, 16);
1011
1012 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LR, 0);
1013
1014 if (ret)
1015 goto qls_init_rss_exit;
1016
1017 ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1018
1019 if (ret) {
1020 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1021 goto qls_init_rss_exit;
1022 }
1023
1024 value = (uint32_t)ha->rss_dma.dma_addr;
1025 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1026
1027 value = (uint32_t)(ha->rss_dma.dma_addr >> 32);
1028 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1029
1030 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1031
1032 value = (Q81_CTL_CONFIG_LR << Q81_CTL_CONFIG_MASK_SHIFT) |
1033 Q81_CTL_CONFIG_LR;
1034
1035 WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1036
1037 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LR, 0);
1038
1039 qls_init_rss_exit:
1040 return (ret);
1041 }
1042
1043 static int
1044 qls_init_comp_queue(qla_host_t *ha, int cid)
1045 {
1046 q81_cq_icb_t *cq_icb;
1047 qla_rx_ring_t *rxr;
1048 int ret = 0;
1049 uint32_t value;
1050
1051 rxr = &ha->rx_ring[cid];
1052
1053 rxr->cq_db_offset = ha->vm_pgsize * (128 + cid);
1054
1055 cq_icb = rxr->cq_icb_vaddr;
1056
1057 bzero(cq_icb, sizeof (q81_cq_icb_t));
1058
1059 cq_icb->msix_vector = cid;
1060 cq_icb->flags = Q81_CQ_ICB_FLAGS_LC |
1061 Q81_CQ_ICB_FLAGS_LI |
1062 Q81_CQ_ICB_FLAGS_LL |
1063 Q81_CQ_ICB_FLAGS_LS |
1064 Q81_CQ_ICB_FLAGS_LV;
1065
1066 cq_icb->length_v = NUM_CQ_ENTRIES;
1067
1068 cq_icb->cq_baddr_lo = (rxr->cq_base_paddr & 0xFFFFFFFF);
1069 cq_icb->cq_baddr_hi = (rxr->cq_base_paddr >> 32) & 0xFFFFFFFF;
1070
1071 cq_icb->cqi_addr_lo = (rxr->cqi_paddr & 0xFFFFFFFF);
1072 cq_icb->cqi_addr_hi = (rxr->cqi_paddr >> 32) & 0xFFFFFFFF;
1073
1074 cq_icb->pkt_idelay = 10;
1075 cq_icb->idelay = 100;
1076
1077 cq_icb->lbq_baddr_lo = (rxr->lbq_addr_tbl_paddr & 0xFFFFFFFF);
1078 cq_icb->lbq_baddr_hi = (rxr->lbq_addr_tbl_paddr >> 32) & 0xFFFFFFFF;
1079
1080 cq_icb->lbq_bsize = QLA_LGB_SIZE;
1081 cq_icb->lbq_length = QLA_NUM_LGB_ENTRIES;
1082
1083 cq_icb->sbq_baddr_lo = (rxr->sbq_addr_tbl_paddr & 0xFFFFFFFF);
1084 cq_icb->sbq_baddr_hi = (rxr->sbq_addr_tbl_paddr >> 32) & 0xFFFFFFFF;
1085
1086 cq_icb->sbq_bsize = (uint16_t)ha->msize;
1087 cq_icb->sbq_length = QLA_NUM_SMB_ENTRIES;
1088
1089 QL_DUMP_CQ(ha);
1090
1091 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LCQ, 0);
1092
1093 if (ret)
1094 goto qls_init_comp_queue_exit;
1095
1096 ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1097
1098 if (ret) {
1099 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1100 goto qls_init_comp_queue_exit;
1101 }
1102
1103 value = (uint32_t)rxr->cq_icb_paddr;
1104 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1105
1106 value = (uint32_t)(rxr->cq_icb_paddr >> 32);
1107 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1108
1109 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1110
1111 value = Q81_CTL_CONFIG_LCQ | Q81_CTL_CONFIG_Q_NUM_MASK;
1112 value = (value << Q81_CTL_CONFIG_MASK_SHIFT) | Q81_CTL_CONFIG_LCQ;
1113 value |= (cid << Q81_CTL_CONFIG_Q_NUM_SHIFT);
1114 WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1115
1116 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LCQ, 0);
1117
1118 rxr->cq_next = 0;
1119 rxr->lbq_next = rxr->lbq_free = 0;
1120 rxr->sbq_next = rxr->sbq_free = 0;
1121 rxr->rx_free = rxr->rx_next = 0;
1122 rxr->lbq_in = (QLA_NUM_LGB_ENTRIES - 1) & ~0xF;
1123 rxr->sbq_in = (QLA_NUM_SMB_ENTRIES - 1) & ~0xF;
1124
1125 qls_init_comp_queue_exit:
1126 return (ret);
1127 }
1128
1129 static int
1130 qls_init_work_queue(qla_host_t *ha, int wid)
1131 {
1132 q81_wq_icb_t *wq_icb;
1133 qla_tx_ring_t *txr;
1134 int ret = 0;
1135 uint32_t value;
1136
1137 txr = &ha->tx_ring[wid];
1138
1139 txr->wq_db_addr = (struct resource *)((uint8_t *)ha->pci_reg1
1140 + (ha->vm_pgsize * wid));
1141
1142 txr->wq_db_offset = (ha->vm_pgsize * wid);
1143
1144 wq_icb = txr->wq_icb_vaddr;
1145 bzero(wq_icb, sizeof (q81_wq_icb_t));
1146
1147 wq_icb->length_v = NUM_TX_DESCRIPTORS |
1148 Q81_WQ_ICB_VALID;
1149
1150 wq_icb->flags = Q81_WQ_ICB_FLAGS_LO | Q81_WQ_ICB_FLAGS_LI |
1151 Q81_WQ_ICB_FLAGS_LB | Q81_WQ_ICB_FLAGS_LC;
1152
1153 wq_icb->wqcqid_rss = wid;
1154
1155 wq_icb->baddr_lo = txr->wq_paddr & 0xFFFFFFFF;
1156 wq_icb->baddr_hi = (txr->wq_paddr >> 32)& 0xFFFFFFFF;
1157
1158 wq_icb->ci_addr_lo = txr->txr_cons_paddr & 0xFFFFFFFF;
1159 wq_icb->ci_addr_hi = (txr->txr_cons_paddr >> 32)& 0xFFFFFFFF;
1160
1161 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LRQ, 0);
1162
1163 if (ret)
1164 goto qls_init_wq_exit;
1165
1166 ret = qls_sem_lock(ha, Q81_CTL_SEM_MASK_ICB, Q81_CTL_SEM_SET_ICB);
1167
1168 if (ret) {
1169 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1170 goto qls_init_wq_exit;
1171 }
1172
1173 value = (uint32_t)txr->wq_icb_paddr;
1174 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_LO, value);
1175
1176 value = (uint32_t)(txr->wq_icb_paddr >> 32);
1177 WRITE_REG32(ha, Q81_CTL_ICB_ACCESS_ADDR_HI, value);
1178
1179 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_ICB);
1180
1181 value = Q81_CTL_CONFIG_LRQ | Q81_CTL_CONFIG_Q_NUM_MASK;
1182 value = (value << Q81_CTL_CONFIG_MASK_SHIFT) | Q81_CTL_CONFIG_LRQ;
1183 value |= (wid << Q81_CTL_CONFIG_Q_NUM_SHIFT);
1184 WRITE_REG32(ha, Q81_CTL_CONFIG, value);
1185
1186 ret = qls_wait_for_config_reg_bits(ha, Q81_CTL_CONFIG_LRQ, 0);
1187
1188 txr->txr_free = NUM_TX_DESCRIPTORS;
1189 txr->txr_next = 0;
1190 txr->txr_done = 0;
1191
1192 qls_init_wq_exit:
1193 return (ret);
1194 }
1195
1196 static int
1197 qls_hw_add_all_mcast(qla_host_t *ha)
1198 {
1199 int i, nmcast;
1200
1201 nmcast = ha->nmcast;
1202
1203 for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
1204 if ((ha->mcast[i].addr[0] != 0) ||
1205 (ha->mcast[i].addr[1] != 0) ||
1206 (ha->mcast[i].addr[2] != 0) ||
1207 (ha->mcast[i].addr[3] != 0) ||
1208 (ha->mcast[i].addr[4] != 0) ||
1209 (ha->mcast[i].addr[5] != 0)) {
1210 if (qls_config_mcast_mac_addr(ha, ha->mcast[i].addr,
1211 1, i)) {
1212 device_printf(ha->pci_dev, "%s: failed\n",
1213 __func__);
1214 return (-1);
1215 }
1216
1217 nmcast--;
1218 }
1219 }
1220 return 0;
1221 }
1222
1223 static int
1224 qls_hw_add_mcast(qla_host_t *ha, uint8_t *mta)
1225 {
1226 int i;
1227
1228 for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1229 if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0)
1230 return 0; /* its been already added */
1231 }
1232
1233 for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1234 if ((ha->mcast[i].addr[0] == 0) &&
1235 (ha->mcast[i].addr[1] == 0) &&
1236 (ha->mcast[i].addr[2] == 0) &&
1237 (ha->mcast[i].addr[3] == 0) &&
1238 (ha->mcast[i].addr[4] == 0) &&
1239 (ha->mcast[i].addr[5] == 0)) {
1240 if (qls_config_mcast_mac_addr(ha, mta, 1, i))
1241 return (-1);
1242
1243 bcopy(mta, ha->mcast[i].addr, Q8_MAC_ADDR_LEN);
1244 ha->nmcast++;
1245
1246 return 0;
1247 }
1248 }
1249 return 0;
1250 }
1251
1252 static int
1253 qls_hw_del_mcast(qla_host_t *ha, uint8_t *mta)
1254 {
1255 int i;
1256
1257 for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
1258 if (QL_MAC_CMP(ha->mcast[i].addr, mta) == 0) {
1259 if (qls_config_mcast_mac_addr(ha, mta, 0, i))
1260 return (-1);
1261
1262 ha->mcast[i].addr[0] = 0;
1263 ha->mcast[i].addr[1] = 0;
1264 ha->mcast[i].addr[2] = 0;
1265 ha->mcast[i].addr[3] = 0;
1266 ha->mcast[i].addr[4] = 0;
1267 ha->mcast[i].addr[5] = 0;
1268
1269 ha->nmcast--;
1270
1271 return 0;
1272 }
1273 }
1274 return 0;
1275 }
1276
1277 /*
1278 * Name: qls_hw_set_multi
1279 * Function: Sets the Multicast Addresses provided the host O.S into the
1280 * hardware (for the given interface)
1281 */
1282 void
1283 qls_hw_set_multi(qla_host_t *ha, uint8_t *mta, uint32_t mcnt,
1284 uint32_t add_mac)
1285 {
1286 int i;
1287
1288 for (i = 0; i < mcnt; i++) {
1289 if (add_mac) {
1290 if (qls_hw_add_mcast(ha, mta))
1291 break;
1292 } else {
1293 if (qls_hw_del_mcast(ha, mta))
1294 break;
1295 }
1296
1297 mta += Q8_MAC_ADDR_LEN;
1298 }
1299 return;
1300 }
1301
1302 void
1303 qls_update_link_state(qla_host_t *ha)
1304 {
1305 uint32_t link_state;
1306 uint32_t prev_link_state;
1307
1308 if (!(ha->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1309 ha->link_up = 0;
1310 return;
1311 }
1312 link_state = READ_REG32(ha, Q81_CTL_STATUS);
1313
1314 prev_link_state = ha->link_up;
1315
1316 if ((ha->pci_func & 0x1) == 0)
1317 ha->link_up = ((link_state & Q81_CTL_STATUS_PL0)? 1 : 0);
1318 else
1319 ha->link_up = ((link_state & Q81_CTL_STATUS_PL1)? 1 : 0);
1320
1321 if (prev_link_state != ha->link_up) {
1322 if (ha->link_up) {
1323 if_link_state_change(ha->ifp, LINK_STATE_UP);
1324 } else {
1325 if_link_state_change(ha->ifp, LINK_STATE_DOWN);
1326 }
1327 }
1328 return;
1329 }
1330
1331 static void
1332 qls_free_tx_ring_dma(qla_host_t *ha, int r_idx)
1333 {
1334 if (ha->tx_ring[r_idx].flags.wq_dma) {
1335 qls_free_dmabuf(ha, &ha->tx_ring[r_idx].wq_dma);
1336 ha->tx_ring[r_idx].flags.wq_dma = 0;
1337 }
1338
1339 if (ha->tx_ring[r_idx].flags.privb_dma) {
1340 qls_free_dmabuf(ha, &ha->tx_ring[r_idx].privb_dma);
1341 ha->tx_ring[r_idx].flags.privb_dma = 0;
1342 }
1343 return;
1344 }
1345
1346 static void
1347 qls_free_tx_dma(qla_host_t *ha)
1348 {
1349 int i, j;
1350 qla_tx_buf_t *txb;
1351
1352 for (i = 0; i < ha->num_tx_rings; i++) {
1353 qls_free_tx_ring_dma(ha, i);
1354
1355 for (j = 0; j < NUM_TX_DESCRIPTORS; j++) {
1356 txb = &ha->tx_ring[i].tx_buf[j];
1357
1358 if (txb->map) {
1359 bus_dmamap_destroy(ha->tx_tag, txb->map);
1360 }
1361 }
1362 }
1363
1364 if (ha->tx_tag != NULL) {
1365 bus_dma_tag_destroy(ha->tx_tag);
1366 ha->tx_tag = NULL;
1367 }
1368
1369 return;
1370 }
1371
1372 static int
1373 qls_alloc_tx_ring_dma(qla_host_t *ha, int ridx)
1374 {
1375 int ret = 0, i;
1376 uint8_t *v_addr;
1377 bus_addr_t p_addr;
1378 qla_tx_buf_t *txb;
1379 device_t dev = ha->pci_dev;
1380
1381 ha->tx_ring[ridx].wq_dma.alignment = 8;
1382 ha->tx_ring[ridx].wq_dma.size =
1383 NUM_TX_DESCRIPTORS * (sizeof (q81_tx_cmd_t));
1384
1385 ret = qls_alloc_dmabuf(ha, &ha->tx_ring[ridx].wq_dma);
1386
1387 if (ret) {
1388 device_printf(dev, "%s: [%d] txr failed\n", __func__, ridx);
1389 goto qls_alloc_tx_ring_dma_exit;
1390 }
1391 ha->tx_ring[ridx].flags.wq_dma = 1;
1392
1393 ha->tx_ring[ridx].privb_dma.alignment = 8;
1394 ha->tx_ring[ridx].privb_dma.size = QLA_TX_PRIVATE_BSIZE;
1395
1396 ret = qls_alloc_dmabuf(ha, &ha->tx_ring[ridx].privb_dma);
1397
1398 if (ret) {
1399 device_printf(dev, "%s: [%d] oalb failed\n", __func__, ridx);
1400 goto qls_alloc_tx_ring_dma_exit;
1401 }
1402
1403 ha->tx_ring[ridx].flags.privb_dma = 1;
1404
1405 ha->tx_ring[ridx].wq_vaddr = ha->tx_ring[ridx].wq_dma.dma_b;
1406 ha->tx_ring[ridx].wq_paddr = ha->tx_ring[ridx].wq_dma.dma_addr;
1407
1408 v_addr = ha->tx_ring[ridx].privb_dma.dma_b;
1409 p_addr = ha->tx_ring[ridx].privb_dma.dma_addr;
1410
1411 ha->tx_ring[ridx].wq_icb_vaddr = v_addr;
1412 ha->tx_ring[ridx].wq_icb_paddr = p_addr;
1413
1414 ha->tx_ring[ridx].txr_cons_vaddr =
1415 (uint32_t *)(v_addr + (PAGE_SIZE >> 1));
1416 ha->tx_ring[ridx].txr_cons_paddr = p_addr + (PAGE_SIZE >> 1);
1417
1418 v_addr = v_addr + (PAGE_SIZE >> 1);
1419 p_addr = p_addr + (PAGE_SIZE >> 1);
1420
1421 txb = ha->tx_ring[ridx].tx_buf;
1422
1423 for (i = 0; i < NUM_TX_DESCRIPTORS; i++) {
1424 txb[i].oal_vaddr = v_addr;
1425 txb[i].oal_paddr = p_addr;
1426
1427 v_addr = v_addr + QLA_OAL_BLK_SIZE;
1428 p_addr = p_addr + QLA_OAL_BLK_SIZE;
1429 }
1430
1431 qls_alloc_tx_ring_dma_exit:
1432 return (ret);
1433 }
1434
1435 static int
1436 qls_alloc_tx_dma(qla_host_t *ha)
1437 {
1438 int i, j;
1439 int ret = 0;
1440 qla_tx_buf_t *txb;
1441
1442 if (bus_dma_tag_create(NULL, /* parent */
1443 1, 0, /* alignment, bounds */
1444 BUS_SPACE_MAXADDR, /* lowaddr */
1445 BUS_SPACE_MAXADDR, /* highaddr */
1446 NULL, NULL, /* filter, filterarg */
1447 QLA_MAX_TSO_FRAME_SIZE, /* maxsize */
1448 QLA_MAX_SEGMENTS, /* nsegments */
1449 PAGE_SIZE, /* maxsegsize */
1450 BUS_DMA_ALLOCNOW, /* flags */
1451 NULL, /* lockfunc */
1452 NULL, /* lockfuncarg */
1453 &ha->tx_tag)) {
1454 device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n",
1455 __func__);
1456 return (ENOMEM);
1457 }
1458
1459 for (i = 0; i < ha->num_tx_rings; i++) {
1460 ret = qls_alloc_tx_ring_dma(ha, i);
1461
1462 if (ret) {
1463 qls_free_tx_dma(ha);
1464 break;
1465 }
1466
1467 for (j = 0; j < NUM_TX_DESCRIPTORS; j++) {
1468 txb = &ha->tx_ring[i].tx_buf[j];
1469
1470 ret = bus_dmamap_create(ha->tx_tag,
1471 BUS_DMA_NOWAIT, &txb->map);
1472 if (ret) {
1473 ha->err_tx_dmamap_create++;
1474 device_printf(ha->pci_dev,
1475 "%s: bus_dmamap_create failed[%d, %d, %d]\n",
1476 __func__, ret, i, j);
1477
1478 qls_free_tx_dma(ha);
1479
1480 return (ret);
1481 }
1482 }
1483 }
1484
1485 return (ret);
1486 }
1487
1488 static void
1489 qls_free_rss_dma(qla_host_t *ha)
1490 {
1491 qls_free_dmabuf(ha, &ha->rss_dma);
1492 ha->flags.rss_dma = 0;
1493 }
1494
1495 static int
1496 qls_alloc_rss_dma(qla_host_t *ha)
1497 {
1498 int ret = 0;
1499
1500 ha->rss_dma.alignment = 4;
1501 ha->rss_dma.size = PAGE_SIZE;
1502
1503 ret = qls_alloc_dmabuf(ha, &ha->rss_dma);
1504
1505 if (ret)
1506 device_printf(ha->pci_dev, "%s: failed\n", __func__);
1507 else
1508 ha->flags.rss_dma = 1;
1509
1510 return (ret);
1511 }
1512
1513 static void
1514 qls_free_mpi_dma(qla_host_t *ha)
1515 {
1516 qls_free_dmabuf(ha, &ha->mpi_dma);
1517 ha->flags.mpi_dma = 0;
1518 }
1519
1520 static int
1521 qls_alloc_mpi_dma(qla_host_t *ha)
1522 {
1523 int ret = 0;
1524
1525 ha->mpi_dma.alignment = 4;
1526 ha->mpi_dma.size = (0x4000 * 4);
1527
1528 ret = qls_alloc_dmabuf(ha, &ha->mpi_dma);
1529 if (ret)
1530 device_printf(ha->pci_dev, "%s: failed\n", __func__);
1531 else
1532 ha->flags.mpi_dma = 1;
1533
1534 return (ret);
1535 }
1536
1537 static void
1538 qls_free_rx_ring_dma(qla_host_t *ha, int ridx)
1539 {
1540 if (ha->rx_ring[ridx].flags.cq_dma) {
1541 qls_free_dmabuf(ha, &ha->rx_ring[ridx].cq_dma);
1542 ha->rx_ring[ridx].flags.cq_dma = 0;
1543 }
1544
1545 if (ha->rx_ring[ridx].flags.lbq_dma) {
1546 qls_free_dmabuf(ha, &ha->rx_ring[ridx].lbq_dma);
1547 ha->rx_ring[ridx].flags.lbq_dma = 0;
1548 }
1549
1550 if (ha->rx_ring[ridx].flags.sbq_dma) {
1551 qls_free_dmabuf(ha, &ha->rx_ring[ridx].sbq_dma);
1552 ha->rx_ring[ridx].flags.sbq_dma = 0;
1553 }
1554
1555 if (ha->rx_ring[ridx].flags.lb_dma) {
1556 qls_free_dmabuf(ha, &ha->rx_ring[ridx].lb_dma);
1557 ha->rx_ring[ridx].flags.lb_dma = 0;
1558 }
1559 return;
1560 }
1561
1562 static void
1563 qls_free_rx_dma(qla_host_t *ha)
1564 {
1565 int i;
1566
1567 for (i = 0; i < ha->num_rx_rings; i++) {
1568 qls_free_rx_ring_dma(ha, i);
1569 }
1570
1571 if (ha->rx_tag != NULL) {
1572 bus_dma_tag_destroy(ha->rx_tag);
1573 ha->rx_tag = NULL;
1574 }
1575
1576 return;
1577 }
1578
1579 static int
1580 qls_alloc_rx_ring_dma(qla_host_t *ha, int ridx)
1581 {
1582 int i, ret = 0;
1583 uint8_t *v_addr;
1584 bus_addr_t p_addr;
1585 volatile q81_bq_addr_e_t *bq_e;
1586 device_t dev = ha->pci_dev;
1587
1588 ha->rx_ring[ridx].cq_dma.alignment = 128;
1589 ha->rx_ring[ridx].cq_dma.size =
1590 (NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t))) + PAGE_SIZE;
1591
1592 ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].cq_dma);
1593
1594 if (ret) {
1595 device_printf(dev, "%s: [%d] cq failed\n", __func__, ridx);
1596 goto qls_alloc_rx_ring_dma_exit;
1597 }
1598 ha->rx_ring[ridx].flags.cq_dma = 1;
1599
1600 ha->rx_ring[ridx].lbq_dma.alignment = 8;
1601 ha->rx_ring[ridx].lbq_dma.size = QLA_LGBQ_AND_TABLE_SIZE;
1602
1603 ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].lbq_dma);
1604
1605 if (ret) {
1606 device_printf(dev, "%s: [%d] lbq failed\n", __func__, ridx);
1607 goto qls_alloc_rx_ring_dma_exit;
1608 }
1609 ha->rx_ring[ridx].flags.lbq_dma = 1;
1610
1611 ha->rx_ring[ridx].sbq_dma.alignment = 8;
1612 ha->rx_ring[ridx].sbq_dma.size = QLA_SMBQ_AND_TABLE_SIZE;
1613
1614 ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].sbq_dma);
1615
1616 if (ret) {
1617 device_printf(dev, "%s: [%d] sbq failed\n", __func__, ridx);
1618 goto qls_alloc_rx_ring_dma_exit;
1619 }
1620 ha->rx_ring[ridx].flags.sbq_dma = 1;
1621
1622 ha->rx_ring[ridx].lb_dma.alignment = 8;
1623 ha->rx_ring[ridx].lb_dma.size = (QLA_LGB_SIZE * QLA_NUM_LGB_ENTRIES);
1624
1625 ret = qls_alloc_dmabuf(ha, &ha->rx_ring[ridx].lb_dma);
1626 if (ret) {
1627 device_printf(dev, "%s: [%d] lb failed\n", __func__, ridx);
1628 goto qls_alloc_rx_ring_dma_exit;
1629 }
1630 ha->rx_ring[ridx].flags.lb_dma = 1;
1631
1632 bzero(ha->rx_ring[ridx].cq_dma.dma_b, ha->rx_ring[ridx].cq_dma.size);
1633 bzero(ha->rx_ring[ridx].lbq_dma.dma_b, ha->rx_ring[ridx].lbq_dma.size);
1634 bzero(ha->rx_ring[ridx].sbq_dma.dma_b, ha->rx_ring[ridx].sbq_dma.size);
1635 bzero(ha->rx_ring[ridx].lb_dma.dma_b, ha->rx_ring[ridx].lb_dma.size);
1636
1637 /* completion queue */
1638 ha->rx_ring[ridx].cq_base_vaddr = ha->rx_ring[ridx].cq_dma.dma_b;
1639 ha->rx_ring[ridx].cq_base_paddr = ha->rx_ring[ridx].cq_dma.dma_addr;
1640
1641 v_addr = ha->rx_ring[ridx].cq_dma.dma_b;
1642 p_addr = ha->rx_ring[ridx].cq_dma.dma_addr;
1643
1644 v_addr = v_addr + (NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t)));
1645 p_addr = p_addr + (NUM_CQ_ENTRIES * (sizeof (q81_cq_e_t)));
1646
1647 /* completion queue icb */
1648 ha->rx_ring[ridx].cq_icb_vaddr = v_addr;
1649 ha->rx_ring[ridx].cq_icb_paddr = p_addr;
1650
1651 v_addr = v_addr + (PAGE_SIZE >> 2);
1652 p_addr = p_addr + (PAGE_SIZE >> 2);
1653
1654 /* completion queue index register */
1655 ha->rx_ring[ridx].cqi_vaddr = (uint32_t *)v_addr;
1656 ha->rx_ring[ridx].cqi_paddr = p_addr;
1657
1658 v_addr = ha->rx_ring[ridx].lbq_dma.dma_b;
1659 p_addr = ha->rx_ring[ridx].lbq_dma.dma_addr;
1660
1661 /* large buffer queue address table */
1662 ha->rx_ring[ridx].lbq_addr_tbl_vaddr = v_addr;
1663 ha->rx_ring[ridx].lbq_addr_tbl_paddr = p_addr;
1664
1665 /* large buffer queue */
1666 ha->rx_ring[ridx].lbq_vaddr = v_addr + PAGE_SIZE;
1667 ha->rx_ring[ridx].lbq_paddr = p_addr + PAGE_SIZE;
1668
1669 v_addr = ha->rx_ring[ridx].sbq_dma.dma_b;
1670 p_addr = ha->rx_ring[ridx].sbq_dma.dma_addr;
1671
1672 /* small buffer queue address table */
1673 ha->rx_ring[ridx].sbq_addr_tbl_vaddr = v_addr;
1674 ha->rx_ring[ridx].sbq_addr_tbl_paddr = p_addr;
1675
1676 /* small buffer queue */
1677 ha->rx_ring[ridx].sbq_vaddr = v_addr + PAGE_SIZE;
1678 ha->rx_ring[ridx].sbq_paddr = p_addr + PAGE_SIZE;
1679
1680 ha->rx_ring[ridx].lb_vaddr = ha->rx_ring[ridx].lb_dma.dma_b;
1681 ha->rx_ring[ridx].lb_paddr = ha->rx_ring[ridx].lb_dma.dma_addr;
1682
1683 /* Initialize Large Buffer Queue Table */
1684
1685 p_addr = ha->rx_ring[ridx].lbq_paddr;
1686 bq_e = ha->rx_ring[ridx].lbq_addr_tbl_vaddr;
1687
1688 bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1689 bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1690
1691 p_addr = ha->rx_ring[ridx].lb_paddr;
1692 bq_e = ha->rx_ring[ridx].lbq_vaddr;
1693
1694 for (i = 0; i < QLA_NUM_LGB_ENTRIES; i++) {
1695 bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1696 bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1697
1698 p_addr = p_addr + QLA_LGB_SIZE;
1699 bq_e++;
1700 }
1701
1702 /* Initialize Small Buffer Queue Table */
1703
1704 p_addr = ha->rx_ring[ridx].sbq_paddr;
1705 bq_e = ha->rx_ring[ridx].sbq_addr_tbl_vaddr;
1706
1707 for (i =0; i < (QLA_SBQ_SIZE/QLA_PAGE_SIZE); i++) {
1708 bq_e->addr_lo = p_addr & 0xFFFFFFFF;
1709 bq_e->addr_hi = (p_addr >> 32) & 0xFFFFFFFF;
1710
1711 p_addr = p_addr + QLA_PAGE_SIZE;
1712 bq_e++;
1713 }
1714
1715 qls_alloc_rx_ring_dma_exit:
1716 return (ret);
1717 }
1718
1719 static int
1720 qls_alloc_rx_dma(qla_host_t *ha)
1721 {
1722 int i;
1723 int ret = 0;
1724
1725 if (bus_dma_tag_create(NULL, /* parent */
1726 1, 0, /* alignment, bounds */
1727 BUS_SPACE_MAXADDR, /* lowaddr */
1728 BUS_SPACE_MAXADDR, /* highaddr */
1729 NULL, NULL, /* filter, filterarg */
1730 MJUM9BYTES, /* maxsize */
1731 1, /* nsegments */
1732 MJUM9BYTES, /* maxsegsize */
1733 BUS_DMA_ALLOCNOW, /* flags */
1734 NULL, /* lockfunc */
1735 NULL, /* lockfuncarg */
1736 &ha->rx_tag)) {
1737 device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n",
1738 __func__);
1739
1740 return (ENOMEM);
1741 }
1742
1743 for (i = 0; i < ha->num_rx_rings; i++) {
1744 ret = qls_alloc_rx_ring_dma(ha, i);
1745
1746 if (ret) {
1747 qls_free_rx_dma(ha);
1748 break;
1749 }
1750 }
1751
1752 return (ret);
1753 }
1754
1755 static int
1756 qls_wait_for_flash_ready(qla_host_t *ha)
1757 {
1758 uint32_t data32;
1759 uint32_t count = 3;
1760
1761 while (count--) {
1762 data32 = READ_REG32(ha, Q81_CTL_FLASH_ADDR);
1763
1764 if (data32 & Q81_CTL_FLASH_ADDR_ERR)
1765 goto qls_wait_for_flash_ready_exit;
1766
1767 if (data32 & Q81_CTL_FLASH_ADDR_RDY)
1768 return (0);
1769
1770 QLA_USEC_DELAY(100);
1771 }
1772
1773 qls_wait_for_flash_ready_exit:
1774 QL_DPRINT1((ha->pci_dev, "%s: failed\n", __func__));
1775
1776 return (-1);
1777 }
1778
1779 /*
1780 * Name: qls_rd_flash32
1781 * Function: Read Flash Memory
1782 */
1783 int
1784 qls_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
1785 {
1786 int ret;
1787
1788 ret = qls_wait_for_flash_ready(ha);
1789
1790 if (ret)
1791 return (ret);
1792
1793 WRITE_REG32(ha, Q81_CTL_FLASH_ADDR, (addr | Q81_CTL_FLASH_ADDR_R));
1794
1795 ret = qls_wait_for_flash_ready(ha);
1796
1797 if (ret)
1798 return (ret);
1799
1800 *data = READ_REG32(ha, Q81_CTL_FLASH_DATA);
1801
1802 return 0;
1803 }
1804
1805 static int
1806 qls_flash_validate(qla_host_t *ha, const char *signature)
1807 {
1808 uint16_t csum16 = 0;
1809 uint16_t *data16;
1810 int i;
1811
1812 if (bcmp(ha->flash.id, signature, 4)) {
1813 QL_DPRINT1((ha->pci_dev, "%s: invalid signature "
1814 "%x:%x:%x:%x %s\n", __func__, ha->flash.id[0],
1815 ha->flash.id[1], ha->flash.id[2], ha->flash.id[3],
1816 signature));
1817 return(-1);
1818 }
1819
1820 data16 = (uint16_t *)&ha->flash;
1821
1822 for (i = 0; i < (sizeof (q81_flash_t) >> 1); i++) {
1823 csum16 += *data16++;
1824 }
1825
1826 if (csum16) {
1827 QL_DPRINT1((ha->pci_dev, "%s: invalid checksum\n", __func__));
1828 return(-1);
1829 }
1830 return(0);
1831 }
1832
1833 int
1834 qls_rd_nic_params(qla_host_t *ha)
1835 {
1836 int i, ret = 0;
1837 uint32_t faddr;
1838 uint32_t *qflash;
1839
1840 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_FLASH, Q81_CTL_SEM_SET_FLASH)) {
1841 QL_DPRINT1((ha->pci_dev, "%s: semlock failed\n", __func__));
1842 return(-1);
1843 }
1844
1845 if ((ha->pci_func & 0x1) == 0)
1846 faddr = Q81_F0_FLASH_OFFSET >> 2;
1847 else
1848 faddr = Q81_F1_FLASH_OFFSET >> 2;
1849
1850 qflash = (uint32_t *)&ha->flash;
1851
1852 for (i = 0; i < (sizeof(q81_flash_t) >> 2) ; i++) {
1853 ret = qls_rd_flash32(ha, faddr, qflash);
1854
1855 if (ret)
1856 goto qls_rd_flash_data_exit;
1857
1858 faddr++;
1859 qflash++;
1860 }
1861
1862 QL_DUMP_BUFFER8(ha, __func__, (&ha->flash), (sizeof (q81_flash_t)));
1863
1864 ret = qls_flash_validate(ha, Q81_FLASH_ID);
1865
1866 if (ret)
1867 goto qls_rd_flash_data_exit;
1868
1869 bcopy(ha->flash.mac_addr0, ha->mac_addr, ETHER_ADDR_LEN);
1870
1871 QL_DPRINT1((ha->pci_dev, "%s: mac %02x:%02x:%02x:%02x:%02x:%02x\n",
1872 __func__, ha->mac_addr[0], ha->mac_addr[1], ha->mac_addr[2],
1873 ha->mac_addr[3], ha->mac_addr[4], ha->mac_addr[5]));
1874
1875 qls_rd_flash_data_exit:
1876
1877 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_FLASH);
1878
1879 return(ret);
1880 }
1881
1882 static int
1883 qls_sem_lock(qla_host_t *ha, uint32_t mask, uint32_t value)
1884 {
1885 uint32_t count = 30;
1886 uint32_t data;
1887
1888 while (count--) {
1889 WRITE_REG32(ha, Q81_CTL_SEMAPHORE, (mask|value));
1890
1891 data = READ_REG32(ha, Q81_CTL_SEMAPHORE);
1892
1893 if (data & value) {
1894 return (0);
1895 } else {
1896 QLA_USEC_DELAY(100);
1897 }
1898 }
1899 ha->qla_initiate_recovery = 1;
1900 return (-1);
1901 }
1902
1903 static void
1904 qls_sem_unlock(qla_host_t *ha, uint32_t mask)
1905 {
1906 WRITE_REG32(ha, Q81_CTL_SEMAPHORE, mask);
1907 }
1908
1909 static int
1910 qls_wait_for_proc_addr_ready(qla_host_t *ha)
1911 {
1912 uint32_t data32;
1913 uint32_t count = 3;
1914
1915 while (count--) {
1916 data32 = READ_REG32(ha, Q81_CTL_PROC_ADDR);
1917
1918 if (data32 & Q81_CTL_PROC_ADDR_ERR)
1919 goto qls_wait_for_proc_addr_ready_exit;
1920
1921 if (data32 & Q81_CTL_PROC_ADDR_RDY)
1922 return (0);
1923
1924 QLA_USEC_DELAY(100);
1925 }
1926
1927 qls_wait_for_proc_addr_ready_exit:
1928 QL_DPRINT1((ha->pci_dev, "%s: failed\n", __func__));
1929
1930 ha->qla_initiate_recovery = 1;
1931 return (-1);
1932 }
1933
1934 static int
1935 qls_proc_addr_rd_reg(qla_host_t *ha, uint32_t addr_module, uint32_t reg,
1936 uint32_t *data)
1937 {
1938 int ret;
1939 uint32_t value;
1940
1941 ret = qls_wait_for_proc_addr_ready(ha);
1942
1943 if (ret)
1944 goto qls_proc_addr_rd_reg_exit;
1945
1946 value = addr_module | reg | Q81_CTL_PROC_ADDR_READ;
1947
1948 WRITE_REG32(ha, Q81_CTL_PROC_ADDR, value);
1949
1950 ret = qls_wait_for_proc_addr_ready(ha);
1951
1952 if (ret)
1953 goto qls_proc_addr_rd_reg_exit;
1954
1955 *data = READ_REG32(ha, Q81_CTL_PROC_DATA);
1956
1957 qls_proc_addr_rd_reg_exit:
1958 return (ret);
1959 }
1960
1961 static int
1962 qls_proc_addr_wr_reg(qla_host_t *ha, uint32_t addr_module, uint32_t reg,
1963 uint32_t data)
1964 {
1965 int ret;
1966 uint32_t value;
1967
1968 ret = qls_wait_for_proc_addr_ready(ha);
1969
1970 if (ret)
1971 goto qls_proc_addr_wr_reg_exit;
1972
1973 WRITE_REG32(ha, Q81_CTL_PROC_DATA, data);
1974
1975 value = addr_module | reg;
1976
1977 WRITE_REG32(ha, Q81_CTL_PROC_ADDR, value);
1978
1979 ret = qls_wait_for_proc_addr_ready(ha);
1980
1981 qls_proc_addr_wr_reg_exit:
1982 return (ret);
1983 }
1984
1985 static int
1986 qls_hw_nic_reset(qla_host_t *ha)
1987 {
1988 int count;
1989 uint32_t data;
1990 device_t dev = ha->pci_dev;
1991
1992 ha->hw_init = 0;
1993
1994 data = (Q81_CTL_RESET_FUNC << Q81_CTL_RESET_MASK_SHIFT) |
1995 Q81_CTL_RESET_FUNC;
1996 WRITE_REG32(ha, Q81_CTL_RESET, data);
1997
1998 count = 10;
1999 while (count--) {
2000 data = READ_REG32(ha, Q81_CTL_RESET);
2001 if ((data & Q81_CTL_RESET_FUNC) == 0)
2002 break;
2003 QLA_USEC_DELAY(10);
2004 }
2005 if (count == 0) {
2006 device_printf(dev, "%s: Bit 15 not cleared after Reset\n",
2007 __func__);
2008 return (-1);
2009 }
2010 return (0);
2011 }
2012
2013 static int
2014 qls_hw_reset(qla_host_t *ha)
2015 {
2016 device_t dev = ha->pci_dev;
2017 int ret;
2018 int count;
2019 uint32_t data;
2020
2021 QL_DPRINT2((ha->pci_dev, "%s:enter[%d]\n", __func__, ha->hw_init));
2022
2023 if (ha->hw_init == 0) {
2024 ret = qls_hw_nic_reset(ha);
2025 goto qls_hw_reset_exit;
2026 }
2027
2028 ret = qls_clear_routing_table(ha);
2029 if (ret)
2030 goto qls_hw_reset_exit;
2031
2032 ret = qls_mbx_set_mgmt_ctrl(ha, Q81_MBX_SET_MGMT_CTL_STOP);
2033 if (ret)
2034 goto qls_hw_reset_exit;
2035
2036 /*
2037 * Wait for FIFO to empty
2038 */
2039 count = 5;
2040 while (count--) {
2041 data = READ_REG32(ha, Q81_CTL_STATUS);
2042 if (data & Q81_CTL_STATUS_NFE)
2043 break;
2044 qls_mdelay(__func__, 100);
2045 }
2046 if (count == 0) {
2047 device_printf(dev, "%s: NFE bit not set\n", __func__);
2048 goto qls_hw_reset_exit;
2049 }
2050
2051 count = 5;
2052 while (count--) {
2053 (void)qls_mbx_get_mgmt_ctrl(ha, &data);
2054
2055 if ((data & Q81_MBX_GET_MGMT_CTL_FIFO_EMPTY) &&
2056 (data & Q81_MBX_GET_MGMT_CTL_SET_MGMT))
2057 break;
2058 qls_mdelay(__func__, 100);
2059 }
2060 if (count == 0)
2061 goto qls_hw_reset_exit;
2062
2063 /*
2064 * Reset the NIC function
2065 */
2066 ret = qls_hw_nic_reset(ha);
2067 if (ret)
2068 goto qls_hw_reset_exit;
2069
2070 ret = qls_mbx_set_mgmt_ctrl(ha, Q81_MBX_SET_MGMT_CTL_RESUME);
2071
2072 qls_hw_reset_exit:
2073 if (ret)
2074 device_printf(dev, "%s: failed\n", __func__);
2075
2076 return (ret);
2077 }
2078
2079 /*
2080 * MPI Related Functions
2081 */
2082 int
2083 qls_mpi_risc_rd_reg(qla_host_t *ha, uint32_t reg, uint32_t *data)
2084 {
2085 int ret;
2086
2087 ret = qls_proc_addr_rd_reg(ha, Q81_CTL_PROC_ADDR_MPI_RISC,
2088 reg, data);
2089 return (ret);
2090 }
2091
2092 int
2093 qls_mpi_risc_wr_reg(qla_host_t *ha, uint32_t reg, uint32_t data)
2094 {
2095 int ret;
2096
2097 ret = qls_proc_addr_wr_reg(ha, Q81_CTL_PROC_ADDR_MPI_RISC,
2098 reg, data);
2099 return (ret);
2100 }
2101
2102 int
2103 qls_mbx_rd_reg(qla_host_t *ha, uint32_t reg, uint32_t *data)
2104 {
2105 int ret;
2106
2107 if ((ha->pci_func & 0x1) == 0)
2108 reg += Q81_FUNC0_MBX_OUT_REG0;
2109 else
2110 reg += Q81_FUNC1_MBX_OUT_REG0;
2111
2112 ret = qls_mpi_risc_rd_reg(ha, reg, data);
2113
2114 return (ret);
2115 }
2116
2117 int
2118 qls_mbx_wr_reg(qla_host_t *ha, uint32_t reg, uint32_t data)
2119 {
2120 int ret;
2121
2122 if ((ha->pci_func & 0x1) == 0)
2123 reg += Q81_FUNC0_MBX_IN_REG0;
2124 else
2125 reg += Q81_FUNC1_MBX_IN_REG0;
2126
2127 ret = qls_mpi_risc_wr_reg(ha, reg, data);
2128
2129 return (ret);
2130 }
2131
2132 static int
2133 qls_mbx_cmd(qla_host_t *ha, uint32_t *in_mbx, uint32_t i_count,
2134 uint32_t *out_mbx, uint32_t o_count)
2135 {
2136 int i, ret = -1;
2137 uint32_t data32;
2138 uint32_t count = 50;
2139
2140 QL_DPRINT2((ha->pci_dev, "%s: enter[0x%08x 0x%08x 0x%08x]\n",
2141 __func__, *in_mbx, *(in_mbx + 1), *(in_mbx + 2)));
2142
2143 data32 = READ_REG32(ha, Q81_CTL_HOST_CMD_STATUS);
2144
2145 if (data32 & Q81_CTL_HCS_HTR_INTR) {
2146 device_printf(ha->pci_dev, "%s: cmd_status[0x%08x]\n",
2147 __func__, data32);
2148 goto qls_mbx_cmd_exit;
2149 }
2150
2151 if (qls_sem_lock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV,
2152 Q81_CTL_SEM_SET_PROC_ADDR_NIC_RCV)) {
2153 device_printf(ha->pci_dev, "%s: semlock failed\n", __func__);
2154 goto qls_mbx_cmd_exit;
2155 }
2156
2157 ha->mbx_done = 0;
2158
2159 for (i = 0; i < i_count; i++) {
2160 ret = qls_mbx_wr_reg(ha, i, *in_mbx);
2161
2162 if (ret) {
2163 device_printf(ha->pci_dev,
2164 "%s: mbx_wr[%d, 0x%08x] failed\n", __func__,
2165 i, *in_mbx);
2166 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV);
2167 goto qls_mbx_cmd_exit;
2168 }
2169
2170 in_mbx++;
2171 }
2172 WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS, Q81_CTL_HCS_CMD_SET_HTR_INTR);
2173
2174 qls_sem_unlock(ha, Q81_CTL_SEM_MASK_PROC_ADDR_NIC_RCV);
2175
2176 ret = -1;
2177 ha->mbx_done = 0;
2178
2179 while (count--) {
2180 if (ha->flags.intr_enable == 0) {
2181 data32 = READ_REG32(ha, Q81_CTL_STATUS);
2182
2183 if (!(data32 & Q81_CTL_STATUS_PI)) {
2184 qls_mdelay(__func__, 100);
2185 continue;
2186 }
2187
2188 ret = qls_mbx_rd_reg(ha, 0, &data32);
2189
2190 if (ret == 0 ) {
2191 if ((data32 & 0xF000) == 0x4000) {
2192 out_mbx[0] = data32;
2193
2194 for (i = 1; i < o_count; i++) {
2195 ret = qls_mbx_rd_reg(ha, i,
2196 &data32);
2197 if (ret) {
2198 device_printf(
2199 ha->pci_dev,
2200 "%s: mbx_rd[%d]"
2201 " failed\n",
2202 __func__, i);
2203 break;
2204 }
2205 out_mbx[i] = data32;
2206 }
2207 break;
2208 } else if ((data32 & 0xF000) == 0x8000) {
2209 count = 50;
2210 WRITE_REG32(ha,\
2211 Q81_CTL_HOST_CMD_STATUS,\
2212 Q81_CTL_HCS_CMD_CLR_RTH_INTR);
2213 }
2214 }
2215 } else {
2216 if (ha->mbx_done) {
2217 for (i = 1; i < o_count; i++) {
2218 out_mbx[i] = ha->mbox[i];
2219 }
2220 ret = 0;
2221 break;
2222 }
2223 }
2224 qls_mdelay(__func__, 1000);
2225 }
2226
2227 qls_mbx_cmd_exit:
2228
2229 if (ha->flags.intr_enable == 0) {
2230 WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2231 Q81_CTL_HCS_CMD_CLR_RTH_INTR);
2232 }
2233
2234 if (ret) {
2235 ha->qla_initiate_recovery = 1;
2236 }
2237
2238 QL_DPRINT2((ha->pci_dev, "%s: exit[%d]\n", __func__, ret));
2239 return (ret);
2240 }
2241
2242 static int
2243 qls_mbx_set_mgmt_ctrl(qla_host_t *ha, uint32_t t_ctrl)
2244 {
2245 uint32_t *mbox;
2246 device_t dev = ha->pci_dev;
2247
2248 mbox = ha->mbox;
2249 bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2250
2251 mbox[0] = Q81_MBX_SET_MGMT_CTL;
2252 mbox[1] = t_ctrl;
2253
2254 if (qls_mbx_cmd(ha, mbox, 2, mbox, 1)) {
2255 device_printf(dev, "%s failed\n", __func__);
2256 return (-1);
2257 }
2258
2259 if ((mbox[0] == Q81_MBX_CMD_COMPLETE) ||
2260 ((t_ctrl == Q81_MBX_SET_MGMT_CTL_STOP) &&
2261 (mbox[0] == Q81_MBX_CMD_ERROR))){
2262 return (0);
2263 }
2264 device_printf(dev, "%s failed [0x%08x]\n", __func__, mbox[0]);
2265 return (-1);
2266
2267 }
2268
2269 static int
2270 qls_mbx_get_mgmt_ctrl(qla_host_t *ha, uint32_t *t_status)
2271 {
2272 uint32_t *mbox;
2273 device_t dev = ha->pci_dev;
2274
2275 *t_status = 0;
2276
2277 mbox = ha->mbox;
2278 bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2279
2280 mbox[0] = Q81_MBX_GET_MGMT_CTL;
2281
2282 if (qls_mbx_cmd(ha, mbox, 1, mbox, 2)) {
2283 device_printf(dev, "%s failed\n", __func__);
2284 return (-1);
2285 }
2286
2287 *t_status = mbox[1];
2288
2289 return (0);
2290 }
2291
2292 static void
2293 qls_mbx_get_link_status(qla_host_t *ha)
2294 {
2295 uint32_t *mbox;
2296 device_t dev = ha->pci_dev;
2297
2298 mbox = ha->mbox;
2299 bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2300
2301 mbox[0] = Q81_MBX_GET_LNK_STATUS;
2302
2303 if (qls_mbx_cmd(ha, mbox, 1, mbox, 6)) {
2304 device_printf(dev, "%s failed\n", __func__);
2305 return;
2306 }
2307
2308 ha->link_status = mbox[1];
2309 ha->link_down_info = mbox[2];
2310 ha->link_hw_info = mbox[3];
2311 ha->link_dcbx_counters = mbox[4];
2312 ha->link_change_counters = mbox[5];
2313
2314 device_printf(dev, "%s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
2315 __func__, mbox[0],mbox[1],mbox[2],mbox[3],mbox[4],mbox[5]);
2316
2317 return;
2318 }
2319
2320 static void
2321 qls_mbx_about_fw(qla_host_t *ha)
2322 {
2323 uint32_t *mbox;
2324 device_t dev = ha->pci_dev;
2325
2326 mbox = ha->mbox;
2327 bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2328
2329 mbox[0] = Q81_MBX_ABOUT_FW;
2330
2331 if (qls_mbx_cmd(ha, mbox, 1, mbox, 6)) {
2332 device_printf(dev, "%s failed\n", __func__);
2333 return;
2334 }
2335
2336 device_printf(dev, "%s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
2337 __func__, mbox[0],mbox[1],mbox[2],mbox[3],mbox[4],mbox[5]);
2338 }
2339
2340 int
2341 qls_mbx_dump_risc_ram(qla_host_t *ha, void *buf, uint32_t r_addr,
2342 uint32_t r_size)
2343 {
2344 bus_addr_t b_paddr;
2345 uint32_t *mbox;
2346 device_t dev = ha->pci_dev;
2347
2348 mbox = ha->mbox;
2349 bzero(mbox, (sizeof (uint32_t) * Q81_NUM_MBX_REGISTERS));
2350
2351 bzero(ha->mpi_dma.dma_b,(r_size << 2));
2352 b_paddr = ha->mpi_dma.dma_addr;
2353
2354 mbox[0] = Q81_MBX_DUMP_RISC_RAM;
2355 mbox[1] = r_addr & 0xFFFF;
2356 mbox[2] = ((uint32_t)(b_paddr >> 16)) & 0xFFFF;
2357 mbox[3] = ((uint32_t)b_paddr) & 0xFFFF;
2358 mbox[4] = (r_size >> 16) & 0xFFFF;
2359 mbox[5] = r_size & 0xFFFF;
2360 mbox[6] = ((uint32_t)(b_paddr >> 48)) & 0xFFFF;
2361 mbox[7] = ((uint32_t)(b_paddr >> 32)) & 0xFFFF;
2362 mbox[8] = (r_addr >> 16) & 0xFFFF;
2363
2364 bus_dmamap_sync(ha->mpi_dma.dma_tag, ha->mpi_dma.dma_map,
2365 BUS_DMASYNC_PREREAD);
2366
2367 if (qls_mbx_cmd(ha, mbox, 9, mbox, 1)) {
2368 device_printf(dev, "%s failed\n", __func__);
2369 return (-1);
2370 }
2371 if (mbox[0] != 0x4000) {
2372 device_printf(ha->pci_dev, "%s: failed!\n", __func__);
2373 return (-1);
2374 } else {
2375 bus_dmamap_sync(ha->mpi_dma.dma_tag, ha->mpi_dma.dma_map,
2376 BUS_DMASYNC_POSTREAD);
2377 bcopy(ha->mpi_dma.dma_b, buf, (r_size << 2));
2378 }
2379
2380 return (0);
2381 }
2382
2383 int
2384 qls_mpi_reset(qla_host_t *ha)
2385 {
2386 int count;
2387 uint32_t data;
2388 device_t dev = ha->pci_dev;
2389
2390 WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2391 Q81_CTL_HCS_CMD_SET_RISC_RESET);
2392
2393 count = 10;
2394 while (count--) {
2395 data = READ_REG32(ha, Q81_CTL_HOST_CMD_STATUS);
2396 if (data & Q81_CTL_HCS_RISC_RESET) {
2397 WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS,\
2398 Q81_CTL_HCS_CMD_CLR_RISC_RESET);
2399 break;
2400 }
2401 qls_mdelay(__func__, 10);
2402 }
2403 if (count == 0) {
2404 device_printf(dev, "%s: failed\n", __func__);
2405 return (-1);
2406 }
2407 return (0);
2408 }
Cache object: 6c039b9638c05212b13facfd41df463d
|