Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ntxn/unm_gem.c
+++ new/usr/src/uts/common/io/ntxn/unm_gem.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 NetXen, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 27 * Use is subject to license terms.
28 28 */
29 29 #include <sys/types.h>
30 30 #include <sys/conf.h>
31 31 #include <sys/debug.h>
32 32 #include <sys/stropts.h>
33 33 #include <sys/stream.h>
34 34 #include <sys/strlog.h>
35 35 #include <sys/kmem.h>
36 36 #include <sys/stat.h>
37 37 #include <sys/kstat.h>
38 38 #include <sys/vtrace.h>
39 39 #include <sys/dlpi.h>
40 40 #include <sys/strsun.h>
41 41 #include <sys/ethernet.h>
42 42 #include <sys/modctl.h>
43 43 #include <sys/errno.h>
44 44 #include <sys/dditypes.h>
45 45 #include <sys/ddi.h>
46 46 #include <sys/sunddi.h>
47 47 #include <sys/sysmacros.h>
48 48 #include <sys/pci.h>
49 49 #include <sys/ddi_intr.h>
50 50
51 51 #include "unm_nic.h"
52 52 #include "unm_nic_hw.h"
53 53 #include "unm_brdcfg.h"
54 54 #include "nic_cmn.h"
55 55 #include "nic_phan_reg.h"
56 56 #include "unm_nic_ioctl.h"
57 57 #include "nx_hw_pci_regs.h"
58 58
59 59 char ident[] = "Netxen nic driver v" UNM_NIC_VERSIONID;
60 60 char unm_nic_driver_name[] = "ntxn";
61 61 int verbmsg = 0;
62 62
63 63 static char txbcopythreshold_propname[] = "tx_bcopy_threshold";
64 64 static char rxbcopythreshold_propname[] = "rx_bcopy_threshold";
65 65 static char rxringsize_propname[] = "rx_ring_size";
66 66 static char jumborxringsize_propname[] = "jumbo_rx_ring_size";
67 67 static char txringsize_propname[] = "tx_ring_size";
68 68 static char defaultmtu_propname[] = "default_mtu";
69 69 static char dmesg_propname[] = "verbose_driver";
70 70
71 71 #define STRUCT_COPY(a, b) bcopy(&(b), &(a), sizeof (a))
72 72
73 73 extern int unm_register_mac(unm_adapter *adapter);
74 74 extern void unm_fini_kstats(unm_adapter* adapter);
75 75 extern void unm_nic_remove(unm_adapter *adapter);
76 76 extern int unm_nic_suspend(unm_adapter *);
77 77 extern uint_t unm_intr(caddr_t, caddr_t);
78 78
79 79 /* Data access requirements. */
80 80 static struct ddi_device_acc_attr unm_dev_attr = {
81 81 DDI_DEVICE_ATTR_V0,
82 82 DDI_STRUCTURE_LE_ACC,
83 83 DDI_STRICTORDER_ACC
84 84 };
85 85
86 86 static struct ddi_device_acc_attr unm_buf_attr = {
87 87 DDI_DEVICE_ATTR_V0,
88 88 DDI_NEVERSWAP_ACC,
89 89 DDI_STRICTORDER_ACC
90 90 };
91 91
92 92 static ddi_dma_attr_t unm_dma_attr_desc = {
93 93 DMA_ATTR_V0, /* dma_attr_version */
94 94 0, /* dma_attr_addr_lo */
95 95 0xffffffffull, /* dma_attr_addr_hi */
96 96 0x000fffffull, /* dma_attr_count_max */
97 97 4096, /* dma_attr_align */
98 98 0x000fffffull, /* dma_attr_burstsizes */
99 99 4, /* dma_attr_minxfer */
100 100 0x003fffffull, /* dma_attr_maxxfer */
101 101 0xffffffffull, /* dma_attr_seg */
102 102 1, /* dma_attr_sgllen */
103 103 1, /* dma_attr_granular */
104 104 0 /* dma_attr_flags */
105 105 };
106 106
107 107 static ddi_dma_attr_t unm_dma_attr_rxbuf = {
108 108 DMA_ATTR_V0, /* dma_attr_version */
109 109 0, /* dma_attr_addr_lo */
110 110 0x7ffffffffULL, /* dma_attr_addr_hi */
111 111 0xffffull, /* dma_attr_count_max */
112 112 4096, /* dma_attr_align */
113 113 0xfff8ull, /* dma_attr_burstsizes */
114 114 1, /* dma_attr_minxfer */
115 115 0xffffffffull, /* dma_attr_maxxfer */
116 116 0xffffull, /* dma_attr_seg */
117 117 1, /* dma_attr_sgllen */
118 118 1, /* dma_attr_granular */
119 119 0 /* dma_attr_flags */
120 120 };
121 121
122 122 static ddi_dma_attr_t unm_dma_attr_cmddesc = {
123 123 DMA_ATTR_V0, /* dma_attr_version */
124 124 0, /* dma_attr_addr_lo */
125 125 0x7ffffffffULL, /* dma_attr_addr_hi */
126 126 0xffffull, /* dma_attr_count_max */
127 127 1, /* dma_attr_align */
128 128 0xfff8ull, /* dma_attr_burstsizes */
129 129 1, /* dma_attr_minxfer */
130 130 0xffff0ull, /* dma_attr_maxxfer */
131 131 0xffffull, /* dma_attr_seg */
132 132 16, /* dma_attr_sgllen */
133 133 1, /* dma_attr_granular */
134 134 0 /* dma_attr_flags */
135 135 };
136 136
137 137 static struct nx_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG;
138 138
139 139 static int
140 140 check_hw_init(struct unm_adapter_s *adapter)
141 141 {
142 142 u32 val;
143 143 int ret = 0;
144 144
145 145 adapter->unm_nic_hw_read_wx(adapter, UNM_CAM_RAM(0x1fc), &val, 4);
146 146 if (val == 0x55555555) {
147 147 /* This is the first boot after power up */
148 148 adapter->unm_nic_hw_read_wx(adapter, UNM_ROMUSB_GLB_SW_RESET,
149 149 &val, 4);
150 150 if (val != 0x80000f)
151 151 ret = -1;
152 152
153 153 if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
154 154 /* Start P2 boot loader */
155 155 adapter->unm_nic_pci_write_normalize(adapter,
156 156 UNM_CAM_RAM(0x1fc), UNM_BDINFO_MAGIC);
157 157 adapter->unm_nic_pci_write_normalize(adapter,
158 158 UNM_ROMUSB_GLB_PEGTUNE_DONE, 1);
159 159 }
160 160 }
161 161 return (ret);
162 162 }
163 163
164 164
165 165 static int
166 166 unm_get_flash_block(unm_adapter *adapter, int base, int size, uint32_t *buf)
167 167 {
168 168 int i, addr;
169 169 uint32_t *ptr32;
170 170
171 171 addr = base;
172 172 ptr32 = buf;
173 173 for (i = 0; i < size / sizeof (uint32_t); i++) {
174 174 if (rom_fast_read(adapter, addr, (int *)ptr32) == -1)
175 175 return (-1);
176 176 ptr32++;
177 177 addr += sizeof (uint32_t);
178 178 }
179 179 if ((char *)buf + size > (char *)ptr32) {
180 180 int local;
181 181
182 182 if (rom_fast_read(adapter, addr, &local) == -1)
183 183 return (-1);
184 184 (void) memcpy(ptr32, &local,
185 185 (uintptr_t)((char *)buf + size) - (uintptr_t)(char *)ptr32);
186 186 }
187 187
188 188 return (0);
189 189 }
190 190
191 191
192 192 static int
193 193 get_flash_mac_addr(struct unm_adapter_s *adapter, u64 mac[])
194 194 {
195 195 uint32_t *pmac = (uint32_t *)&mac[0];
196 196
197 197 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
198 198 uint32_t temp, crbaddr;
199 199 uint16_t *pmac16 = (uint16_t *)pmac;
200 200
201 201 // FOR P3, read from CAM RAM
202 202
203 203 int pci_func = adapter->ahw.pci_func;
204 204 pmac16 += (4 * pci_func);
205 205 crbaddr = CRB_MAC_BLOCK_START + (4 * ((pci_func/2) * 3)) +
206 206 (4 * (pci_func & 1));
207 207
208 208 adapter->unm_nic_hw_read_wx(adapter, crbaddr, &temp, 4);
209 209 if (pci_func & 1) {
210 210 *pmac16++ = (temp >> 16);
211 211 adapter->unm_nic_hw_read_wx(adapter, crbaddr+4,
212 212 &temp, 4);
213 213 *pmac16++ = (temp & 0xffff);
214 214 *pmac16++ = (temp >> 16);
215 215 *pmac16 = 0;
216 216 } else {
217 217 *pmac16++ = (temp & 0xffff);
218 218 *pmac16++ = (temp >> 16);
219 219 adapter->unm_nic_hw_read_wx(adapter, crbaddr+4,
220 220 &temp, 4);
221 221 *pmac16++ = (temp & 0xffff);
222 222 *pmac16 = 0;
223 223 }
224 224 return (0);
225 225 }
226 226
227 227
228 228 if (unm_get_flash_block(adapter, USER_START +
229 229 offsetof(unm_user_info_t, mac_addr), FLASH_NUM_PORTS * sizeof (U64),
230 230 pmac) == -1)
231 231 return (-1);
232 232
233 233 if (*mac == ~0ULL) {
234 234 if (unm_get_flash_block(adapter, USER_START_OLD +
235 235 offsetof(unm_old_user_info_t, mac_addr),
236 236 FLASH_NUM_PORTS * sizeof (U64), pmac) == -1)
237 237 return (-1);
238 238
239 239 if (*mac == ~0ULL)
240 240 return (-1);
241 241 }
242 242
243 243 return (0);
244 244 }
245 245
246 246 static int
247 247 unm_initialize_dummy_dma(unm_adapter *adapter)
248 248 {
249 249 uint32_t hi, lo, temp;
250 250 ddi_dma_cookie_t cookie;
251 251
252 252 if (unm_pci_alloc_consistent(adapter, UNM_HOST_DUMMY_DMA_SIZE,
253 253 (caddr_t *)&adapter->dummy_dma.addr, &cookie,
254 254 &adapter->dummy_dma.dma_handle,
255 255 &adapter->dummy_dma.acc_handle) != DDI_SUCCESS) {
256 256 cmn_err(CE_WARN, "%s%d: Unable to alloc dummy dma buf\n",
257 257 adapter->name, adapter->instance);
258 258 return (DDI_ENOMEM);
259 259 }
260 260
261 261 adapter->dummy_dma.phys_addr = cookie.dmac_laddress;
262 262
263 263 hi = (adapter->dummy_dma.phys_addr >> 32) & 0xffffffff;
264 264 lo = adapter->dummy_dma.phys_addr & 0xffffffff;
265 265
266 266 UNM_READ_LOCK(&adapter->adapter_lock);
267 267 adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI,
268 268 &hi, 4);
269 269 adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO,
270 270 &lo, 4);
271 271 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
272 272 temp = DUMMY_BUF_INIT;
273 273 adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF,
274 274 &temp, 4);
275 275 }
276 276 UNM_READ_UNLOCK(&adapter->adapter_lock);
277 277
278 278 return (DDI_SUCCESS);
279 279 }
280 280
281 281 void
282 282 unm_free_dummy_dma(unm_adapter *adapter)
283 283 {
284 284 if (adapter->dummy_dma.addr) {
285 285 unm_pci_free_consistent(&adapter->dummy_dma.dma_handle,
286 286 &adapter->dummy_dma.acc_handle);
287 287 adapter->dummy_dma.addr = NULL;
288 288 }
289 289 }
290 290
291 291 static int
292 292 unm_pci_cfg_init(unm_adapter *adapter)
293 293 {
294 294 hardware_context *hwcontext;
295 295 ddi_acc_handle_t pci_cfg_hdl;
296 296 int *reg_options;
297 297 dev_info_t *dip;
298 298 uint_t noptions;
299 299 int ret;
300 300 uint16_t vendor_id, pci_cmd_word;
301 301 uint8_t base_class, sub_class, prog_class;
302 302 uint32_t pexsizes;
303 303 struct nx_legacy_intr_set *legacy_intrp;
304 304
305 305 hwcontext = &adapter->ahw;
306 306 pci_cfg_hdl = adapter->pci_cfg_handle;
307 307 dip = adapter->dip;
308 308
309 309 vendor_id = pci_config_get16(pci_cfg_hdl, PCI_CONF_VENID);
310 310
311 311 if (vendor_id != 0x4040) {
312 312 cmn_err(CE_WARN, "%s%d: vendor id %x not 0x4040\n",
313 313 adapter->name, adapter->instance, vendor_id);
314 314 return (DDI_FAILURE);
315 315 }
316 316
317 317 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
318 318 dip, 0, "reg", ®_options, &noptions);
319 319 if (ret != DDI_PROP_SUCCESS) {
320 320 cmn_err(CE_WARN, "%s%d: Could not determine reg property\n",
321 321 adapter->name, adapter->instance);
322 322 return (DDI_FAILURE);
323 323 }
324 324
325 325 hwcontext->pci_func = (reg_options[0] >> 8) & 0x7;
326 326 ddi_prop_free(reg_options);
327 327
328 328 base_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_BASCLASS);
329 329 sub_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_SUBCLASS);
330 330 prog_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_PROGCLASS);
331 331
332 332 /*
333 333 * Need this check so that MEZZ card mgmt interface ntxn0 could fail
334 334 * attach & return and proceed to next interfaces ntxn1 and ntxn2
335 335 */
336 336 if ((base_class != 0x02) || (sub_class != 0) || (prog_class != 0)) {
337 337 cmn_err(CE_WARN, "%s%d: Base/sub/prog class problem %d/%d/%d\n",
338 338 adapter->name, adapter->instance, base_class, sub_class,
339 339 prog_class);
340 340 return (DDI_FAILURE);
341 341 }
342 342
343 343 hwcontext->revision_id = pci_config_get8(pci_cfg_hdl, PCI_CONF_REVID);
344 344
345 345 /*
346 346 * Refuse to work with dubious P3 cards.
347 347 */
348 348 if ((hwcontext->revision_id >= NX_P3_A0) &&
349 349 (hwcontext->revision_id < NX_P3_B1)) {
350 350 cmn_err(CE_WARN, "%s%d: NetXen chip revs between 0x%x-0x%x "
351 351 "is unsupported\n", adapter->name, adapter->instance,
352 352 NX_P3_A0, NX_P3_B0);
353 353 return (DDI_FAILURE);
354 354 }
355 355
356 356 /*
357 357 * Save error reporting settings; clear [19:16] error status bits.
358 358 * Set max read request [14:12] to 0 for 128 bytes. Set max payload
359 359 * size[7:5] to 0 for for 128 bytes.
360 360 */
361 361 if (NX_IS_REVISION_P2(hwcontext->revision_id)) {
362 362 pexsizes = pci_config_get32(pci_cfg_hdl, 0xd8);
363 363 pexsizes &= 7;
364 364 pexsizes |= 0xF0000;
365 365 pci_config_put32(pci_cfg_hdl, 0xd8, pexsizes);
366 366 }
367 367
368 368 pci_cmd_word = pci_config_get16(pci_cfg_hdl, PCI_CONF_COMM);
369 369 pci_cmd_word |= (PCI_COMM_INTX_DISABLE | PCI_COMM_SERR_ENABLE);
370 370 pci_config_put16(pci_cfg_hdl, PCI_CONF_COMM, pci_cmd_word);
371 371
372 372 if (hwcontext->revision_id >= NX_P3_B0)
373 373 legacy_intrp = &legacy_intr[hwcontext->pci_func];
374 374 else
375 375 legacy_intrp = &legacy_intr[0];
376 376
377 377 adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit;
378 378 adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg;
379 379 adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg;
380 380 adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg;
381 381
382 382 return (DDI_SUCCESS);
383 383 }
384 384
385 385 static void
386 386 unm_free_tx_dmahdl(unm_adapter *adapter)
387 387 {
388 388 int i;
389 389 unm_dmah_node_t *nodep;
390 390
391 391 mutex_enter(&adapter->tx_lock);
392 392 nodep = &adapter->tx_dma_hdls[0];
393 393
394 394 for (i = 0; i < adapter->MaxTxDescCount + EXTRA_HANDLES; i++) {
395 395 if (nodep->dmahdl != NULL) {
396 396 ddi_dma_free_handle(&nodep->dmahdl);
397 397 nodep->dmahdl = NULL;
398 398 }
399 399 nodep->next = NULL;
400 400 nodep++;
401 401 }
402 402
403 403 adapter->dmahdl_pool = NULL;
404 404 adapter->freehdls = 0;
405 405 mutex_exit(&adapter->tx_lock);
406 406 }
407 407
408 408 static int
409 409 unm_alloc_tx_dmahdl(unm_adapter *adapter)
410 410 {
411 411 int i;
412 412 unm_dmah_node_t *nodep = &adapter->tx_dma_hdls[0];
413 413
414 414 mutex_enter(&adapter->tx_lock);
415 415 for (i = 0; i < adapter->MaxTxDescCount + EXTRA_HANDLES; i++) {
416 416 if (ddi_dma_alloc_handle(adapter->dip, &unm_dma_attr_cmddesc,
417 417 DDI_DMA_DONTWAIT, NULL, &nodep->dmahdl) != DDI_SUCCESS) {
418 418 mutex_exit(&adapter->tx_lock);
419 419 goto alloc_hdl_fail;
420 420 }
421 421
422 422 if (i > 0)
423 423 nodep->next = nodep - 1;
424 424 nodep++;
425 425 }
426 426
427 427 adapter->dmahdl_pool = nodep - 1;
428 428 adapter->freehdls = i;
429 429 mutex_exit(&adapter->tx_lock);
430 430
431 431 return (DDI_SUCCESS);
432 432
433 433 alloc_hdl_fail:
434 434 unm_free_tx_dmahdl(adapter);
435 435 cmn_err(CE_WARN, "%s%d: Failed transmit ring dma handle allocation\n",
436 436 adapter->name, adapter->instance);
437 437 return (DDI_FAILURE);
438 438 }
439 439
440 440 static void
441 441 unm_free_dma_mem(dma_area_t *dma_p)
442 442 {
443 443 if (dma_p->dma_hdl != NULL) {
444 444 if (dma_p->ncookies) {
445 445 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
446 446 dma_p->ncookies = 0;
447 447 }
448 448 }
449 449 if (dma_p->acc_hdl != NULL) {
450 450 ddi_dma_mem_free(&dma_p->acc_hdl);
451 451 dma_p->acc_hdl = NULL;
452 452 }
453 453 if (dma_p->dma_hdl != NULL) {
454 454 ddi_dma_free_handle(&dma_p->dma_hdl);
455 455 dma_p->dma_hdl = NULL;
456 456 }
457 457 }
458 458
459 459 static int
460 460 unm_alloc_dma_mem(unm_adapter *adapter, int size, uint_t dma_flag,
461 461 ddi_dma_attr_t *dma_attr_p, dma_area_t *dma_p)
462 462 {
463 463 int ret;
464 464 caddr_t vaddr;
465 465 size_t actual_size;
466 466 ddi_dma_cookie_t cookie;
467 467
468 468 ret = ddi_dma_alloc_handle(adapter->dip,
469 469 dma_attr_p, DDI_DMA_DONTWAIT,
470 470 NULL, &dma_p->dma_hdl);
471 471 if (ret != DDI_SUCCESS) {
472 472 cmn_err(CE_WARN, "%s%d: Failed ddi_dma_alloc_handle\n",
473 473 adapter->name, adapter->instance);
474 474 goto dma_mem_fail;
475 475 }
476 476
477 477 ret = ddi_dma_mem_alloc(dma_p->dma_hdl,
478 478 size, &adapter->gc_attr_desc,
479 479 dma_flag & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT),
480 480 DDI_DMA_DONTWAIT, NULL, &vaddr, &actual_size,
481 481 &dma_p->acc_hdl);
482 482 if (ret != DDI_SUCCESS) {
483 483 cmn_err(CE_WARN, "%s%d: ddi_dma_mem_alloc() failed\n",
484 484 adapter->name, adapter->instance);
485 485 goto dma_mem_fail;
486 486 }
487 487
488 488 if (actual_size < size) {
489 489 cmn_err(CE_WARN, "%s%d: ddi_dma_mem_alloc() allocated small\n",
490 490 adapter->name, adapter->instance);
491 491 goto dma_mem_fail;
492 492 }
493 493
494 494 ret = ddi_dma_addr_bind_handle(dma_p->dma_hdl,
495 495 NULL, vaddr, size, dma_flag, DDI_DMA_DONTWAIT,
496 496 NULL, &cookie, &dma_p->ncookies);
497 497 if (ret != DDI_DMA_MAPPED || dma_p->ncookies != 1) {
498 498 cmn_err(CE_WARN, "%s%d: ddi_dma_addr_bind_handle() failed, "
499 499 "%d, %d\n", adapter->name, adapter->instance, ret,
500 500 dma_p->ncookies);
501 501 goto dma_mem_fail;
502 502 }
503 503
504 504 dma_p->dma_addr = cookie.dmac_laddress;
505 505 dma_p->vaddr = vaddr;
506 506 (void) memset(vaddr, 0, size);
507 507
508 508 return (DDI_SUCCESS);
509 509
510 510 dma_mem_fail:
511 511 unm_free_dma_mem(dma_p);
512 512 return (DDI_FAILURE);
513 513 }
514 514
515 515 static void
516 516 unm_free_tx_buffers(unm_adapter *adapter)
517 517 {
518 518 int i;
519 519 dma_area_t *dma_p;
520 520 struct unm_cmd_buffer *cmd_buf;
521 521 unm_dmah_node_t *nodep;
522 522
523 523 cmd_buf = &adapter->cmd_buf_arr[0];
524 524
525 525 for (i = 0; i < adapter->MaxTxDescCount; i++) {
526 526 dma_p = &cmd_buf->dma_area;
527 527 unm_free_dma_mem(dma_p);
528 528 nodep = cmd_buf->head;
529 529 while (nodep != NULL) {
530 530 (void) ddi_dma_unbind_handle(nodep->dmahdl);
531 531 nodep = nodep->next;
532 532 }
533 533 if (cmd_buf->msg != NULL)
534 534 freemsg(cmd_buf->msg);
535 535 cmd_buf++;
536 536 }
537 537 adapter->freecmds = 0;
538 538 }
539 539
540 540 static int
541 541 unm_alloc_tx_buffers(unm_adapter *adapter)
542 542 {
543 543 int i, ret, size, allocated = 0;
544 544 dma_area_t *dma_p;
545 545 struct unm_cmd_buffer *cmd_buf;
546 546
547 547 cmd_buf = &adapter->cmd_buf_arr[0];
548 548 size = adapter->maxmtu;
549 549
550 550 for (i = 0; i < adapter->MaxTxDescCount; i++) {
551 551 dma_p = &cmd_buf->dma_area;
552 552 ret = unm_alloc_dma_mem(adapter, size,
553 553 DDI_DMA_WRITE | DDI_DMA_STREAMING,
554 554 &unm_dma_attr_rxbuf, dma_p);
555 555 if (ret != DDI_SUCCESS)
556 556 goto alloc_tx_buffer_fail;
557 557
558 558 allocated++;
559 559 cmd_buf++;
560 560 }
561 561 adapter->freecmds = adapter->MaxTxDescCount;
562 562 return (DDI_SUCCESS);
563 563
564 564 alloc_tx_buffer_fail:
565 565
566 566 cmd_buf = &adapter->cmd_buf_arr[0];
567 567 for (i = 0; i < allocated; i++) {
568 568 dma_p = &cmd_buf->dma_area;
569 569 unm_free_dma_mem(dma_p);
570 570 cmd_buf++;
571 571 }
572 572 cmn_err(CE_WARN, "%s%d: Failed transmit ring memory allocation\n",
573 573 adapter->name, adapter->instance);
574 574 return (DDI_FAILURE);
575 575 }
576 576
577 577 /*
578 578 * Called by freemsg() to "free" the resource.
579 579 */
580 580 static void
581 581 unm_rx_buffer_recycle(char *arg)
582 582 {
583 583 unm_rx_buffer_t *rx_buffer = (unm_rx_buffer_t *)(uintptr_t)arg;
584 584 unm_adapter *adapter = rx_buffer->adapter;
585 585 unm_rcv_desc_ctx_t *rcv_desc = rx_buffer->rcv_desc;
586 586
587 587 rx_buffer->mp = desballoc(rx_buffer->dma_info.vaddr,
588 588 rcv_desc->dma_size, 0, &rx_buffer->rx_recycle);
589 589
590 590 if (rx_buffer->mp == NULL)
591 591 adapter->stats.desballocfailed++;
592 592
593 593 mutex_enter(rcv_desc->recycle_lock);
594 594 rx_buffer->next = rcv_desc->recycle_list;
595 595 rcv_desc->recycle_list = rx_buffer;
596 596 rcv_desc->rx_buf_recycle++;
597 597 mutex_exit(rcv_desc->recycle_lock);
598 598 }
599 599
600 600 static void
601 601 unm_destroy_rx_ring(unm_rcv_desc_ctx_t *rcv_desc)
602 602 {
603 603 uint32_t i, total_buf;
604 604 unm_rx_buffer_t *buf_pool;
605 605
606 606 total_buf = rcv_desc->rx_buf_total;
607 607 buf_pool = rcv_desc->rx_buf_pool;
608 608 for (i = 0; i < total_buf; i++) {
609 609 if (buf_pool->mp != NULL)
610 610 freemsg(buf_pool->mp);
611 611 unm_free_dma_mem(&buf_pool->dma_info);
612 612 buf_pool++;
613 613 }
614 614
615 615 kmem_free(rcv_desc->rx_buf_pool, sizeof (unm_rx_buffer_t) * total_buf);
616 616 rcv_desc->rx_buf_pool = NULL;
617 617 rcv_desc->pool_list = NULL;
618 618 rcv_desc->recycle_list = NULL;
619 619 rcv_desc->rx_buf_free = 0;
620 620
621 621 mutex_destroy(rcv_desc->pool_lock);
622 622 mutex_destroy(rcv_desc->recycle_lock);
623 623 }
624 624
625 625 static int
626 626 unm_create_rx_ring(unm_adapter *adapter, unm_rcv_desc_ctx_t *rcv_desc)
627 627 {
628 628 int i, ret, allocate = 0, sreoff;
629 629 uint32_t total_buf;
630 630 dma_area_t *dma_info;
631 631 unm_rx_buffer_t *rx_buffer;
632 632
633 633 sreoff = adapter->ahw.cut_through ? 0 : IP_ALIGNMENT_BYTES;
634 634
635 635 /* temporarily set the total rx buffers two times of MaxRxDescCount */
636 636 total_buf = rcv_desc->rx_buf_total = rcv_desc->MaxRxDescCount * 2;
637 637
638 638 rcv_desc->rx_buf_pool = kmem_zalloc(sizeof (unm_rx_buffer_t) *
639 639 total_buf, KM_SLEEP);
640 640 rx_buffer = rcv_desc->rx_buf_pool;
641 641 for (i = 0; i < total_buf; i++) {
642 642 dma_info = &rx_buffer->dma_info;
643 643 ret = unm_alloc_dma_mem(adapter, rcv_desc->buf_size,
644 644 DDI_DMA_READ | DDI_DMA_STREAMING,
645 645 &unm_dma_attr_rxbuf, dma_info);
646 646 if (ret != DDI_SUCCESS)
647 647 goto alloc_mem_failed;
648 648 else {
649 649 allocate++;
650 650 dma_info->vaddr = (void *) ((char *)dma_info->vaddr +
651 651 sreoff);
652 652 dma_info->dma_addr += sreoff;
653 653 rx_buffer->rx_recycle.free_func =
654 654 unm_rx_buffer_recycle;
655 655 rx_buffer->rx_recycle.free_arg = (caddr_t)rx_buffer;
656 656 rx_buffer->next = NULL;
657 657 rx_buffer->mp = desballoc(dma_info->vaddr,
658 658 rcv_desc->dma_size, 0, &rx_buffer->rx_recycle);
659 659 if (rx_buffer->mp == NULL)
660 660 adapter->stats.desballocfailed++;
661 661 rx_buffer->rcv_desc = rcv_desc;
662 662 rx_buffer->adapter = adapter;
663 663 rx_buffer++;
664 664 }
665 665 }
666 666
667 667 for (i = 0; i < (total_buf - 1); i++) {
668 668 rcv_desc->rx_buf_pool[i].next = &rcv_desc->rx_buf_pool[i + 1];
669 669 }
670 670
671 671 rcv_desc->pool_list = rcv_desc->rx_buf_pool;
672 672 rcv_desc->recycle_list = NULL;
673 673 rcv_desc->rx_buf_free = total_buf;
674 674
675 675 mutex_init(rcv_desc->pool_lock, NULL,
676 676 MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri)));
677 677 mutex_init(rcv_desc->recycle_lock, NULL,
678 678 MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri)));
679 679
680 680 return (DDI_SUCCESS);
681 681
682 682 alloc_mem_failed:
683 683 rx_buffer = rcv_desc->rx_buf_pool;
684 684 for (i = 0; i < allocate; i++, rx_buffer++) {
685 685 dma_info = &rx_buffer->dma_info;
686 686 if (rx_buffer->mp != NULL)
687 687 freemsg(rx_buffer->mp);
688 688 unm_free_dma_mem(dma_info);
689 689 }
690 690
691 691 kmem_free(rcv_desc->rx_buf_pool, sizeof (unm_rx_buffer_t) * total_buf);
692 692 rcv_desc->rx_buf_pool = NULL;
693 693
694 694 cmn_err(CE_WARN, "%s%d: Failed receive ring resource allocation\n",
695 695 adapter->name, adapter->instance);
696 696 return (DDI_FAILURE);
697 697 }
698 698
699 699 static void
700 700 unm_check_options(unm_adapter *adapter)
701 701 {
702 702 int i, ring, tx_desc, rx_desc, rx_jdesc, maxrx;
703 703 unm_recv_context_t *recv_ctx;
704 704 unm_rcv_desc_ctx_t *rcv_desc;
705 705 uint8_t revid = adapter->ahw.revision_id;
706 706 dev_info_t *dip = adapter->dip;
707 707
708 708 /*
709 709 * Reduce number of regular rcv desc to half on x86.
710 710 */
711 711 maxrx = MAX_RCV_DESCRIPTORS;
712 712 #if !defined(_LP64)
713 713 maxrx /= 2;
714 714 #endif /* !_LP64 */
715 715
716 716 verbmsg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
717 717 dmesg_propname, 0);
718 718
719 719 adapter->tx_bcopy_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
720 720 dip, DDI_PROP_DONTPASS, txbcopythreshold_propname,
721 721 UNM_TX_BCOPY_THRESHOLD);
722 722 adapter->rx_bcopy_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
723 723 dip, DDI_PROP_DONTPASS, rxbcopythreshold_propname,
724 724 UNM_RX_BCOPY_THRESHOLD);
725 725
726 726 tx_desc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
727 727 txringsize_propname, MAX_CMD_DESCRIPTORS_HOST);
728 728 if (tx_desc >= 256 && tx_desc <= MAX_CMD_DESCRIPTORS && ISP2(tx_desc)) {
729 729 adapter->MaxTxDescCount = tx_desc;
730 730 } else {
731 731 cmn_err(CE_WARN, "%s%d: TxRingSize defaulting to %d, since "
732 732 ".conf value is not 2 power aligned in range 256 - %d\n",
733 733 adapter->name, adapter->instance, MAX_CMD_DESCRIPTORS_HOST,
734 734 MAX_CMD_DESCRIPTORS);
735 735 adapter->MaxTxDescCount = MAX_CMD_DESCRIPTORS_HOST;
736 736 }
737 737
738 738 rx_desc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
739 739 rxringsize_propname, maxrx);
740 740 if (rx_desc >= NX_MIN_DRIVER_RDS_SIZE &&
741 741 rx_desc <= NX_MAX_SUPPORTED_RDS_SIZE && ISP2(rx_desc)) {
742 742 adapter->MaxRxDescCount = rx_desc;
743 743 } else {
744 744 cmn_err(CE_WARN, "%s%d: RxRingSize defaulting to %d, since "
745 745 ".conf value is not 2 power aligned in range %d - %d\n",
746 746 adapter->name, adapter->instance, MAX_RCV_DESCRIPTORS,
747 747 NX_MIN_DRIVER_RDS_SIZE, NX_MAX_SUPPORTED_RDS_SIZE);
748 748 adapter->MaxRxDescCount = MAX_RCV_DESCRIPTORS;
749 749 }
750 750
751 751 rx_jdesc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
752 752 jumborxringsize_propname, MAX_JUMBO_RCV_DESCRIPTORS);
753 753 if (rx_jdesc >= NX_MIN_DRIVER_RDS_SIZE &&
754 754 rx_jdesc <= NX_MAX_SUPPORTED_JUMBO_RDS_SIZE && ISP2(rx_jdesc)) {
755 755 adapter->MaxJumboRxDescCount = rx_jdesc;
756 756 } else {
757 757 cmn_err(CE_WARN, "%s%d: JumboRingSize defaulting to %d, since "
758 758 ".conf value is not 2 power aligned in range %d - %d\n",
759 759 adapter->name, adapter->instance, MAX_JUMBO_RCV_DESCRIPTORS,
760 760 NX_MIN_DRIVER_RDS_SIZE, NX_MAX_SUPPORTED_JUMBO_RDS_SIZE);
761 761 adapter->MaxJumboRxDescCount = MAX_JUMBO_RCV_DESCRIPTORS;
762 762 }
763 763
764 764 /*
765 765 * Solaris does not use LRO, but older firmware needs to have a
766 766 * couple of descriptors for initialization.
767 767 */
768 768 adapter->MaxLroRxDescCount = (adapter->fw_major < 4) ? 2 : 0;
769 769
770 770 adapter->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
771 771 DDI_PROP_DONTPASS, defaultmtu_propname, MTU_SIZE);
772 772
773 773 if (adapter->mtu < MTU_SIZE) {
774 774 cmn_err(CE_WARN, "Raising mtu to %d\n", MTU_SIZE);
775 775 adapter->mtu = MTU_SIZE;
776 776 }
777 777 adapter->maxmtu = NX_IS_REVISION_P2(revid) ? P2_MAX_MTU : P3_MAX_MTU;
778 778 if (adapter->mtu > adapter->maxmtu) {
779 779 cmn_err(CE_WARN, "Lowering mtu to %d\n", adapter->maxmtu);
780 780 adapter->mtu = adapter->maxmtu;
781 781 }
782 782
783 783 adapter->maxmtu = adapter->mtu + NX_MAX_ETHERHDR;
784 784
785 785 /*
786 786 * If we are not expecting to receive jumbo frames, save memory and
787 787 * do not allocate.
788 788 */
789 789 if (adapter->mtu <= MTU_SIZE)
790 790 adapter->MaxJumboRxDescCount = NX_MIN_DRIVER_RDS_SIZE;
791 791
792 792 for (i = 0; i < MAX_RCV_CTX; ++i) {
793 793 recv_ctx = &adapter->recv_ctx[i];
794 794
795 795 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
796 796 rcv_desc = &recv_ctx->rcv_desc[ring];
797 797
798 798 switch (RCV_DESC_TYPE(ring)) {
799 799 case RCV_DESC_NORMAL:
800 800 rcv_desc->MaxRxDescCount =
801 801 adapter->MaxRxDescCount;
802 802 if (adapter->ahw.cut_through) {
803 803 rcv_desc->dma_size =
804 804 NX_CT_DEFAULT_RX_BUF_LEN;
805 805 rcv_desc->buf_size = rcv_desc->dma_size;
806 806 } else {
807 807 rcv_desc->dma_size =
808 808 NX_RX_NORMAL_BUF_MAX_LEN;
809 809 rcv_desc->buf_size =
810 810 rcv_desc->dma_size +
811 811 IP_ALIGNMENT_BYTES;
812 812 }
813 813 break;
814 814
815 815 case RCV_DESC_JUMBO:
816 816 rcv_desc->MaxRxDescCount =
817 817 adapter->MaxJumboRxDescCount;
818 818 if (adapter->ahw.cut_through) {
819 819 rcv_desc->dma_size =
820 820 rcv_desc->buf_size =
821 821 NX_P3_RX_JUMBO_BUF_MAX_LEN;
822 822 } else {
823 823 if (NX_IS_REVISION_P2(revid))
824 824 rcv_desc->dma_size =
825 825 NX_P2_RX_JUMBO_BUF_MAX_LEN;
826 826 else
827 827 rcv_desc->dma_size =
828 828 NX_P3_RX_JUMBO_BUF_MAX_LEN;
829 829 rcv_desc->buf_size =
830 830 rcv_desc->dma_size +
831 831 IP_ALIGNMENT_BYTES;
832 832 }
833 833 break;
834 834
835 835 case RCV_RING_LRO:
836 836 rcv_desc->MaxRxDescCount =
837 837 adapter->MaxLroRxDescCount;
838 838 rcv_desc->buf_size = MAX_RX_LRO_BUFFER_LENGTH;
839 839 rcv_desc->dma_size = RX_LRO_DMA_MAP_LEN;
840 840 break;
841 841 default:
842 842 break;
843 843 }
844 844 }
845 845 }
846 846 }
847 847
848 848 static void
849 849 vector128M(unm_adapter *aptr)
850 850 {
851 851 aptr->unm_nic_pci_change_crbwindow = &unm_nic_pci_change_crbwindow_128M;
852 852 aptr->unm_crb_writelit_adapter = &unm_crb_writelit_adapter_128M;
853 853 aptr->unm_nic_hw_write_wx = &unm_nic_hw_write_wx_128M;
854 854 aptr->unm_nic_hw_read_wx = &unm_nic_hw_read_wx_128M;
855 855 aptr->unm_nic_hw_write_ioctl = &unm_nic_hw_write_ioctl_128M;
856 856 aptr->unm_nic_hw_read_ioctl = &unm_nic_hw_read_ioctl_128M;
857 857 aptr->unm_nic_pci_mem_write = &unm_nic_pci_mem_write_128M;
858 858 aptr->unm_nic_pci_mem_read = &unm_nic_pci_mem_read_128M;
859 859 aptr->unm_nic_pci_write_immediate = &unm_nic_pci_write_immediate_128M;
860 860 aptr->unm_nic_pci_read_immediate = &unm_nic_pci_read_immediate_128M;
861 861 aptr->unm_nic_pci_write_normalize = &unm_nic_pci_write_normalize_128M;
862 862 aptr->unm_nic_pci_read_normalize = &unm_nic_pci_read_normalize_128M;
863 863 aptr->unm_nic_pci_set_window = &unm_nic_pci_set_window_128M;
864 864 aptr->unm_nic_clear_statistics = &unm_nic_clear_statistics_128M;
865 865 aptr->unm_nic_fill_statistics = &unm_nic_fill_statistics_128M;
866 866 }
867 867
868 868 static void
869 869 vector2M(unm_adapter *aptr)
870 870 {
871 871 aptr->unm_nic_pci_change_crbwindow = &unm_nic_pci_change_crbwindow_2M;
872 872 aptr->unm_crb_writelit_adapter = &unm_crb_writelit_adapter_2M;
873 873 aptr->unm_nic_hw_write_wx = &unm_nic_hw_write_wx_2M;
874 874 aptr->unm_nic_hw_read_wx = &unm_nic_hw_read_wx_2M;
875 875 aptr->unm_nic_hw_write_ioctl = &unm_nic_hw_write_wx_2M;
876 876 aptr->unm_nic_hw_read_ioctl = &unm_nic_hw_read_wx_2M;
877 877 aptr->unm_nic_pci_mem_write = &unm_nic_pci_mem_write_2M;
878 878 aptr->unm_nic_pci_mem_read = &unm_nic_pci_mem_read_2M;
879 879 aptr->unm_nic_pci_write_immediate = &unm_nic_pci_write_immediate_2M;
880 880 aptr->unm_nic_pci_read_immediate = &unm_nic_pci_read_immediate_2M;
881 881 aptr->unm_nic_pci_write_normalize = &unm_nic_pci_write_normalize_2M;
882 882 aptr->unm_nic_pci_read_normalize = &unm_nic_pci_read_normalize_2M;
883 883 aptr->unm_nic_pci_set_window = &unm_nic_pci_set_window_2M;
884 884 aptr->unm_nic_clear_statistics = &unm_nic_clear_statistics_2M;
885 885 aptr->unm_nic_fill_statistics = &unm_nic_fill_statistics_2M;
886 886 }
887 887
888 888 static int
889 889 unm_pci_map_setup(unm_adapter *adapter)
890 890 {
891 891 int ret;
892 892 caddr_t reg_base, db_base;
893 893 caddr_t mem_ptr0, mem_ptr1 = NULL, mem_ptr2 = NULL;
894 894 unsigned long pci_len0;
895 895 unsigned long first_page_group_start, first_page_group_end;
896 896
897 897 off_t regsize, dbsize = UNM_DB_MAPSIZE_BYTES;
898 898 dev_info_t *dip = adapter->dip;
899 899
900 900 adapter->ahw.qdr_sn_window = adapter->ahw.ddr_mn_window = -1;
901 901
902 902 /* map register space */
903 903
904 904 ret = ddi_dev_regsize(dip, 1, ®size);
905 905 if (ret != DDI_SUCCESS) {
906 906 cmn_err(CE_WARN, "%s%d: failed to read reg size for bar0\n",
907 907 adapter->name, adapter->instance);
908 908 return (DDI_FAILURE);
909 909 }
910 910
911 911 ret = ddi_regs_map_setup(dip, 1, ®_base, 0,
912 912 regsize, &unm_dev_attr, &adapter->regs_handle);
913 913 if (ret != DDI_SUCCESS) {
914 914 cmn_err(CE_WARN, "%s%d: failed to map registers\n",
915 915 adapter->name, adapter->instance);
916 916 return (DDI_FAILURE);
917 917 }
918 918
919 919 mem_ptr0 = reg_base;
920 920
921 921 if (regsize == UNM_PCI_128MB_SIZE) {
922 922 pci_len0 = FIRST_PAGE_GROUP_SIZE;
923 923 mem_ptr1 = mem_ptr0 + SECOND_PAGE_GROUP_START;
924 924 mem_ptr2 = mem_ptr0 + THIRD_PAGE_GROUP_START;
925 925 first_page_group_start = FIRST_PAGE_GROUP_START;
926 926 first_page_group_end = FIRST_PAGE_GROUP_END;
927 927 vector128M(adapter);
928 928 } else if (regsize == UNM_PCI_32MB_SIZE) {
929 929 pci_len0 = 0;
930 930 mem_ptr1 = mem_ptr0;
931 931 mem_ptr2 = mem_ptr0 +
932 932 (THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START);
933 933 first_page_group_start = 0;
934 934 first_page_group_end = 0;
935 935 vector128M(adapter);
936 936 } else if (regsize == UNM_PCI_2MB_SIZE) {
937 937 pci_len0 = UNM_PCI_2MB_SIZE;
938 938 first_page_group_start = 0;
939 939 first_page_group_end = 0;
940 940 adapter->ahw.ddr_mn_window = adapter->ahw.qdr_sn_window = 0;
941 941 adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW +
942 942 (adapter->ahw.pci_func * 0x20);
943 943 if (adapter->ahw.pci_func < 4)
944 944 adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW +
945 945 (adapter->ahw.pci_func * 0x20);
946 946 else
947 947 adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW +
948 948 0xA0 + ((adapter->ahw.pci_func - 4) * 0x10);
949 949 vector2M(adapter);
950 950 } else {
951 951 cmn_err(CE_WARN, "%s%d: invalid pci regs map size %ld\n",
952 952 adapter->name, adapter->instance, regsize);
953 953 ddi_regs_map_free(&adapter->regs_handle);
954 954 return (DDI_FAILURE);
955 955 }
956 956
957 957 adapter->ahw.pci_base0 = (unsigned long)mem_ptr0;
958 958 adapter->ahw.pci_len0 = pci_len0;
959 959 adapter->ahw.pci_base1 = (unsigned long)mem_ptr1;
960 960 adapter->ahw.pci_len1 = SECOND_PAGE_GROUP_SIZE;
961 961 adapter->ahw.pci_base2 = (unsigned long)mem_ptr2;
962 962 adapter->ahw.pci_len2 = THIRD_PAGE_GROUP_SIZE;
963 963 adapter->ahw.crb_base =
964 964 PCI_OFFSET_SECOND_RANGE(adapter, UNM_PCI_CRBSPACE);
965 965
966 966 adapter->ahw.first_page_group_start = first_page_group_start;
967 967 adapter->ahw.first_page_group_end = first_page_group_end;
968 968
969 969 /* map doorbell */
970 970
971 971 ret = ddi_regs_map_setup(dip, 2, &db_base, 0,
972 972 dbsize, &unm_dev_attr, &adapter->db_handle);
973 973 if (ret != DDI_SUCCESS) {
974 974 cmn_err(CE_WARN, "%s%d: failed to map doorbell\n",
975 975 adapter->name, adapter->instance);
976 976 ddi_regs_map_free(&adapter->regs_handle);
977 977 return (DDI_FAILURE);
978 978 }
979 979
980 980 adapter->ahw.db_base = (unsigned long)db_base;
981 981 adapter->ahw.db_len = dbsize;
982 982
983 983 return (DDI_SUCCESS);
984 984 }
985 985
986 986 static int
987 987 unm_initialize_intr(unm_adapter *adapter)
988 988 {
989 989
990 990 int ret;
991 991 int type, count, avail, actual;
992 992
993 993 ret = ddi_intr_get_supported_types(adapter->dip, &type);
994 994 if (ret != DDI_SUCCESS) {
995 995 cmn_err(CE_WARN, "%s%d: ddi_intr_get_supported_types() "
996 996 "failed\n", adapter->name, adapter->instance);
997 997 return (DDI_FAILURE);
998 998 }
999 999
1000 1000 type = DDI_INTR_TYPE_MSI;
1001 1001 ret = ddi_intr_get_nintrs(adapter->dip, type, &count);
1002 1002 if ((ret == DDI_SUCCESS) && (count > 0))
1003 1003 goto found_msi;
1004 1004
1005 1005 type = DDI_INTR_TYPE_FIXED;
1006 1006 ret = ddi_intr_get_nintrs(adapter->dip, type, &count);
1007 1007 if ((ret != DDI_SUCCESS) || (count == 0)) {
1008 1008 cmn_err(CE_WARN,
1009 1009 "ddi_intr_get_nintrs() failure ret=%d\n", ret);
1010 1010 return (DDI_FAILURE);
1011 1011 }
1012 1012
1013 1013 found_msi:
1014 1014 adapter->intr_type = type;
1015 1015 adapter->flags &= ~(UNM_NIC_MSI_ENABLED | UNM_NIC_MSIX_ENABLED);
1016 1016 if (type == DDI_INTR_TYPE_MSI)
1017 1017 adapter->flags |= UNM_NIC_MSI_ENABLED;
1018 1018
1019 1019 /* Get number of available interrupts */
1020 1020 ret = ddi_intr_get_navail(adapter->dip, type, &avail);
1021 1021 if ((ret != DDI_SUCCESS) || (avail == 0)) {
1022 1022 cmn_err(CE_WARN, "ddi_intr_get_navail() failure, ret=%d\n",
1023 1023 ret);
1024 1024 return (DDI_FAILURE);
1025 1025 }
1026 1026
1027 1027 ret = ddi_intr_alloc(adapter->dip, &adapter->intr_handle,
1028 1028 type, 0, 1, &actual, DDI_INTR_ALLOC_NORMAL);
1029 1029 if ((ret != DDI_SUCCESS) || (actual == 0)) {
1030 1030 cmn_err(CE_WARN, "ddi_intr_alloc() failure: %d\n", ret);
1031 1031 return (DDI_FAILURE);
1032 1032 }
1033 1033
1034 1034 ret = ddi_intr_get_pri(adapter->intr_handle, &adapter->intr_pri);
1035 1035 if (ret != DDI_SUCCESS) {
1036 1036 cmn_err(CE_WARN, "ddi_intr_get_pri() failure: %d\n", ret);
1037 1037 }
1038 1038
1039 1039 /* Call ddi_intr_add_handler() */
1040 1040 ret = ddi_intr_add_handler(adapter->intr_handle, unm_intr,
1041 1041 (caddr_t)adapter, NULL);
1042 1042 if (ret != DDI_SUCCESS) {
1043 1043 cmn_err(CE_WARN, "%s%d: ddi_intr_add_handler() failure\n",
1044 1044 adapter->name, adapter->instance);
1045 1045 (void) ddi_intr_free(adapter->intr_handle);
1046 1046 return (DDI_FAILURE);
1047 1047 }
1048 1048
1049 1049 /* Add softintr if required */
1050 1050
1051 1051 return (DDI_SUCCESS);
1052 1052
1053 1053 }
1054 1054
1055 1055 void
1056 1056 unm_destroy_intr(unm_adapter *adapter)
1057 1057 {
1058 1058 /* disable interrupt */
1059 1059 if (adapter->intr_type == DDI_INTR_TYPE_MSI)
1060 1060 (void) ddi_intr_block_disable(&adapter->intr_handle, 1);
1061 1061 else
1062 1062 (void) ddi_intr_disable(adapter->intr_handle);
1063 1063
1064 1064 (void) ddi_intr_remove_handler(adapter->intr_handle);
1065 1065 (void) ddi_intr_free(adapter->intr_handle);
1066 1066
1067 1067 /* Remove the software intr handler */
1068 1068 }
1069 1069
1070 1070 static void
1071 1071 netxen_set_port_mode(unm_adapter *adapter)
1072 1072 {
1073 1073 static int wol_port_mode = UNM_PORT_MODE_AUTO_NEG_1G;
1074 1074 static int port_mode = UNM_PORT_MODE_AUTO_NEG;
1075 1075 int btype = adapter->ahw.boardcfg.board_type, data = 0;
1076 1076
1077 1077 if (btype == UNM_BRDTYPE_P3_HMEZ || btype == UNM_BRDTYPE_P3_XG_LOM) {
1078 1078 data = port_mode; /* set to port_mode normally */
1079 1079 if ((port_mode != UNM_PORT_MODE_802_3_AP) &&
1080 1080 (port_mode != UNM_PORT_MODE_XG) &&
1081 1081 (port_mode != UNM_PORT_MODE_AUTO_NEG_1G) &&
1082 1082 (port_mode != UNM_PORT_MODE_AUTO_NEG_XG))
1083 1083 data = UNM_PORT_MODE_AUTO_NEG;
1084 1084
1085 1085 adapter->unm_nic_hw_write_wx(adapter, UNM_PORT_MODE_ADDR,
1086 1086 &data, 4);
1087 1087
1088 1088 if ((wol_port_mode != UNM_PORT_MODE_802_3_AP) &&
1089 1089 (wol_port_mode != UNM_PORT_MODE_XG) &&
1090 1090 (wol_port_mode != UNM_PORT_MODE_AUTO_NEG_1G) &&
1091 1091 (wol_port_mode != UNM_PORT_MODE_AUTO_NEG_XG))
1092 1092 wol_port_mode = UNM_PORT_MODE_AUTO_NEG;
1093 1093
1094 1094 adapter->unm_nic_hw_write_wx(adapter, UNM_WOL_PORT_MODE,
1095 1095 &wol_port_mode, 4);
1096 1096 }
1097 1097 }
1098 1098
1099 1099 static void
1100 1100 netxen_pcie_strap_init(unm_adapter *adapter)
1101 1101 {
1102 1102 ddi_acc_handle_t pcihdl = adapter->pci_cfg_handle;
1103 1103 u32 chicken, control, c8c9value = 0xF1000;
1104 1104
1105 1105 adapter->unm_nic_hw_read_wx(adapter, UNM_PCIE_REG(PCIE_CHICKEN3),
1106 1106 &chicken, 4);
1107 1107
1108 1108 chicken &= 0xFCFFFFFF; /* clear chicken3 25:24 */
1109 1109 control = pci_config_get32(pcihdl, 0xD0);
1110 1110 if ((control & 0x000F0000) != 0x00020000) /* is it gen1? */
1111 1111 chicken |= 0x01000000;
1112 1112 adapter->unm_nic_hw_write_wx(adapter, UNM_PCIE_REG(PCIE_CHICKEN3),
1113 1113 &chicken, 4);
1114 1114 control = pci_config_get32(pcihdl, 0xC8);
1115 1115 control = pci_config_get32(pcihdl, 0xC8);
1116 1116 pci_config_put32(pcihdl, 0xC8, c8c9value);
1117 1117 }
1118 1118
1119 1119 static int
1120 1120 netxen_read_mac_addr(unm_adapter *adapter)
1121 1121 {
1122 1122 u64 mac_addr[8 + 1];
1123 1123 unsigned char *p;
1124 1124 int i;
1125 1125
1126 1126 if (get_flash_mac_addr(adapter, mac_addr) != 0)
1127 1127 return (-1);
1128 1128
1129 1129 if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
1130 1130 p = (unsigned char *)&mac_addr[adapter->ahw.pci_func];
1131 1131 else
1132 1132 p = (unsigned char *)&mac_addr[adapter->portnum];
1133 1133
1134 1134 for (i = 0; i < 6; i++)
1135 1135 adapter->mac_addr[i] = p[5 - i];
1136 1136
1137 1137 if (unm_nic_macaddr_set(adapter, adapter->mac_addr) != 0)
1138 1138 return (-1);
1139 1139
1140 1140 return (0);
1141 1141 }
1142 1142
1143 1143 static int
1144 1144 unmattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1145 1145 {
1146 1146 unm_adapter *adapter;
1147 1147 int i, first_driver = 0;
1148 1148 int ret, temp;
1149 1149
1150 1150 switch (cmd) {
1151 1151 case DDI_ATTACH:
1152 1152 break;
1153 1153 case DDI_RESUME:
1154 1154 case DDI_PM_RESUME:
1155 1155 default:
1156 1156 return (DDI_FAILURE);
1157 1157 }
1158 1158
1159 1159 adapter = kmem_zalloc(sizeof (unm_adapter), KM_SLEEP);
1160 1160 adapter->dip = dip;
1161 1161 ddi_set_driver_private(dip, adapter);
1162 1162 adapter->instance = ddi_get_instance(dip);
1163 1163
1164 1164 adapter->name = ddi_driver_name(dip);
1165 1165
1166 1166 ret = pci_config_setup(dip, &adapter->pci_cfg_handle);
1167 1167 if (ret != DDI_SUCCESS) {
1168 1168 cmn_err(CE_WARN, "%s%d: pci_config_setup failed\n",
1169 1169 adapter->name, adapter->instance);
1170 1170 goto attach_setup_err;
1171 1171 }
1172 1172
1173 1173 ret = unm_pci_cfg_init(adapter);
1174 1174 if (ret != DDI_SUCCESS)
1175 1175 goto attach_err;
1176 1176
1177 1177 ret = unm_pci_map_setup(adapter);
1178 1178 if (ret != DDI_SUCCESS)
1179 1179 goto attach_err;
1180 1180
1181 1181 if (unm_initialize_intr(adapter) != DDI_SUCCESS)
1182 1182 goto attach_unmap_regs;
1183 1183
1184 1184 rw_init(&adapter->adapter_lock, NULL,
1185 1185 RW_DRIVER, DDI_INTR_PRI(adapter->intr_pri));
1186 1186 mutex_init(&adapter->tx_lock, NULL,
1187 1187 MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri)));
1188 1188 mutex_init(&adapter->lock, NULL,
1189 1189 MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri)));
1190 1190
1191 1191 adapter->portnum = (int8_t)adapter->ahw.pci_func;
1192 1192
1193 1193 /*
1194 1194 * Set the CRB window to invalid. If any register in window 0 is
1195 1195 * accessed it should set window to 0 and then reset it to 1.
1196 1196 */
1197 1197 adapter->curr_window = 255;
1198 1198
1199 1199 adapter->fw_major = adapter->unm_nic_pci_read_normalize(adapter,
1200 1200 UNM_FW_VERSION_MAJOR);
1201 1201
1202 1202 if (adapter->fw_major < 4)
1203 1203 adapter->max_rds_rings = 3;
1204 1204 else
1205 1205 adapter->max_rds_rings = 2;
1206 1206
1207 1207 STRUCT_COPY(adapter->gc_dma_attr_desc, unm_dma_attr_desc);
1208 1208 STRUCT_COPY(adapter->gc_attr_desc, unm_buf_attr);
1209 1209
1210 1210 ret = unm_nic_get_board_info(adapter);
1211 1211 if (ret != DDI_SUCCESS) {
1212 1212 cmn_err(CE_WARN, "%s%d: error reading board config\n",
1213 1213 adapter->name, adapter->instance);
1214 1214 goto attach_destroy_intr;
1215 1215 }
1216 1216
1217 1217 /* Mezz cards have PCI function 0, 2, 3 enabled */
1218 1218 switch (adapter->ahw.boardcfg.board_type) {
1219 1219 case UNM_BRDTYPE_P2_SB31_10G_IMEZ:
1220 1220 case UNM_BRDTYPE_P2_SB31_10G_HMEZ:
1221 1221 if (adapter->ahw.pci_func >= 2) {
1222 1222 adapter->portnum = adapter->ahw.pci_func - 2;
1223 1223 }
1224 1224 default:
1225 1225 break;
1226 1226 }
1227 1227
1228 1228 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
1229 1229 temp = UNM_CRB_READ_VAL_ADAPTER(UNM_MIU_MN_CONTROL, adapter);
1230 1230 adapter->ahw.cut_through = NX_IS_SYSTEM_CUT_THROUGH(temp);
1231 1231 if (adapter->ahw.pci_func == 0)
1232 1232 first_driver = 1;
1233 1233 } else {
1234 1234 if (adapter->portnum == 0)
1235 1235 first_driver = 1;
1236 1236 }
1237 1237
1238 1238 unm_check_options(adapter);
1239 1239
1240 1240 if (first_driver) {
1241 1241 int first_boot = adapter->unm_nic_pci_read_normalize(adapter,
1242 1242 UNM_CAM_RAM(0x1fc));
1243 1243
1244 1244 if (check_hw_init(adapter) != 0) {
1245 1245 cmn_err(CE_WARN, "%s%d: Error in HW init sequence\n",
1246 1246 adapter->name, adapter->instance);
1247 1247 goto attach_destroy_intr;
1248 1248 }
1249 1249
1250 1250 if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
1251 1251 netxen_set_port_mode(adapter);
1252 1252
1253 1253 if (first_boot != 0x55555555) {
1254 1254 temp = 0;
1255 1255 adapter->unm_nic_hw_write_wx(adapter, CRB_CMDPEG_STATE,
1256 1256 &temp, 4);
1257 1257 if (pinit_from_rom(adapter, 0) != 0)
1258 1258 goto attach_destroy_intr;
1259 1259
1260 1260 drv_usecwait(500);
1261 1261
1262 1262 ret = load_from_flash(adapter);
1263 1263 if (ret != DDI_SUCCESS)
1264 1264 goto attach_destroy_intr;
1265 1265 }
1266 1266
1267 1267 if (ret = unm_initialize_dummy_dma(adapter))
1268 1268 goto attach_destroy_intr;
1269 1269
1270 1270 /*
1271 1271 * Tell the hardware our version number.
1272 1272 */
1273 1273 i = (_UNM_NIC_MAJOR << 16) |
1274 1274 ((_UNM_NIC_MINOR << 8)) | (_UNM_NIC_SUBVERSION);
1275 1275 adapter->unm_nic_hw_write_wx(adapter, CRB_DRIVER_VERSION,
1276 1276 &i, 4);
1277 1277
1278 1278 /* Unlock the HW, prompting the boot sequence */
1279 1279 if ((first_boot == 0x55555555) &&
1280 1280 (NX_IS_REVISION_P2(adapter->ahw.revision_id)))
1281 1281 adapter->unm_nic_pci_write_normalize(adapter,
1282 1282 UNM_ROMUSB_GLB_PEGTUNE_DONE, 1);
1283 1283
1284 1284 /* Handshake with the card before we register the devices. */
1285 1285 if (phantom_init(adapter, 0) != DDI_SUCCESS)
1286 1286 goto attach_destroy_intr;
1287 1287 }
1288 1288
1289 1289 if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
1290 1290 netxen_pcie_strap_init(adapter);
1291 1291
1292 1292 /*
1293 1293 * See if the firmware gave us a virtual-physical port mapping.
1294 1294 */
1295 1295 adapter->physical_port = adapter->portnum;
1296 1296 i = adapter->unm_nic_pci_read_normalize(adapter,
1297 1297 CRB_V2P(adapter->portnum));
1298 1298 if (i != 0x55555555)
1299 1299 adapter->physical_port = (uint16_t)i;
1300 1300
1301 1301 adapter->ahw.linkup = 0;
1302 1302
1303 1303 if (receive_peg_ready(adapter)) {
1304 1304 ret = -EIO;
1305 1305 goto free_dummy_dma;
1306 1306 }
1307 1307
1308 1308 if (netxen_read_mac_addr(adapter))
1309 1309 cmn_err(CE_WARN, "%s%d: Failed to read MAC addr\n",
1310 1310 adapter->name, adapter->instance);
1311 1311
1312 1312 unm_nic_flash_print(adapter);
1313 1313
1314 1314 if (verbmsg != 0) {
1315 1315 switch (adapter->ahw.board_type) {
1316 1316 case UNM_NIC_GBE:
1317 1317 cmn_err(CE_NOTE, "%s: QUAD GbE port %d initialized\n",
1318 1318 unm_nic_driver_name, adapter->portnum);
1319 1319 break;
1320 1320
1321 1321 case UNM_NIC_XGBE:
1322 1322 cmn_err(CE_NOTE, "%s: XGbE port %d initialized\n",
1323 1323 unm_nic_driver_name, adapter->portnum);
1324 1324 break;
1325 1325 }
1326 1326 }
1327 1327
1328 1328 ret = unm_register_mac(adapter);
1329 1329 if (ret != DDI_SUCCESS) {
1330 1330 cmn_err(CE_NOTE, "%s%d: Mac registration error\n",
1331 1331 adapter->name, adapter->instance);
1332 1332 goto free_dummy_dma;
1333 1333 }
1334 1334
1335 1335 return (DDI_SUCCESS);
1336 1336
1337 1337 free_dummy_dma:
1338 1338 if (first_driver)
1339 1339 unm_free_dummy_dma(adapter);
1340 1340 attach_destroy_intr:
1341 1341 unm_destroy_intr(adapter);
1342 1342 attach_unmap_regs:
1343 1343 ddi_regs_map_free(&(adapter->regs_handle));
1344 1344 ddi_regs_map_free(&(adapter->db_handle));
1345 1345 attach_err:
1346 1346 pci_config_teardown(&adapter->pci_cfg_handle);
1347 1347 attach_setup_err:
1348 1348 kmem_free(adapter, sizeof (unm_adapter));
1349 1349 return (ret);
1350 1350 }
1351 1351
1352 1352 static int
1353 1353 unmdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1354 1354 {
1355 1355 unm_adapter *adapter = (unm_adapter *)ddi_get_driver_private(dip);
1356 1356
1357 1357 if (adapter == NULL)
1358 1358 return (DDI_FAILURE);
1359 1359
1360 1360 switch (cmd) {
1361 1361 case DDI_DETACH:
1362 1362 unm_fini_kstats(adapter);
1363 1363 adapter->kstats[0] = NULL;
1364 1364
1365 1365 if (adapter->pci_cfg_handle != NULL)
1366 1366 pci_config_teardown(&adapter->pci_cfg_handle);
1367 1367
1368 1368 unm_nd_cleanup(adapter);
1369 1369 unm_nic_remove(adapter);
1370 1370 return (DDI_SUCCESS);
1371 1371
1372 1372 case DDI_SUSPEND:
1373 1373 return (unm_nic_suspend(adapter));
1374 1374
1375 1375 default:
1376 1376 break;
1377 1377 }
1378 1378
1379 1379 return (DDI_FAILURE);
1380 1380 }
1381 1381
1382 1382 int
1383 1383 create_rxtx_rings(unm_adapter *adapter)
1384 1384 {
1385 1385 unm_recv_context_t *recv_ctx;
1386 1386 unm_rcv_desc_ctx_t *rcv_desc;
1387 1387 int i, ring;
1388 1388
1389 1389 adapter->cmd_buf_arr = (struct unm_cmd_buffer *)kmem_zalloc(
1390 1390 sizeof (struct unm_cmd_buffer) * adapter->MaxTxDescCount,
1391 1391 KM_SLEEP);
1392 1392
1393 1393 for (i = 0; i < MAX_RCV_CTX; ++i) {
1394 1394 recv_ctx = &adapter->recv_ctx[i];
1395 1395
1396 1396 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1397 1397 rcv_desc = &recv_ctx->rcv_desc[ring];
1398 1398 if (unm_create_rx_ring(adapter, rcv_desc) !=
1399 1399 DDI_SUCCESS)
1400 1400 goto attach_free_cmdbufs;
1401 1401 }
1402 1402 }
1403 1403
1404 1404 if (unm_alloc_tx_dmahdl(adapter) != DDI_SUCCESS)
1405 1405 goto attach_free_cmdbufs;
1406 1406
1407 1407 if (unm_alloc_tx_buffers(adapter) != DDI_SUCCESS)
1408 1408 goto attach_free_tx_dmahdl;
1409 1409
1410 1410 return (DDI_SUCCESS);
1411 1411
1412 1412 attach_free_tx_buffers:
1413 1413 unm_free_tx_buffers(adapter);
1414 1414 attach_free_tx_dmahdl:
1415 1415 unm_free_tx_dmahdl(adapter);
1416 1416 attach_free_cmdbufs:
1417 1417 kmem_free(adapter->cmd_buf_arr, sizeof (struct unm_cmd_buffer) *
1418 1418 adapter->MaxTxDescCount);
1419 1419 for (i = 0; i < MAX_RCV_CTX; ++i) {
1420 1420 recv_ctx = &adapter->recv_ctx[i];
1421 1421
1422 1422 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1423 1423 rcv_desc = &recv_ctx->rcv_desc[ring];
1424 1424 if (rcv_desc->rx_buf_pool != NULL)
1425 1425 unm_destroy_rx_ring(rcv_desc);
1426 1426 }
1427 1427 }
1428 1428 return (DDI_FAILURE);
1429 1429 }
1430 1430
1431 1431 void
1432 1432 destroy_rxtx_rings(unm_adapter *adapter)
1433 1433 {
1434 1434 unm_recv_context_t *recv_ctx;
1435 1435 unm_rcv_desc_ctx_t *rcv_desc;
1436 1436 int ctx, ring;
1437 1437
1438 1438 unm_free_tx_buffers(adapter);
1439 1439 unm_free_tx_dmahdl(adapter);
1440 1440
1441 1441 for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
1442 1442 recv_ctx = &adapter->recv_ctx[ctx];
1443 1443 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1444 1444 rcv_desc = &recv_ctx->rcv_desc[ring];
1445 1445 if (rcv_desc->rx_buf_pool != NULL)
1446 1446 unm_destroy_rx_ring(rcv_desc);
1447 1447 }
1448 1448 }
1449 1449
1450 1450 if (adapter->cmd_buf_arr != NULL)
1451 1451 kmem_free(adapter->cmd_buf_arr,
1452 1452 sizeof (struct unm_cmd_buffer) * adapter->MaxTxDescCount);
1453 1453 }
1454 1454
1455 1455 #ifdef SOLARIS11
1456 1456 DDI_DEFINE_STREAM_OPS(unm_ops, nulldev, nulldev, unmattach, unmdetach,
1457 1457 nodev, NULL, D_MP, NULL, NULL);
1458 1458 #else
1459 1459 DDI_DEFINE_STREAM_OPS(unm_ops, nulldev, nulldev, unmattach, unmdetach,
1460 1460 nodev, NULL, D_MP, NULL);
↓ open down ↓ |
1460 lines elided |
↑ open up ↑ |
1461 1461 #endif
1462 1462
1463 1463 static struct modldrv modldrv = {
1464 1464 &mod_driverops, /* Type of module. This one is a driver */
1465 1465 ident,
1466 1466 &unm_ops, /* driver ops */
1467 1467 };
1468 1468
1469 1469 static struct modlinkage modlinkage = {
1470 1470 MODREV_1,
1471 - (&modldrv),
1472 - NULL
1471 + { (&modldrv), NULL }
1473 1472 };
1474 1473
1475 1474
1476 1475 int
1477 1476 _init(void)
1478 1477 {
1479 1478 int ret;
1480 1479
1481 1480 unm_ops.devo_cb_ops->cb_str = NULL;
1482 1481 mac_init_ops(&unm_ops, "ntxn");
1483 1482
1484 1483 ret = mod_install(&modlinkage);
1485 1484 if (ret != DDI_SUCCESS) {
1486 1485 mac_fini_ops(&unm_ops);
1487 1486 cmn_err(CE_WARN, "ntxn: mod_install failed\n");
1488 1487 }
1489 1488
1490 1489 return (ret);
1491 1490 }
1492 1491
1493 1492
1494 1493 int
1495 1494 _fini(void)
1496 1495 {
1497 1496 int ret;
1498 1497
1499 1498 ret = mod_remove(&modlinkage);
1500 1499 if (ret == DDI_SUCCESS)
1501 1500 mac_fini_ops(&unm_ops);
1502 1501 return (ret);
1503 1502 }
1504 1503
1505 1504 int
1506 1505 _info(struct modinfo *modinfop)
1507 1506 {
1508 1507 return (mod_info(&modlinkage, modinfop));
1509 1508 }
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX