XXXX introduce drv_sectohz
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 NetXen, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/debug.h>
32 #include <sys/stropts.h>
33 #include <sys/stream.h>
34 #include <sys/strlog.h>
35 #include <sys/kmem.h>
36 #include <sys/stat.h>
37 #include <sys/kstat.h>
38 #include <sys/vtrace.h>
39 #include <sys/dlpi.h>
40 #include <sys/strsun.h>
41 #include <sys/ethernet.h>
42 #include <sys/modctl.h>
43 #include <sys/errno.h>
44 #include <sys/dditypes.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sysmacros.h>
48 #include <sys/pci.h>
49
50 #include <sys/gld.h>
51 #include <netinet/in.h>
52 #include <inet/ip.h>
53 #include <inet/tcp.h>
54
55 #include <sys/rwlock.h>
56 #include <sys/mutex.h>
57 #include <sys/pattr.h>
58 #include <sys/strsubr.h>
59 #include <sys/ddi_impldefs.h>
60 #include<sys/task.h>
61
62 #include "unm_nic_hw.h"
63 #include "unm_nic.h"
64
65 #include "nic_phan_reg.h"
66 #include "unm_nic_ioctl.h"
67 #include "nic_cmn.h"
68 #include "unm_version.h"
69 #include "unm_brdcfg.h"
70
71 #if defined(lint)
72 #undef MBLKL
73 #define MBLKL(_mp_) ((uintptr_t)(_mp_)->b_wptr - (uintptr_t)(_mp_)->b_rptr)
74 #endif /* lint */
75
76 #undef UNM_LOOPBACK
77 #undef SINGLE_DMA_BUF
78
79 #define UNM_ADAPTER_UP_MAGIC 777
80 #define VLAN_TAGSZ 0x4
81
82 #define index2rxbuf(_rdp_, _idx_) ((_rdp_)->rx_buf_pool + (_idx_))
83 #define rxbuf2index(_rdp_, _bufp_) ((_bufp_) - (_rdp_)->rx_buf_pool)
84
85 /*
86 * Receive ISR processes NX_RX_MAXBUFS incoming packets at most, then posts
87 * as many buffers as packets processed. This loop repeats as required to
88 * process all incoming packets delivered in a single interrupt. Higher
89 * value of NX_RX_MAXBUFS improves performance by posting rx buffers less
90 * frequently, but at the cost of not posting quickly enough when card is
91 * running out of rx buffers.
92 */
93 #define NX_RX_THRESHOLD 32
94 #define NX_RX_MAXBUFS 128
95 #define NX_MAX_TXCOMPS 256
96
97 extern int create_rxtx_rings(unm_adapter *adapter);
98 extern void destroy_rxtx_rings(unm_adapter *adapter);
99
100 static void unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
101 uint32_t ringid);
102 static mblk_t *unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc);
103 static int unm_process_rcv_ring(unm_adapter *, int);
104 static int unm_process_cmd_ring(struct unm_adapter_s *adapter);
105
106 static int unm_nic_do_ioctl(unm_adapter *adapter, queue_t *q, mblk_t *mp);
107 static void unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q,
108 mblk_t *mp);
109
110 /* GLDv3 interface functions */
111 static int ntxn_m_start(void *);
112 static void ntxn_m_stop(void *);
113 static int ntxn_m_multicst(void *, boolean_t, const uint8_t *);
114 static int ntxn_m_promisc(void *, boolean_t);
115 static int ntxn_m_stat(void *arg, uint_t stat, uint64_t *val);
116 static mblk_t *ntxn_m_tx(void *, mblk_t *);
117 static void ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
118 static boolean_t ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data);
119
120 /*
121 * Allocates DMA handle, virtual memory and binds them
122 * returns size of actual memory binded and the physical address.
123 */
124 int
125 unm_pci_alloc_consistent(unm_adapter *adapter,
126 int size, caddr_t *address, ddi_dma_cookie_t *cookie,
127 ddi_dma_handle_t *dma_handle, ddi_acc_handle_t *handlep)
128 {
129 int err;
130 uint32_t ncookies;
131 size_t ring_len;
132 uint_t dma_flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
133
134 *dma_handle = NULL;
135
136 if (size <= 0)
137 return (DDI_ENOMEM);
138
139 err = ddi_dma_alloc_handle(adapter->dip,
140 &adapter->gc_dma_attr_desc,
141 DDI_DMA_DONTWAIT, NULL, dma_handle);
142 if (err != DDI_SUCCESS) {
143 cmn_err(CE_WARN, "!%s: %s: ddi_dma_alloc_handle FAILED:"
144 " %d", unm_nic_driver_name, __func__, err);
145 return (DDI_ENOMEM);
146 }
147
148 err = ddi_dma_mem_alloc(*dma_handle,
149 size, &adapter->gc_attr_desc,
150 dma_flags & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT),
151 DDI_DMA_DONTWAIT, NULL, address, &ring_len,
152 handlep);
153 if (err != DDI_SUCCESS) {
154 cmn_err(CE_WARN, "!%s: %s: ddi_dma_mem_alloc failed:"
155 "ret %d, request size: %d",
156 unm_nic_driver_name, __func__, err, size);
157 ddi_dma_free_handle(dma_handle);
158 return (DDI_ENOMEM);
159 }
160
161 if (ring_len < size) {
162 cmn_err(CE_WARN, "%s: %s: could not allocate required "
163 "memory :%d\n", unm_nic_driver_name,
164 __func__, err);
165 ddi_dma_mem_free(handlep);
166 ddi_dma_free_handle(dma_handle);
167 return (DDI_FAILURE);
168 }
169
170 (void) memset(*address, 0, size);
171
172 if (((err = ddi_dma_addr_bind_handle(*dma_handle,
173 NULL, *address, ring_len,
174 dma_flags,
175 DDI_DMA_DONTWAIT, NULL,
176 cookie, &ncookies)) != DDI_DMA_MAPPED) ||
177 (ncookies != 1)) {
178 cmn_err(CE_WARN,
179 "!%s: %s: ddi_dma_addr_bind_handle FAILED: %d",
180 unm_nic_driver_name, __func__, err);
181 ddi_dma_mem_free(handlep);
182 ddi_dma_free_handle(dma_handle);
183 return (DDI_FAILURE);
184 }
185
186 return (DDI_SUCCESS);
187 }
188
189 /*
190 * Unbinds the memory, frees the DMA handle and at the end, frees the memory
191 */
192 void
193 unm_pci_free_consistent(ddi_dma_handle_t *dma_handle,
194 ddi_acc_handle_t *acc_handle)
195 {
196 int err;
197
198 err = ddi_dma_unbind_handle(*dma_handle);
199 if (err != DDI_SUCCESS) {
200 cmn_err(CE_WARN, "%s: Error unbinding memory\n", __func__);
201 return;
202 }
203
204 ddi_dma_mem_free(acc_handle);
205 ddi_dma_free_handle(dma_handle);
206 }
207
208 static uint32_t msi_tgt_status[] = {
209 ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
210 ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
211 ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
212 ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
213 };
214
215 static void
216 unm_nic_disable_int(unm_adapter *adapter)
217 {
218 __uint32_t temp = 0;
219
220 adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
221 &temp, 4);
222 }
223
224 static inline int
225 unm_nic_clear_int(unm_adapter *adapter)
226 {
227 uint32_t mask, temp, our_int, status;
228
229 UNM_READ_LOCK(&adapter->adapter_lock);
230
231 /* check whether it's our interrupt */
232 if (!UNM_IS_MSI_FAMILY(adapter)) {
233
234 /* Legacy Interrupt case */
235 adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
236 &status);
237
238 if (!(status & adapter->legacy_intr.int_vec_bit)) {
239 UNM_READ_UNLOCK(&adapter->adapter_lock);
240 return (-1);
241 }
242
243 if (adapter->ahw.revision_id >= NX_P3_B1) {
244 adapter->unm_nic_pci_read_immediate(adapter,
245 ISR_INT_STATE_REG, &temp);
246 if (!ISR_IS_LEGACY_INTR_TRIGGERED(temp)) {
247 UNM_READ_UNLOCK(&adapter->adapter_lock);
248 return (-1);
249 }
250 } else if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
251 our_int = adapter->unm_nic_pci_read_normalize(adapter,
252 CRB_INT_VECTOR);
253
254 /* FIXME: Assumes pci_func is same as ctx */
255 if ((our_int & (0x80 << adapter->portnum)) == 0) {
256 if (our_int != 0) {
257 /* not our interrupt */
258 UNM_READ_UNLOCK(&adapter->adapter_lock);
259 return (-1);
260 }
261 }
262 temp = our_int & ~((u32)(0x80 << adapter->portnum));
263 adapter->unm_nic_pci_write_normalize(adapter,
264 CRB_INT_VECTOR, temp);
265 }
266
267 if (adapter->fw_major < 4)
268 unm_nic_disable_int(adapter);
269
270 /* claim interrupt */
271 temp = 0xffffffff;
272 adapter->unm_nic_pci_write_immediate(adapter,
273 adapter->legacy_intr.tgt_status_reg, &temp);
274
275 adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
276 &mask);
277
278 /*
279 * Read again to make sure the legacy interrupt message got
280 * flushed out
281 */
282 adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
283 &mask);
284 } else if (adapter->flags & UNM_NIC_MSI_ENABLED) {
285 /* clear interrupt */
286 temp = 0xffffffff;
287 adapter->unm_nic_pci_write_immediate(adapter,
288 msi_tgt_status[adapter->ahw.pci_func], &temp);
289 }
290
291 UNM_READ_UNLOCK(&adapter->adapter_lock);
292
293 return (0);
294 }
295
296 static void
297 unm_nic_enable_int(unm_adapter *adapter)
298 {
299 u32 temp = 1;
300
301 adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
302 &temp, 4);
303
304 if (!UNM_IS_MSI_FAMILY(adapter)) {
305 u32 mask = 0xfbff;
306
307 adapter->unm_nic_pci_write_immediate(adapter,
308 adapter->legacy_intr.tgt_mask_reg, &mask);
309 }
310 }
311
312 static void
313 unm_free_hw_resources(unm_adapter *adapter)
314 {
315 unm_recv_context_t *recv_ctx;
316 unm_rcv_desc_ctx_t *rcv_desc;
317 int ctx, ring;
318
319 if (adapter->context_alloced == 1) {
320 netxen_destroy_rxtx(adapter);
321 adapter->context_alloced = 0;
322 }
323
324 if (adapter->ctxDesc != NULL) {
325 unm_pci_free_consistent(&adapter->ctxDesc_dma_handle,
326 &adapter->ctxDesc_acc_handle);
327 adapter->ctxDesc = NULL;
328 }
329
330 if (adapter->ahw.cmdDescHead != NULL) {
331 unm_pci_free_consistent(&adapter->ahw.cmd_desc_dma_handle,
332 &adapter->ahw.cmd_desc_acc_handle);
333 adapter->ahw.cmdDesc_physAddr = NULL;
334 adapter->ahw.cmdDescHead = NULL;
335 }
336
337 for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
338 recv_ctx = &adapter->recv_ctx[ctx];
339 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
340 rcv_desc = &recv_ctx->rcv_desc[ring];
341
342 if (rcv_desc->desc_head != NULL) {
343 unm_pci_free_consistent(
344 &rcv_desc->rx_desc_dma_handle,
345 &rcv_desc->rx_desc_acc_handle);
346 rcv_desc->desc_head = NULL;
347 rcv_desc->phys_addr = NULL;
348 }
349 }
350
351 if (recv_ctx->rcvStatusDescHead != NULL) {
352 unm_pci_free_consistent(
353 &recv_ctx->status_desc_dma_handle,
354 &recv_ctx->status_desc_acc_handle);
355 recv_ctx->rcvStatusDesc_physAddr = NULL;
356 recv_ctx->rcvStatusDescHead = NULL;
357 }
358 }
359 }
360
361 static void
362 cleanup_adapter(struct unm_adapter_s *adapter)
363 {
364 ddi_regs_map_free(&(adapter->regs_handle));
365 ddi_regs_map_free(&(adapter->db_handle));
366 kmem_free(adapter, sizeof (unm_adapter));
367 }
368
369 void
370 unm_nic_remove(unm_adapter *adapter)
371 {
372 mac_link_update(adapter->mach, LINK_STATE_DOWN);
373 unm_nic_stop_port(adapter);
374
375 if (adapter->interrupt_crb) {
376 UNM_READ_LOCK(&adapter->adapter_lock);
377 unm_nic_disable_int(adapter);
378 UNM_READ_UNLOCK(&adapter->adapter_lock);
379 }
380 (void) untimeout(adapter->watchdog_timer);
381
382 unm_free_hw_resources(adapter);
383
384 if (adapter->is_up == UNM_ADAPTER_UP_MAGIC)
385 destroy_rxtx_rings(adapter);
386
387 if (adapter->portnum == 0)
388 unm_free_dummy_dma(adapter);
389
390 unm_destroy_intr(adapter);
391
392 ddi_set_driver_private(adapter->dip, NULL);
393 cleanup_adapter(adapter);
394 }
395
396 static int
397 init_firmware(unm_adapter *adapter)
398 {
399 uint32_t state = 0, loops = 0, tempout;
400
401 /* Window 1 call */
402 UNM_READ_LOCK(&adapter->adapter_lock);
403 state = adapter->unm_nic_pci_read_normalize(adapter, CRB_CMDPEG_STATE);
404 UNM_READ_UNLOCK(&adapter->adapter_lock);
405
406 if (state == PHAN_INITIALIZE_ACK)
407 return (0);
408
409 while (state != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
410 drv_usecwait(100);
411 /* Window 1 call */
412 UNM_READ_LOCK(&adapter->adapter_lock);
413 state = adapter->unm_nic_pci_read_normalize(adapter,
414 CRB_CMDPEG_STATE);
415 UNM_READ_UNLOCK(&adapter->adapter_lock);
416 loops++;
417 }
418
419 if (loops >= 200000) {
420 cmn_err(CE_WARN, "%s%d: CmdPeg init incomplete:%x\n",
421 adapter->name, adapter->instance, state);
422 return (-EIO);
423 }
424
425 /* Window 1 call */
426 UNM_READ_LOCK(&adapter->adapter_lock);
427 tempout = INTR_SCHEME_PERPORT;
428 adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_CAPABILITIES_HOST,
429 &tempout, 4);
430 tempout = MSI_MODE_MULTIFUNC;
431 adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_MSI_MODE_HOST,
432 &tempout, 4);
433 tempout = MPORT_MULTI_FUNCTION_MODE;
434 adapter->unm_nic_hw_write_wx(adapter, CRB_MPORT_MODE, &tempout, 4);
435 tempout = PHAN_INITIALIZE_ACK;
436 adapter->unm_nic_hw_write_wx(adapter, CRB_CMDPEG_STATE, &tempout, 4);
437 UNM_READ_UNLOCK(&adapter->adapter_lock);
438
439 return (0);
440 }
441
442 /*
443 * Utility to synchronize with receive peg.
444 * Returns 0 on sucess
445 * -EIO on error
446 */
447 int
448 receive_peg_ready(struct unm_adapter_s *adapter)
449 {
450 uint32_t state = 0;
451 int loops = 0, err = 0;
452
453 /* Window 1 call */
454 UNM_READ_LOCK(&adapter->adapter_lock);
455 state = adapter->unm_nic_pci_read_normalize(adapter, CRB_RCVPEG_STATE);
456 UNM_READ_UNLOCK(&adapter->adapter_lock);
457
458 while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 20000)) {
459 drv_usecwait(100);
460 /* Window 1 call */
461
462 UNM_READ_LOCK(&adapter->adapter_lock);
463 state = adapter->unm_nic_pci_read_normalize(adapter,
464 CRB_RCVPEG_STATE);
465 UNM_READ_UNLOCK(&adapter->adapter_lock);
466
467 loops++;
468 }
469
470 if (loops >= 20000) {
471 cmn_err(CE_WARN, "Receive Peg initialization incomplete 0x%x\n",
472 state);
473 err = -EIO;
474 }
475
476 return (err);
477 }
478
479 /*
480 * check if the firmware has been downloaded and ready to run and
481 * setup the address for the descriptors in the adapter
482 */
483 static int
484 unm_nic_hw_resources(unm_adapter *adapter)
485 {
486 hardware_context *hw = &adapter->ahw;
487 void *addr;
488 int err;
489 int ctx, ring;
490 unm_recv_context_t *recv_ctx;
491 unm_rcv_desc_ctx_t *rcv_desc;
492 ddi_dma_cookie_t cookie;
493 int size;
494
495 if (err = receive_peg_ready(adapter))
496 return (err);
497
498 size = (sizeof (RingContext) + sizeof (uint32_t));
499
500 err = unm_pci_alloc_consistent(adapter,
501 size, (caddr_t *)&addr, &cookie,
502 &adapter->ctxDesc_dma_handle,
503 &adapter->ctxDesc_acc_handle);
504 if (err != DDI_SUCCESS) {
505 cmn_err(CE_WARN, "Failed to allocate HW context\n");
506 return (err);
507 }
508
509 adapter->ctxDesc_physAddr = cookie.dmac_laddress;
510
511 (void) memset(addr, 0, sizeof (RingContext));
512
513 adapter->ctxDesc = (RingContext *) addr;
514 adapter->ctxDesc->CtxId = adapter->portnum;
515 adapter->ctxDesc->CMD_CONSUMER_OFFSET =
516 adapter->ctxDesc_physAddr + sizeof (RingContext);
517 adapter->cmdConsumer =
518 (uint32_t *)(uintptr_t)(((char *)addr) + sizeof (RingContext));
519
520 ASSERT(!((unsigned long)adapter->ctxDesc_physAddr & 0x3f));
521
522 /*
523 * Allocate command descriptor ring.
524 */
525 size = (sizeof (cmdDescType0_t) * adapter->MaxTxDescCount);
526 err = unm_pci_alloc_consistent(adapter,
527 size, (caddr_t *)&addr, &cookie,
528 &hw->cmd_desc_dma_handle,
529 &hw->cmd_desc_acc_handle);
530 if (err != DDI_SUCCESS) {
531 cmn_err(CE_WARN, "Failed to allocate cmd desc ring\n");
532 return (err);
533 }
534
535 hw->cmdDesc_physAddr = cookie.dmac_laddress;
536 hw->cmdDescHead = (cmdDescType0_t *)addr;
537
538 for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
539 recv_ctx = &adapter->recv_ctx[ctx];
540
541 size = (sizeof (statusDesc_t)* adapter->MaxRxDescCount);
542 err = unm_pci_alloc_consistent(adapter,
543 size, (caddr_t *)&addr,
544 &recv_ctx->status_desc_dma_cookie,
545 &recv_ctx->status_desc_dma_handle,
546 &recv_ctx->status_desc_acc_handle);
547 if (err != DDI_SUCCESS) {
548 cmn_err(CE_WARN, "Failed to allocate sts desc ring\n");
549 goto free_cmd_desc;
550 }
551
552 (void) memset(addr, 0, size);
553 recv_ctx->rcvStatusDesc_physAddr =
554 recv_ctx->status_desc_dma_cookie.dmac_laddress;
555 recv_ctx->rcvStatusDescHead = (statusDesc_t *)addr;
556
557 /* rds rings */
558 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
559 rcv_desc = &recv_ctx->rcv_desc[ring];
560
561 size = (sizeof (rcvDesc_t) * adapter->MaxRxDescCount);
562 err = unm_pci_alloc_consistent(adapter,
563 size, (caddr_t *)&addr,
564 &rcv_desc->rx_desc_dma_cookie,
565 &rcv_desc->rx_desc_dma_handle,
566 &rcv_desc->rx_desc_acc_handle);
567 if (err != DDI_SUCCESS) {
568 cmn_err(CE_WARN, "Failed to allocate "
569 "rx desc ring %d\n", ring);
570 goto free_status_desc;
571 }
572
573 rcv_desc->phys_addr =
574 rcv_desc->rx_desc_dma_cookie.dmac_laddress;
575 rcv_desc->desc_head = (rcvDesc_t *)addr;
576 }
577 }
578
579 if (err = netxen_create_rxtx(adapter))
580 goto free_statusrx_desc;
581 adapter->context_alloced = 1;
582
583 return (DDI_SUCCESS);
584
585 free_statusrx_desc:
586 free_status_desc:
587 free_cmd_desc:
588 unm_free_hw_resources(adapter);
589
590 return (err);
591 }
592
593 void unm_desc_dma_sync(ddi_dma_handle_t handle, uint_t start, uint_t count,
594 uint_t range, uint_t unit_size, uint_t direction)
595 {
596 if ((start + count) < range) {
597 (void) ddi_dma_sync(handle, start * unit_size,
598 count * unit_size, direction);
599 } else {
600 (void) ddi_dma_sync(handle, start * unit_size, 0, direction);
601 (void) ddi_dma_sync(handle, 0,
602 (start + count - range) * unit_size, DDI_DMA_SYNC_FORCPU);
603 }
604 }
605
606 static uint32_t crb_cmd_producer[4] = { CRB_CMD_PRODUCER_OFFSET,
607 CRB_CMD_PRODUCER_OFFSET_1, CRB_CMD_PRODUCER_OFFSET_2,
608 CRB_CMD_PRODUCER_OFFSET_3 };
609
610 static uint32_t crb_cmd_consumer[4] = { CRB_CMD_CONSUMER_OFFSET,
611 CRB_CMD_CONSUMER_OFFSET_1, CRB_CMD_CONSUMER_OFFSET_2,
612 CRB_CMD_CONSUMER_OFFSET_3 };
613
614 void
615 unm_nic_update_cmd_producer(struct unm_adapter_s *adapter,
616 uint32_t crb_producer)
617 {
618 int data = crb_producer;
619
620 if (adapter->crb_addr_cmd_producer) {
621 UNM_READ_LOCK(&adapter->adapter_lock);
622 adapter->unm_nic_hw_write_wx(adapter,
623 adapter->crb_addr_cmd_producer, &data, 4);
624 UNM_READ_UNLOCK(&adapter->adapter_lock);
625 }
626 }
627
628 static void
629 unm_nic_update_cmd_consumer(struct unm_adapter_s *adapter,
630 uint32_t crb_producer)
631 {
632 int data = crb_producer;
633
634 if (adapter->crb_addr_cmd_consumer)
635 adapter->unm_nic_hw_write_wx(adapter,
636 adapter->crb_addr_cmd_consumer, &data, 4);
637 }
638
639 /*
640 * Looks for type of packet and sets opcode accordingly
641 * so that checksum offload can be used.
642 */
643 static void
644 unm_tx_csum(cmdDescType0_t *desc, mblk_t *mp, pktinfo_t *pktinfo)
645 {
646 if (pktinfo->mac_hlen == sizeof (struct ether_vlan_header))
647 desc->u1.s1.flags = FLAGS_VLAN_TAGGED;
648
649 if (pktinfo->etype == htons(ETHERTYPE_IP)) {
650 uint32_t start, flags;
651
652 mac_hcksum_get(mp, &start, NULL, NULL, NULL, &flags);
653 if ((flags & (HCK_FULLCKSUM | HCK_IPV4_HDRCKSUM)) == 0)
654 return;
655
656 /*
657 * For TCP/UDP, ask hardware to do both IP header and
658 * full checksum, even if stack has already done one or
659 * the other. Hardware will always get it correct even
660 * if stack has already done it.
661 */
662 switch (pktinfo->l4_proto) {
663 case IPPROTO_TCP:
664 desc->u1.s1.opcode = TX_TCP_PKT;
665 break;
666 case IPPROTO_UDP:
667 desc->u1.s1.opcode = TX_UDP_PKT;
668 break;
669 default:
670 /* Must be here with HCK_IPV4_HDRCKSUM */
671 desc->u1.s1.opcode = TX_IP_PKT;
672 return;
673 }
674
675 desc->u1.s1.ipHdrOffset = pktinfo->mac_hlen;
676 desc->u1.s1.tcpHdrOffset = pktinfo->mac_hlen + pktinfo->ip_hlen;
677 }
678 }
679
680 /*
681 * For IP/UDP/TCP checksum offload, this checks for MAC+IP header in one
682 * contiguous block ending at 8 byte aligned address as required by hardware.
683 * Caller assumes pktinfo->total_len will be updated by this function and
684 * if pktinfo->etype is set to 0, it will need to linearize the mblk and
685 * invoke unm_update_pkt_info() to determine ethertype, IP header len and
686 * protocol.
687 */
688 static boolean_t
689 unm_get_pkt_info(mblk_t *mp, pktinfo_t *pktinfo)
690 {
691 mblk_t *bp;
692 ushort_t type;
693
694 (void) memset(pktinfo, 0, sizeof (pktinfo_t));
695
696 for (bp = mp; bp != NULL; bp = bp->b_cont) {
697 if (MBLKL(bp) == 0)
698 continue;
699 pktinfo->mblk_no++;
700 pktinfo->total_len += MBLKL(bp);
701 }
702
703 if (MBLKL(mp) < (sizeof (struct ether_header) + sizeof (ipha_t)))
704 return (B_FALSE);
705
706 /*
707 * We just need non 1 byte aligned address, since ether_type is
708 * ushort.
709 */
710 if ((uintptr_t)mp->b_rptr & 1)
711 return (B_FALSE);
712
713 type = ((struct ether_header *)(uintptr_t)mp->b_rptr)->ether_type;
714 if (type == htons(ETHERTYPE_VLAN)) {
715 if (MBLKL(mp) < (sizeof (struct ether_vlan_header) +
716 sizeof (ipha_t)))
717 return (B_FALSE);
718 type = ((struct ether_vlan_header *) \
719 (uintptr_t)mp->b_rptr)->ether_type;
720 pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
721 } else {
722 pktinfo->mac_hlen = sizeof (struct ether_header);
723 }
724 pktinfo->etype = type;
725
726 if (pktinfo->etype == htons(ETHERTYPE_IP)) {
727 uchar_t *ip_off = mp->b_rptr + pktinfo->mac_hlen;
728
729 pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ip_off);
730 pktinfo->l4_proto =
731 ((ipha_t *)(uintptr_t)ip_off)->ipha_protocol;
732
733 /* IP header not aligned to quadward boundary? */
734 if ((unsigned long)(ip_off + pktinfo->ip_hlen) % 8 != 0)
735 return (B_FALSE);
736 }
737
738 return (B_TRUE);
739 }
740
741 static void
742 unm_update_pkt_info(char *ptr, pktinfo_t *pktinfo)
743 {
744 ushort_t type;
745
746 type = ((struct ether_header *)(uintptr_t)ptr)->ether_type;
747 if (type == htons(ETHERTYPE_VLAN)) {
748 type = ((struct ether_vlan_header *)(uintptr_t)ptr)->ether_type;
749 pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
750 } else {
751 pktinfo->mac_hlen = sizeof (struct ether_header);
752 }
753 pktinfo->etype = type;
754
755 if (pktinfo->etype == htons(ETHERTYPE_IP)) {
756 char *ipp = ptr + pktinfo->mac_hlen;
757
758 pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ipp);
759 pktinfo->l4_proto = ((ipha_t *)(uintptr_t)ipp)->ipha_protocol;
760 }
761 }
762
763 static boolean_t
764 unm_send_copy(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
765 {
766 hardware_context *hw;
767 u32 producer = 0;
768 cmdDescType0_t *hwdesc;
769 struct unm_cmd_buffer *pbuf = NULL;
770 u32 mblen;
771 int no_of_desc = 1;
772 int MaxTxDescCount;
773 mblk_t *bp;
774 char *txb;
775
776 hw = &adapter->ahw;
777 MaxTxDescCount = adapter->MaxTxDescCount;
778
779 UNM_SPIN_LOCK(&adapter->tx_lock);
780 membar_enter();
781
782 if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
783 MaxTxDescCount) <= 2) {
784 adapter->stats.outofcmddesc++;
785 adapter->resched_needed = 1;
786 membar_exit();
787 UNM_SPIN_UNLOCK(&adapter->tx_lock);
788 return (B_FALSE);
789 }
790 adapter->freecmds -= no_of_desc;
791
792 producer = adapter->cmdProducer;
793
794 adapter->cmdProducer = get_index_range(adapter->cmdProducer,
795 MaxTxDescCount, no_of_desc);
796
797 hwdesc = &hw->cmdDescHead[producer];
798 (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
799 pbuf = &adapter->cmd_buf_arr[producer];
800
801 pbuf->msg = NULL;
802 pbuf->head = NULL;
803 pbuf->tail = NULL;
804
805 txb = pbuf->dma_area.vaddr;
806
807 for (bp = mp; bp != NULL; bp = bp->b_cont) {
808 if ((mblen = MBLKL(bp)) == 0)
809 continue;
810 bcopy(bp->b_rptr, txb, mblen);
811 txb += mblen;
812 }
813
814 /*
815 * Determine metadata if not previously done due to fragmented mblk.
816 */
817 if (pktinfo->etype == 0)
818 unm_update_pkt_info(pbuf->dma_area.vaddr, pktinfo);
819
820 (void) ddi_dma_sync(pbuf->dma_area.dma_hdl,
821 0, pktinfo->total_len, DDI_DMA_SYNC_FORDEV);
822
823 /* hwdesc->u1.s1.tcpHdrOffset = 0; */
824 /* hwdesc->mss = 0; */
825 hwdesc->u1.s1.opcode = TX_ETHER_PKT;
826 hwdesc->u3.s1.port = adapter->portnum;
827 hwdesc->u3.s1.ctx_id = adapter->portnum;
828
829 hwdesc->u6.s1.buffer1Length = pktinfo->total_len;
830 hwdesc->u5.AddrBuffer1 = pbuf->dma_area.dma_addr;
831 hwdesc->u1.s1.numOfBuffers = 1;
832 hwdesc->u1.s1.totalLength = pktinfo->total_len;
833
834 unm_tx_csum(hwdesc, mp, pktinfo);
835
836 unm_desc_dma_sync(hw->cmd_desc_dma_handle,
837 producer,
838 no_of_desc,
839 MaxTxDescCount,
840 sizeof (cmdDescType0_t),
841 DDI_DMA_SYNC_FORDEV);
842
843 hw->cmdProducer = adapter->cmdProducer;
844 unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
845
846 adapter->stats.txbytes += pktinfo->total_len;
847 adapter->stats.xmitfinished++;
848 adapter->stats.txcopyed++;
849 UNM_SPIN_UNLOCK(&adapter->tx_lock);
850
851 freemsg(mp);
852 return (B_TRUE);
853 }
854
855 /* Should be called with adapter->tx_lock held. */
856 static void
857 unm_return_dma_handle(unm_adapter *adapter, unm_dmah_node_t *head,
858 unm_dmah_node_t *tail, uint32_t num)
859 {
860 ASSERT(tail != NULL);
861 tail->next = adapter->dmahdl_pool;
862 adapter->dmahdl_pool = head;
863 adapter->freehdls += num;
864 }
865
866 static unm_dmah_node_t *
867 unm_reserve_dma_handle(unm_adapter* adapter)
868 {
869 unm_dmah_node_t *dmah = NULL;
870
871 dmah = adapter->dmahdl_pool;
872 if (dmah != NULL) {
873 adapter->dmahdl_pool = dmah->next;
874 dmah->next = NULL;
875 adapter->freehdls--;
876 membar_exit();
877 }
878
879 return (dmah);
880 }
881
882 static boolean_t
883 unm_send_mapped(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
884 {
885 hardware_context *hw;
886 u32 producer = 0;
887 u32 saved_producer = 0;
888 cmdDescType0_t *hwdesc;
889 struct unm_cmd_buffer *pbuf = NULL;
890 int no_of_desc;
891 int k;
892 int MaxTxDescCount;
893 mblk_t *bp;
894
895 unm_dmah_node_t *dmah, *head = NULL, *tail = NULL, *hdlp;
896 ddi_dma_cookie_t cookie[MAX_COOKIES_PER_CMD + 1];
897 int ret, i;
898 uint32_t hdl_reserved = 0;
899 uint32_t mblen;
900 uint32_t ncookies, index = 0, total_cookies = 0;
901
902 MaxTxDescCount = adapter->MaxTxDescCount;
903
904 UNM_SPIN_LOCK(&adapter->tx_lock);
905
906 /* bind all the mblks of the packet first */
907 for (bp = mp; bp != NULL; bp = bp->b_cont) {
908 mblen = MBLKL(bp);
909 if (mblen == 0)
910 continue;
911
912 dmah = unm_reserve_dma_handle(adapter);
913 if (dmah == NULL) {
914 adapter->stats.outoftxdmahdl++;
915 goto err_map;
916 }
917
918 ret = ddi_dma_addr_bind_handle(dmah->dmahdl,
919 NULL, (caddr_t)bp->b_rptr, mblen,
920 DDI_DMA_STREAMING | DDI_DMA_WRITE,
921 DDI_DMA_DONTWAIT, NULL, &cookie[index], &ncookies);
922
923 if (ret != DDI_DMA_MAPPED)
924 goto err_map;
925
926 if (tail == NULL) {
927 head = tail = dmah;
928 } else {
929 tail->next = dmah;
930 tail = dmah;
931 }
932 hdl_reserved++;
933
934 total_cookies += ncookies;
935 if (total_cookies > MAX_COOKIES_PER_CMD) {
936 dmah = NULL;
937 goto err_map;
938 }
939
940 if (index == 0) {
941 size_t hsize = cookie[0].dmac_size;
942
943 /*
944 * For TCP/UDP packets with checksum offload,
945 * MAC/IP headers need to be contiguous. Otherwise,
946 * there must be at least 16 bytes in the first
947 * descriptor.
948 */
949 if ((pktinfo->l4_proto == IPPROTO_TCP) ||
950 (pktinfo->l4_proto == IPPROTO_UDP)) {
951 if (hsize < (pktinfo->mac_hlen +
952 pktinfo->ip_hlen)) {
953 dmah = NULL;
954 goto err_map;
955 }
956 } else {
957 if (hsize < 16) {
958 dmah = NULL;
959 goto err_map;
960 }
961 }
962 }
963
964 index++;
965 ncookies--;
966 for (i = 0; i < ncookies; i++, index++)
967 ddi_dma_nextcookie(dmah->dmahdl, &cookie[index]);
968 }
969
970 dmah = NULL;
971 hw = &adapter->ahw;
972 no_of_desc = (total_cookies + 3) >> 2;
973
974 membar_enter();
975 if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
976 MaxTxDescCount) < no_of_desc+2) {
977 /*
978 * If we are going to be trying the copy path, no point
979 * scheduling an upcall when Tx resources are freed.
980 */
981 if (pktinfo->total_len > adapter->maxmtu) {
982 adapter->stats.outofcmddesc++;
983 adapter->resched_needed = 1;
984 }
985 membar_exit();
986 goto err_alloc_desc;
987 }
988 adapter->freecmds -= no_of_desc;
989
990 /* Copy the descriptors into the hardware */
991 producer = adapter->cmdProducer;
992 saved_producer = producer;
993 hwdesc = &hw->cmdDescHead[producer];
994 (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
995 pbuf = &adapter->cmd_buf_arr[producer];
996
997 pbuf->msg = mp;
998 pbuf->head = head;
999 pbuf->tail = tail;
1000
1001 hwdesc->u1.s1.numOfBuffers = total_cookies;
1002 hwdesc->u1.s1.opcode = TX_ETHER_PKT;
1003 hwdesc->u3.s1.port = adapter->portnum;
1004 /* hwdesc->u1.s1.tcpHdrOffset = 0; */
1005 /* hwdesc->mss = 0; */
1006 hwdesc->u3.s1.ctx_id = adapter->portnum;
1007 hwdesc->u1.s1.totalLength = pktinfo->total_len;
1008 unm_tx_csum(hwdesc, mp, pktinfo);
1009
1010 for (i = k = 0; i < total_cookies; i++) {
1011 if (k == 4) {
1012 /* Move to the next descriptor */
1013 k = 0;
1014 producer = get_next_index(producer, MaxTxDescCount);
1015 hwdesc = &hw->cmdDescHead[producer];
1016 (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
1017 }
1018
1019 switch (k) {
1020 case 0:
1021 hwdesc->u6.s1.buffer1Length = cookie[i].dmac_size;
1022 hwdesc->u5.AddrBuffer1 = cookie[i].dmac_laddress;
1023 break;
1024 case 1:
1025 hwdesc->u6.s1.buffer2Length = cookie[i].dmac_size;
1026 hwdesc->u2.AddrBuffer2 = cookie[i].dmac_laddress;
1027 break;
1028 case 2:
1029 hwdesc->u6.s1.buffer3Length = cookie[i].dmac_size;
1030 hwdesc->u4.AddrBuffer3 = cookie[i].dmac_laddress;
1031 break;
1032 case 3:
1033 hwdesc->u6.s1.buffer4Length = cookie[i].dmac_size;
1034 hwdesc->u7.AddrBuffer4 = cookie[i].dmac_laddress;
1035 break;
1036 }
1037 k++;
1038 }
1039
1040 unm_desc_dma_sync(hw->cmd_desc_dma_handle, saved_producer, no_of_desc,
1041 MaxTxDescCount, sizeof (cmdDescType0_t), DDI_DMA_SYNC_FORDEV);
1042
1043 adapter->cmdProducer = get_next_index(producer, MaxTxDescCount);
1044 hw->cmdProducer = adapter->cmdProducer;
1045 unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
1046
1047 adapter->stats.txbytes += pktinfo->total_len;
1048 adapter->stats.xmitfinished++;
1049 adapter->stats.txmapped++;
1050 UNM_SPIN_UNLOCK(&adapter->tx_lock);
1051 return (B_TRUE);
1052
1053 err_alloc_desc:
1054 err_map:
1055
1056 hdlp = head;
1057 while (hdlp != NULL) {
1058 (void) ddi_dma_unbind_handle(hdlp->dmahdl);
1059 hdlp = hdlp->next;
1060 }
1061
1062 /*
1063 * add the reserved but bind failed one to the list to be returned
1064 */
1065 if (dmah != NULL) {
1066 if (tail == NULL)
1067 head = tail = dmah;
1068 else {
1069 tail->next = dmah;
1070 tail = dmah;
1071 }
1072 hdl_reserved++;
1073 }
1074
1075 if (head != NULL)
1076 unm_return_dma_handle(adapter, head, tail, hdl_reserved);
1077
1078 UNM_SPIN_UNLOCK(&adapter->tx_lock);
1079 return (B_FALSE);
1080 }
1081
1082 static boolean_t
1083 unm_nic_xmit_frame(unm_adapter *adapter, mblk_t *mp)
1084 {
1085 pktinfo_t pktinfo;
1086 boolean_t status = B_FALSE, send_mapped;
1087
1088 adapter->stats.xmitcalled++;
1089
1090 send_mapped = unm_get_pkt_info(mp, &pktinfo);
1091
1092 if (pktinfo.total_len <= adapter->tx_bcopy_threshold ||
1093 pktinfo.mblk_no >= MAX_COOKIES_PER_CMD)
1094 send_mapped = B_FALSE;
1095
1096 if (send_mapped == B_TRUE)
1097 status = unm_send_mapped(adapter, mp, &pktinfo);
1098
1099 if (status != B_TRUE) {
1100 if (pktinfo.total_len <= adapter->maxmtu)
1101 return (unm_send_copy(adapter, mp, &pktinfo));
1102
1103 /* message too large */
1104 freemsg(mp);
1105 adapter->stats.txdropped++;
1106 status = B_TRUE;
1107 }
1108
1109 return (status);
1110 }
1111
1112 static int
1113 unm_nic_check_temp(struct unm_adapter_s *adapter)
1114 {
1115 uint32_t temp, temp_state, temp_val;
1116 int rv = 0;
1117
1118 if ((adapter->ahw.revision_id == NX_P3_A2) ||
1119 (adapter->ahw.revision_id == NX_P3_A0))
1120 return (0);
1121
1122 temp = adapter->unm_nic_pci_read_normalize(adapter, CRB_TEMP_STATE);
1123
1124 temp_state = nx_get_temp_state(temp);
1125 temp_val = nx_get_temp_val(temp);
1126
1127 if (temp_state == NX_TEMP_PANIC) {
1128 cmn_err(CE_WARN, "%s: Device temperature %d C exceeds "
1129 "maximum allowed, device has been shut down\n",
1130 unm_nic_driver_name, temp_val);
1131 rv = 1;
1132 } else if (temp_state == NX_TEMP_WARN) {
1133 if (adapter->temp == NX_TEMP_NORMAL) {
1134 cmn_err(CE_WARN, "%s: Device temperature %d C exceeds"
1135 "operating range. Immediate action needed.\n",
1136 unm_nic_driver_name, temp_val);
1137 }
1138 } else {
1139 if (adapter->temp == NX_TEMP_WARN) {
1140 cmn_err(CE_WARN, "%s: Device temperature is now %d "
1141 "degrees C in normal range.\n",
1142 unm_nic_driver_name, temp_val);
1143 }
1144 }
1145
1146 adapter->temp = temp_state;
1147 return (rv);
1148 }
1149
1150 static void
1151 unm_watchdog(unsigned long v)
1152 {
1153 unm_adapter *adapter = (unm_adapter *)v;
1154
1155 if ((adapter->portnum == 0) && unm_nic_check_temp(adapter)) {
1156 /*
1157 * We return without turning on the netdev queue as there
1158 * was an overheated device
1159 */
1160 return;
1161 }
1162
1163 unm_nic_handle_phy_intr(adapter);
1164
1165 /*
1166 * This function schedules a call for itself.
1167 */
1168 adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
1169 (void *)adapter, drv_sectohz(2));
1170
1171 }
1172
1173 static void unm_nic_clear_stats(unm_adapter *adapter)
1174 {
1175 (void) memset(&adapter->stats, 0, sizeof (adapter->stats));
1176 }
1177
1178 static void
1179 unm_nic_poll(unm_adapter *adapter)
1180 {
1181 int work_done, tx_complete;
1182
1183 adapter->stats.polled++;
1184
1185 loop:
1186 tx_complete = unm_process_cmd_ring(adapter);
1187 work_done = unm_process_rcv_ring(adapter, NX_RX_MAXBUFS);
1188 if ((!tx_complete) || (!(work_done < NX_RX_MAXBUFS)))
1189 goto loop;
1190
1191 UNM_READ_LOCK(&adapter->adapter_lock);
1192 unm_nic_enable_int(adapter);
1193 UNM_READ_UNLOCK(&adapter->adapter_lock);
1194 }
1195
1196 /* ARGSUSED */
1197 uint_t
1198 unm_intr(caddr_t data, caddr_t arg)
1199 {
1200 unm_adapter *adapter = (unm_adapter *)(uintptr_t)data;
1201
1202 if (unm_nic_clear_int(adapter))
1203 return (DDI_INTR_UNCLAIMED);
1204
1205 unm_nic_poll(adapter);
1206 return (DDI_INTR_CLAIMED);
1207 }
1208
1209 /*
1210 * This is invoked from receive isr. Due to the single threaded nature
1211 * of the invocation, pool_lock acquisition is not neccesary to protect
1212 * pool_list.
1213 */
1214 static void
1215 unm_free_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc, unm_rx_buffer_t *rx_buffer)
1216 {
1217 /* mutex_enter(rcv_desc->pool_lock); */
1218 rx_buffer->next = rcv_desc->pool_list;
1219 rcv_desc->pool_list = rx_buffer;
1220 rcv_desc->rx_buf_free++;
1221 /* mutex_exit(rcv_desc->pool_lock); */
1222 }
1223
1224 /*
1225 * unm_process_rcv() send the received packet to the protocol stack.
1226 */
1227 static mblk_t *
1228 unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc)
1229 {
1230 unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
1231 unm_rx_buffer_t *rx_buffer;
1232 mblk_t *mp;
1233 u32 desc_ctx = desc->u1.s1.type;
1234 unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[desc_ctx];
1235 u32 pkt_length = desc->u1.s1.totalLength;
1236 int poff = desc->u1.s1.pkt_offset;
1237 int index, cksum_flags, docopy;
1238 int index_lo = desc->u1.s1.referenceHandle_lo;
1239 char *vaddr;
1240
1241 index = ((desc->u1.s1.referenceHandle_hi << 4) | index_lo);
1242
1243 rx_buffer = index2rxbuf(rcv_desc, index);
1244
1245 if (rx_buffer == NULL) {
1246 cmn_err(CE_WARN, "\r\nNULL rx_buffer idx=%d", index);
1247 return (NULL);
1248 }
1249 vaddr = (char *)rx_buffer->dma_info.vaddr;
1250 if (vaddr == NULL) {
1251 cmn_err(CE_WARN, "\r\nNULL vaddr");
1252 return (NULL);
1253 }
1254 rcv_desc->rx_desc_handled++;
1255 rcv_desc->rx_buf_card--;
1256
1257 (void) ddi_dma_sync(rx_buffer->dma_info.dma_hdl, 0,
1258 pkt_length + poff + (adapter->ahw.cut_through ? 0 :
1259 IP_ALIGNMENT_BYTES), DDI_DMA_SYNC_FORCPU);
1260
1261 /*
1262 * Copy packet into new allocated message buffer, if pkt_length
1263 * is below copy threshold.
1264 */
1265 docopy = (pkt_length <= adapter->rx_bcopy_threshold) ? 1 : 0;
1266
1267 /*
1268 * If card is running out of rx buffers, then attempt to allocate
1269 * new mblk so we can feed this rx buffer back to card (we
1270 * _could_ look at what's pending on free and recycle lists).
1271 */
1272 if (rcv_desc->rx_buf_card < NX_RX_THRESHOLD) {
1273 docopy = 1;
1274 adapter->stats.rxbufshort++;
1275 }
1276
1277 if (docopy == 1) {
1278 if ((mp = allocb(pkt_length + IP_ALIGNMENT_BYTES, 0)) == NULL) {
1279 adapter->stats.allocbfailed++;
1280 goto freebuf;
1281 }
1282
1283 mp->b_rptr += IP_ALIGNMENT_BYTES;
1284 vaddr += poff;
1285 bcopy(vaddr, mp->b_rptr, pkt_length);
1286 adapter->stats.rxcopyed++;
1287 unm_free_rx_buffer(rcv_desc, rx_buffer);
1288 } else {
1289 mp = (mblk_t *)rx_buffer->mp;
1290 if (mp == NULL) {
1291 mp = desballoc(rx_buffer->dma_info.vaddr,
1292 rcv_desc->dma_size, 0, &rx_buffer->rx_recycle);
1293 if (mp == NULL) {
1294 adapter->stats.desballocfailed++;
1295 goto freebuf;
1296 }
1297 rx_buffer->mp = mp;
1298 }
1299 mp->b_rptr += poff;
1300 adapter->stats.rxmapped++;
1301 }
1302
1303 mp->b_wptr = (uchar_t *)((unsigned long)mp->b_rptr + pkt_length);
1304
1305 if (desc->u1.s1.status == STATUS_CKSUM_OK) {
1306 adapter->stats.csummed++;
1307 cksum_flags =
1308 HCK_FULLCKSUM_OK | HCK_IPV4_HDRCKSUM_OK;
1309 } else {
1310 cksum_flags = 0;
1311 }
1312 mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
1313
1314 adapter->stats.no_rcv++;
1315 adapter->stats.rxbytes += pkt_length;
1316 adapter->stats.uphappy++;
1317
1318 return (mp);
1319
1320 freebuf:
1321 unm_free_rx_buffer(rcv_desc, rx_buffer);
1322 return (NULL);
1323 }
1324
1325 /* Process Receive status ring */
1326 static int
1327 unm_process_rcv_ring(unm_adapter *adapter, int max)
1328 {
1329 unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
1330 statusDesc_t *desc_head = recv_ctx->rcvStatusDescHead;
1331 statusDesc_t *desc = NULL;
1332 uint32_t consumer, start;
1333 int count = 0, ring;
1334 mblk_t *mp;
1335
1336 start = consumer = recv_ctx->statusRxConsumer;
1337
1338 unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start, max,
1339 adapter->MaxRxDescCount, sizeof (statusDesc_t),
1340 DDI_DMA_SYNC_FORCPU);
1341
1342 while (count < max) {
1343 desc = &desc_head[consumer];
1344 if (!(desc->u1.s1.owner & STATUS_OWNER_HOST))
1345 break;
1346
1347 mp = unm_process_rcv(adapter, desc);
1348 desc->u1.s1.owner = STATUS_OWNER_PHANTOM;
1349
1350 consumer = (consumer + 1) % adapter->MaxRxDescCount;
1351 count++;
1352 if (mp != NULL)
1353 mac_rx(adapter->mach, NULL, mp);
1354 }
1355
1356 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
1357 if (recv_ctx->rcv_desc[ring].rx_desc_handled > 0)
1358 unm_post_rx_buffers_nodb(adapter, ring);
1359 }
1360
1361 if (count) {
1362 unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start,
1363 count, adapter->MaxRxDescCount, sizeof (statusDesc_t),
1364 DDI_DMA_SYNC_FORDEV);
1365
1366 /* update the consumer index in phantom */
1367 recv_ctx->statusRxConsumer = consumer;
1368
1369 UNM_READ_LOCK(&adapter->adapter_lock);
1370 adapter->unm_nic_hw_write_wx(adapter,
1371 recv_ctx->host_sds_consumer, &consumer, 4);
1372 UNM_READ_UNLOCK(&adapter->adapter_lock);
1373 }
1374
1375 return (count);
1376 }
1377
1378 /* Process Command status ring */
1379 static int
1380 unm_process_cmd_ring(struct unm_adapter_s *adapter)
1381 {
1382 u32 last_consumer;
1383 u32 consumer;
1384 int count = 0;
1385 struct unm_cmd_buffer *buffer;
1386 int done;
1387 unm_dmah_node_t *dmah, *head = NULL, *tail = NULL;
1388 uint32_t free_hdls = 0;
1389
1390 (void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
1391 sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
1392
1393 last_consumer = adapter->lastCmdConsumer;
1394 consumer = *(adapter->cmdConsumer);
1395
1396 while (last_consumer != consumer) {
1397 buffer = &adapter->cmd_buf_arr[last_consumer];
1398 if (buffer->head != NULL) {
1399 dmah = buffer->head;
1400 while (dmah != NULL) {
1401 (void) ddi_dma_unbind_handle(dmah->dmahdl);
1402 dmah = dmah->next;
1403 free_hdls++;
1404 }
1405
1406 if (head == NULL) {
1407 head = buffer->head;
1408 tail = buffer->tail;
1409 } else {
1410 tail->next = buffer->head;
1411 tail = buffer->tail;
1412 }
1413
1414 buffer->head = NULL;
1415 buffer->tail = NULL;
1416
1417 if (buffer->msg != NULL) {
1418 freemsg(buffer->msg);
1419 buffer->msg = NULL;
1420 }
1421 }
1422
1423 last_consumer = get_next_index(last_consumer,
1424 adapter->MaxTxDescCount);
1425 if (++count > NX_MAX_TXCOMPS)
1426 break;
1427 }
1428
1429 if (count) {
1430 int doresched;
1431
1432 UNM_SPIN_LOCK(&adapter->tx_lock);
1433 adapter->lastCmdConsumer = last_consumer;
1434 adapter->freecmds += count;
1435 membar_exit();
1436
1437 doresched = adapter->resched_needed;
1438 if (doresched)
1439 adapter->resched_needed = 0;
1440
1441 if (head != NULL)
1442 unm_return_dma_handle(adapter, head, tail, free_hdls);
1443
1444 UNM_SPIN_UNLOCK(&adapter->tx_lock);
1445
1446 if (doresched)
1447 mac_tx_update(adapter->mach);
1448 }
1449
1450 (void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
1451 sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
1452
1453 consumer = *(adapter->cmdConsumer);
1454 done = (adapter->lastCmdConsumer == consumer);
1455
1456 return (done);
1457 }
1458
1459 /*
1460 * This is invoked from receive isr, and at initialization time when no
1461 * rx buffers have been posted to card. Due to the single threaded nature
1462 * of the invocation, pool_lock acquisition is not neccesary to protect
1463 * pool_list.
1464 */
1465 static unm_rx_buffer_t *
1466 unm_reserve_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc)
1467 {
1468 unm_rx_buffer_t *rx_buffer = NULL;
1469
1470 /* mutex_enter(rcv_desc->pool_lock); */
1471 if (rcv_desc->rx_buf_free) {
1472 rx_buffer = rcv_desc->pool_list;
1473 rcv_desc->pool_list = rx_buffer->next;
1474 rx_buffer->next = NULL;
1475 rcv_desc->rx_buf_free--;
1476 } else {
1477 mutex_enter(rcv_desc->recycle_lock);
1478
1479 if (rcv_desc->rx_buf_recycle) {
1480 rcv_desc->pool_list = rcv_desc->recycle_list;
1481 rcv_desc->recycle_list = NULL;
1482 rcv_desc->rx_buf_free += rcv_desc->rx_buf_recycle;
1483 rcv_desc->rx_buf_recycle = 0;
1484
1485 rx_buffer = rcv_desc->pool_list;
1486 rcv_desc->pool_list = rx_buffer->next;
1487 rx_buffer->next = NULL;
1488 rcv_desc->rx_buf_free--;
1489 }
1490
1491 mutex_exit(rcv_desc->recycle_lock);
1492 }
1493
1494 /* mutex_exit(rcv_desc->pool_lock); */
1495 return (rx_buffer);
1496 }
1497
1498 static void
1499 post_rx_doorbell(struct unm_adapter_s *adapter, uint32_t ringid, int count)
1500 {
1501 #define UNM_RCV_PEG_DB_ID 2
1502 #define UNM_RCV_PRODUCER_OFFSET 0
1503 ctx_msg msg = {0};
1504
1505 /*
1506 * Write a doorbell msg to tell phanmon of change in
1507 * receive ring producer
1508 */
1509 msg.PegId = UNM_RCV_PEG_DB_ID;
1510 msg.privId = 1;
1511 msg.Count = count;
1512 msg.CtxId = adapter->portnum;
1513 msg.Opcode = UNM_RCV_PRODUCER(ringid);
1514 dbwritel(*((__uint32_t *)&msg),
1515 (void *)(DB_NORMALIZE(adapter, UNM_RCV_PRODUCER_OFFSET)));
1516 }
1517
1518 static int
1519 unm_post_rx_buffers(struct unm_adapter_s *adapter, uint32_t ringid)
1520 {
1521 unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
1522 unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[ringid];
1523 unm_rx_buffer_t *rx_buffer;
1524 rcvDesc_t *pdesc;
1525 int count;
1526
1527 for (count = 0; count < rcv_desc->MaxRxDescCount; count++) {
1528 rx_buffer = unm_reserve_rx_buffer(rcv_desc);
1529 if (rx_buffer != NULL) {
1530 pdesc = &rcv_desc->desc_head[count];
1531 pdesc->referenceHandle = rxbuf2index(rcv_desc,
1532 rx_buffer);
1533 pdesc->flags = ringid;
1534 pdesc->bufferLength = rcv_desc->dma_size;
1535 pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
1536 }
1537 else
1538 return (DDI_FAILURE);
1539 }
1540
1541 rcv_desc->producer = count % rcv_desc->MaxRxDescCount;
1542 count--;
1543 unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle,
1544 0, /* start */
1545 count, /* count */
1546 count, /* range */
1547 sizeof (rcvDesc_t), /* unit_size */
1548 DDI_DMA_SYNC_FORDEV); /* direction */
1549
1550 rcv_desc->rx_buf_card = rcv_desc->MaxRxDescCount;
1551 UNM_READ_LOCK(&adapter->adapter_lock);
1552 adapter->unm_nic_hw_write_wx(adapter, rcv_desc->host_rx_producer,
1553 &count, 4);
1554 if (adapter->fw_major < 4)
1555 post_rx_doorbell(adapter, ringid, count);
1556 UNM_READ_UNLOCK(&adapter->adapter_lock);
1557
1558 return (DDI_SUCCESS);
1559 }
1560
1561 static void
1562 unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
1563 uint32_t ringid)
1564 {
1565 unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
1566 unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[ringid];
1567 struct unm_rx_buffer *rx_buffer;
1568 rcvDesc_t *pdesc;
1569 int count, producer = rcv_desc->producer;
1570 int last_producer = producer;
1571
1572 for (count = 0; count < rcv_desc->rx_desc_handled; count++) {
1573 rx_buffer = unm_reserve_rx_buffer(rcv_desc);
1574 if (rx_buffer != NULL) {
1575 pdesc = &rcv_desc->desc_head[producer];
1576 pdesc->referenceHandle = rxbuf2index(rcv_desc,
1577 rx_buffer);
1578 pdesc->flags = ringid;
1579 pdesc->bufferLength = rcv_desc->dma_size;
1580 pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
1581 } else {
1582 adapter->stats.outofrxbuf++;
1583 break;
1584 }
1585 producer = get_next_index(producer, rcv_desc->MaxRxDescCount);
1586 }
1587
1588 /* if we did allocate buffers, then write the count to Phantom */
1589 if (count) {
1590 /* Sync rx ring, considering case for wrap around */
1591 unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle, last_producer,
1592 count, rcv_desc->MaxRxDescCount, sizeof (rcvDesc_t),
1593 DDI_DMA_SYNC_FORDEV);
1594
1595 rcv_desc->producer = producer;
1596 rcv_desc->rx_desc_handled -= count;
1597 rcv_desc->rx_buf_card += count;
1598
1599 producer = (producer - 1) % rcv_desc->MaxRxDescCount;
1600 UNM_READ_LOCK(&adapter->adapter_lock);
1601 adapter->unm_nic_hw_write_wx(adapter,
1602 rcv_desc->host_rx_producer, &producer, 4);
1603 UNM_READ_UNLOCK(&adapter->adapter_lock);
1604 }
1605 }
1606
1607 int
1608 unm_nic_fill_statistics_128M(struct unm_adapter_s *adapter,
1609 struct unm_statistics *unm_stats)
1610 {
1611 void *addr;
1612 if (adapter->ahw.board_type == UNM_NIC_XGBE) {
1613 UNM_WRITE_LOCK(&adapter->adapter_lock);
1614 unm_nic_pci_change_crbwindow_128M(adapter, 0);
1615
1616 /* LINTED: E_FALSE_LOGICAL_EXPR */
1617 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_BYTE_CNT,
1618 &(unm_stats->tx_bytes));
1619 /* LINTED: E_FALSE_LOGICAL_EXPR */
1620 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_FRAME_CNT,
1621 &(unm_stats->tx_packets));
1622 /* LINTED: E_FALSE_LOGICAL_EXPR */
1623 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_BYTE_CNT,
1624 &(unm_stats->rx_bytes));
1625 /* LINTED: E_FALSE_LOGICAL_EXPR */
1626 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_FRAME_CNT,
1627 &(unm_stats->rx_packets));
1628 /* LINTED: E_FALSE_LOGICAL_EXPR */
1629 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_AGGR_ERROR_CNT,
1630 &(unm_stats->rx_errors));
1631 /* LINTED: E_FALSE_LOGICAL_EXPR */
1632 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_CRC_ERROR_CNT,
1633 &(unm_stats->rx_CRC_errors));
1634 /* LINTED: E_FALSE_LOGICAL_EXPR */
1635 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
1636 &(unm_stats->rx_long_length_error));
1637 /* LINTED: E_FALSE_LOGICAL_EXPR */
1638 UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
1639 &(unm_stats->rx_short_length_error));
1640
1641 /*
1642 * For reading rx_MAC_error bit different procedure
1643 * UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_TEST_MUX_CTL, 0x15);
1644 * UNM_NIC_LOCKED_READ_REG((UNM_CRB_NIU + 0xC0), &temp);
1645 * unm_stats->rx_MAC_errors = temp & 0xff;
1646 */
1647
1648 unm_nic_pci_change_crbwindow_128M(adapter, 1);
1649 UNM_WRITE_UNLOCK(&adapter->adapter_lock);
1650 } else {
1651 UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
1652 unm_stats->tx_bytes = adapter->stats.txbytes;
1653 unm_stats->tx_packets = adapter->stats.xmitedframes +
1654 adapter->stats.xmitfinished;
1655 unm_stats->rx_bytes = adapter->stats.rxbytes;
1656 unm_stats->rx_packets = adapter->stats.no_rcv;
1657 unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
1658 unm_stats->tx_errors = adapter->stats.nocmddescriptor;
1659 unm_stats->rx_short_length_error = adapter->stats.uplcong;
1660 unm_stats->rx_long_length_error = adapter->stats.uphcong;
1661 unm_stats->rx_CRC_errors = 0;
1662 unm_stats->rx_MAC_errors = 0;
1663 UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
1664 }
1665 return (0);
1666 }
1667
1668 int
1669 unm_nic_fill_statistics_2M(struct unm_adapter_s *adapter,
1670 struct unm_statistics *unm_stats)
1671 {
1672 if (adapter->ahw.board_type == UNM_NIC_XGBE) {
1673 (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
1674 &(unm_stats->tx_bytes), 4);
1675 (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
1676 &(unm_stats->tx_packets), 4);
1677 (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
1678 &(unm_stats->rx_bytes), 4);
1679 (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
1680 &(unm_stats->rx_packets), 4);
1681 (void) unm_nic_hw_read_wx_2M(adapter,
1682 UNM_NIU_XGE_AGGR_ERROR_CNT, &(unm_stats->rx_errors), 4);
1683 (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
1684 &(unm_stats->rx_CRC_errors), 4);
1685 (void) unm_nic_hw_read_wx_2M(adapter,
1686 UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
1687 &(unm_stats->rx_long_length_error), 4);
1688 (void) unm_nic_hw_read_wx_2M(adapter,
1689 UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
1690 &(unm_stats->rx_short_length_error), 4);
1691 } else {
1692 UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
1693 unm_stats->tx_bytes = adapter->stats.txbytes;
1694 unm_stats->tx_packets = adapter->stats.xmitedframes +
1695 adapter->stats.xmitfinished;
1696 unm_stats->rx_bytes = adapter->stats.rxbytes;
1697 unm_stats->rx_packets = adapter->stats.no_rcv;
1698 unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
1699 unm_stats->tx_errors = adapter->stats.nocmddescriptor;
1700 unm_stats->rx_short_length_error = adapter->stats.uplcong;
1701 unm_stats->rx_long_length_error = adapter->stats.uphcong;
1702 unm_stats->rx_CRC_errors = 0;
1703 unm_stats->rx_MAC_errors = 0;
1704 UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
1705 }
1706 return (0);
1707 }
1708
1709 int
1710 unm_nic_clear_statistics_128M(struct unm_adapter_s *adapter)
1711 {
1712 void *addr;
1713 int data = 0;
1714
1715 UNM_WRITE_LOCK(&adapter->adapter_lock);
1716 unm_nic_pci_change_crbwindow_128M(adapter, 0);
1717
1718 /* LINTED: E_FALSE_LOGICAL_EXPR */
1719 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_BYTE_CNT, &data);
1720 /* LINTED: E_FALSE_LOGICAL_EXPR */
1721 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_FRAME_CNT, &data);
1722 /* LINTED: E_FALSE_LOGICAL_EXPR */
1723 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_BYTE_CNT, &data);
1724 /* LINTED: E_FALSE_LOGICAL_EXPR */
1725 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_FRAME_CNT, &data);
1726 /* LINTED: E_FALSE_LOGICAL_EXPR */
1727 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_AGGR_ERROR_CNT, &data);
1728 /* LINTED: E_FALSE_LOGICAL_EXPR */
1729 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_CRC_ERROR_CNT, &data);
1730 /* LINTED: E_FALSE_LOGICAL_EXPR */
1731 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR, &data);
1732 /* LINTED: E_FALSE_LOGICAL_EXPR */
1733 UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR, &data);
1734
1735 unm_nic_pci_change_crbwindow_128M(adapter, 1);
1736 UNM_WRITE_UNLOCK(&adapter->adapter_lock);
1737 unm_nic_clear_stats(adapter);
1738 return (0);
1739 }
1740
1741 int
1742 unm_nic_clear_statistics_2M(struct unm_adapter_s *adapter)
1743 {
1744 int data = 0;
1745
1746 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
1747 &data, 4);
1748 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
1749 &data, 4);
1750 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
1751 &data, 4);
1752 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
1753 &data, 4);
1754 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_AGGR_ERROR_CNT,
1755 &data, 4);
1756 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
1757 &data, 4);
1758 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
1759 &data, 4);
1760 (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
1761 &data, 4);
1762 unm_nic_clear_stats(adapter);
1763 return (0);
1764 }
1765
1766 /*
1767 * unm_nic_ioctl () We provide the tcl/phanmon support
1768 * through these ioctls.
1769 */
1770 static void
1771 unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q, mblk_t *mp)
1772 {
1773 void *ptr;
1774
1775 switch (cmd) {
1776 case UNM_NIC_CMD:
1777 (void) unm_nic_do_ioctl(adapter, q, mp);
1778 break;
1779
1780 case UNM_NIC_NAME:
1781 ptr = (void *) mp->b_cont->b_rptr;
1782
1783 /*
1784 * Phanmon checks for "UNM-UNM" string
1785 * Replace the hardcoded value with appropriate macro
1786 */
1787 DPRINTF(-1, (CE_CONT, "UNM_NIC_NAME ioctl executed %d %d\n",
1788 cmd, __LINE__));
1789 (void) memcpy(ptr, "UNM-UNM", 10);
1790 miocack(q, mp, 10, 0);
1791 break;
1792
1793 default:
1794 cmn_err(CE_WARN, "Netxen ioctl cmd %x not supported\n", cmd);
1795
1796 miocnak(q, mp, 0, EINVAL);
1797 break;
1798 }
1799 }
1800
1801 int
1802 unm_nic_resume(unm_adapter *adapter)
1803 {
1804
1805 adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
1806 (void *) adapter, 50000);
1807
1808 if (adapter->intr_type == DDI_INTR_TYPE_MSI)
1809 (void) ddi_intr_block_enable(&adapter->intr_handle, 1);
1810 else
1811 (void) ddi_intr_enable(adapter->intr_handle);
1812 UNM_READ_LOCK(&adapter->adapter_lock);
1813 unm_nic_enable_int(adapter);
1814 UNM_READ_UNLOCK(&adapter->adapter_lock);
1815
1816 mac_link_update(adapter->mach, LINK_STATE_UP);
1817
1818 return (DDI_SUCCESS);
1819 }
1820
1821 int
1822 unm_nic_suspend(unm_adapter *adapter)
1823 {
1824 mac_link_update(adapter->mach, LINK_STATE_DOWN);
1825
1826 (void) untimeout(adapter->watchdog_timer);
1827
1828 UNM_READ_LOCK(&adapter->adapter_lock);
1829 unm_nic_disable_int(adapter);
1830 UNM_READ_UNLOCK(&adapter->adapter_lock);
1831 if (adapter->intr_type == DDI_INTR_TYPE_MSI)
1832 (void) ddi_intr_block_disable(&adapter->intr_handle, 1);
1833 else
1834 (void) ddi_intr_disable(adapter->intr_handle);
1835
1836 return (DDI_SUCCESS);
1837 }
1838
1839 static int
1840 unm_nic_do_ioctl(unm_adapter *adapter, queue_t *wq, mblk_t *mp)
1841 {
1842 unm_nic_ioctl_data_t data;
1843 struct unm_nic_ioctl_data *up_data;
1844 ddi_acc_handle_t conf_handle;
1845 int retval = 0;
1846 uint64_t efuse_chip_id = 0;
1847 char *ptr1;
1848 short *ptr2;
1849 int *ptr4;
1850
1851 up_data = (struct unm_nic_ioctl_data *)(mp->b_cont->b_rptr);
1852 (void) memcpy(&data, (void **)(uintptr_t)(mp->b_cont->b_rptr),
1853 sizeof (data));
1854
1855 /* Shouldn't access beyond legal limits of "char u[64];" member */
1856 if (data.size > sizeof (data.uabc)) {
1857 /* evil user tried to crash the kernel */
1858 cmn_err(CE_WARN, "bad size: %d\n", data.size);
1859 retval = GLD_BADARG;
1860 goto error_out;
1861 }
1862
1863 switch (data.cmd) {
1864 case unm_nic_cmd_pci_read:
1865
1866 if ((retval = adapter->unm_nic_hw_read_ioctl(adapter,
1867 data.off, up_data, data.size))) {
1868 DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_read_wx "
1869 "returned %d\n", __FUNCTION__, __LINE__, retval));
1870
1871 retval = data.rv;
1872 goto error_out;
1873 }
1874
1875 data.rv = 0;
1876 break;
1877
1878 case unm_nic_cmd_pci_write:
1879 if ((data.rv = adapter->unm_nic_hw_write_ioctl(adapter,
1880 data.off, &(data.uabc), data.size))) {
1881 DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_write_wx "
1882 "returned %d\n", __FUNCTION__,
1883 __LINE__, data.rv));
1884 retval = data.rv;
1885 goto error_out;
1886 }
1887 data.size = 0;
1888 break;
1889
1890 case unm_nic_cmd_pci_mem_read:
1891 if ((data.rv = adapter->unm_nic_pci_mem_read(adapter,
1892 data.off, up_data, data.size))) {
1893 DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_pci_mem_read "
1894 "returned %d\n", __FUNCTION__,
1895 __LINE__, data.rv));
1896 retval = data.rv;
1897 goto error_out;
1898 }
1899 data.rv = 0;
1900 break;
1901
1902 case unm_nic_cmd_pci_mem_write:
1903 if ((data.rv = adapter->unm_nic_pci_mem_write(adapter,
1904 data.off, &(data.uabc), data.size))) {
1905 DPRINTF(-1, (CE_WARN,
1906 "%s(%d) unm_nic_cmd_pci_mem_write "
1907 "returned %d\n",
1908 __FUNCTION__, __LINE__, data.rv));
1909 retval = data.rv;
1910 goto error_out;
1911 }
1912
1913 data.size = 0;
1914 data.rv = 0;
1915 break;
1916
1917 case unm_nic_cmd_pci_config_read:
1918
1919 if (adapter->pci_cfg_handle != NULL) {
1920 conf_handle = adapter->pci_cfg_handle;
1921
1922 } else if ((retval = pci_config_setup(adapter->dip,
1923 &conf_handle)) != DDI_SUCCESS) {
1924 DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
1925 " error:%d\n", unm_nic_driver_name, retval));
1926 goto error_out;
1927
1928 } else
1929 adapter->pci_cfg_handle = conf_handle;
1930
1931 switch (data.size) {
1932 case 1:
1933 ptr1 = (char *)up_data;
1934 *ptr1 = (char)pci_config_get8(conf_handle, data.off);
1935 break;
1936 case 2:
1937 ptr2 = (short *)up_data;
1938 *ptr2 = (short)pci_config_get16(conf_handle, data.off);
1939 break;
1940 case 4:
1941 ptr4 = (int *)up_data;
1942 *ptr4 = (int)pci_config_get32(conf_handle, data.off);
1943 break;
1944 }
1945
1946 break;
1947
1948 case unm_nic_cmd_pci_config_write:
1949
1950 if (adapter->pci_cfg_handle != NULL) {
1951 conf_handle = adapter->pci_cfg_handle;
1952 } else if ((retval = pci_config_setup(adapter->dip,
1953 &conf_handle)) != DDI_SUCCESS) {
1954 DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
1955 " error:%d\n", unm_nic_driver_name, retval));
1956 goto error_out;
1957 } else {
1958 adapter->pci_cfg_handle = conf_handle;
1959 }
1960
1961 switch (data.size) {
1962 case 1:
1963 pci_config_put8(conf_handle,
1964 data.off, *(char *)&(data.uabc));
1965 break;
1966 case 2:
1967 pci_config_put16(conf_handle,
1968 data.off, *(short *)(uintptr_t)&(data.uabc));
1969 break;
1970 case 4:
1971 pci_config_put32(conf_handle,
1972 data.off, *(u32 *)(uintptr_t)&(data.uabc));
1973 break;
1974 }
1975 data.size = 0;
1976 break;
1977
1978 case unm_nic_cmd_get_stats:
1979 data.rv = adapter->unm_nic_fill_statistics(adapter,
1980 (struct unm_statistics *)up_data);
1981 data.size = sizeof (struct unm_statistics);
1982
1983 break;
1984
1985 case unm_nic_cmd_clear_stats:
1986 data.rv = adapter->unm_nic_clear_statistics(adapter);
1987 break;
1988
1989 case unm_nic_cmd_get_version:
1990 (void) memcpy(up_data, UNM_NIC_VERSIONID,
1991 sizeof (UNM_NIC_VERSIONID));
1992 data.size = sizeof (UNM_NIC_VERSIONID);
1993
1994 break;
1995
1996 case unm_nic_cmd_get_phy_type:
1997 cmn_err(CE_WARN, "unm_nic_cmd_get_phy_type unimplemented\n");
1998 break;
1999
2000 case unm_nic_cmd_efuse_chip_id:
2001 efuse_chip_id = adapter->unm_nic_pci_read_normalize(adapter,
2002 UNM_EFUSE_CHIP_ID_HIGH);
2003 efuse_chip_id <<= 32;
2004 efuse_chip_id |= adapter->unm_nic_pci_read_normalize(adapter,
2005 UNM_EFUSE_CHIP_ID_LOW);
2006 (void) memcpy(up_data, &efuse_chip_id, sizeof (uint64_t));
2007 data.rv = 0;
2008 break;
2009
2010 default:
2011 cmn_err(CE_WARN, "%s%d: bad command %d\n", adapter->name,
2012 adapter->instance, data.cmd);
2013 data.rv = GLD_NOTSUPPORTED;
2014 data.size = 0;
2015 goto error_out;
2016 }
2017
2018 work_done:
2019 miocack(wq, mp, data.size, data.rv);
2020 return (DDI_SUCCESS);
2021
2022 error_out:
2023 cmn_err(CE_WARN, "%s(%d) ioctl error\n", __FUNCTION__, data.cmd);
2024 miocnak(wq, mp, 0, EINVAL);
2025 return (retval);
2026 }
2027
2028 /*
2029 * Local datatype for defining tables of (Offset, Name) pairs
2030 */
2031 typedef struct {
2032 offset_t index;
2033 char *name;
2034 } unm_ksindex_t;
2035
2036 static const unm_ksindex_t unm_kstat[] = {
2037 { 0, "freehdls" },
2038 { 1, "freecmds" },
2039 { 2, "tx_bcopy_threshold" },
2040 { 3, "rx_bcopy_threshold" },
2041 { 4, "xmitcalled" },
2042 { 5, "xmitedframes" },
2043 { 6, "xmitfinished" },
2044 { 7, "txbytes" },
2045 { 8, "txcopyed" },
2046 { 9, "txmapped" },
2047 { 10, "outoftxdmahdl" },
2048 { 11, "outofcmddesc" },
2049 { 12, "txdropped" },
2050 { 13, "polled" },
2051 { 14, "uphappy" },
2052 { 15, "updropped" },
2053 { 16, "csummed" },
2054 { 17, "no_rcv" },
2055 { 18, "rxbytes" },
2056 { 19, "rxcopyed" },
2057 { 20, "rxmapped" },
2058 { 21, "desballocfailed" },
2059 { 22, "outofrxbuf" },
2060 { 23, "promiscmode" },
2061 { 24, "rxbufshort" },
2062 { 25, "allocbfailed" },
2063 { -1, NULL }
2064 };
2065
2066 static int
2067 unm_kstat_update(kstat_t *ksp, int flag)
2068 {
2069 unm_adapter *adapter;
2070 kstat_named_t *knp;
2071
2072 if (flag != KSTAT_READ)
2073 return (EACCES);
2074
2075 adapter = ksp->ks_private;
2076 knp = ksp->ks_data;
2077
2078 (knp++)->value.ui32 = adapter->freehdls;
2079 (knp++)->value.ui64 = adapter->freecmds;
2080 (knp++)->value.ui64 = adapter->tx_bcopy_threshold;
2081 (knp++)->value.ui64 = adapter->rx_bcopy_threshold;
2082
2083 (knp++)->value.ui64 = adapter->stats.xmitcalled;
2084 (knp++)->value.ui64 = adapter->stats.xmitedframes;
2085 (knp++)->value.ui64 = adapter->stats.xmitfinished;
2086 (knp++)->value.ui64 = adapter->stats.txbytes;
2087 (knp++)->value.ui64 = adapter->stats.txcopyed;
2088 (knp++)->value.ui64 = adapter->stats.txmapped;
2089 (knp++)->value.ui64 = adapter->stats.outoftxdmahdl;
2090 (knp++)->value.ui64 = adapter->stats.outofcmddesc;
2091 (knp++)->value.ui64 = adapter->stats.txdropped;
2092 (knp++)->value.ui64 = adapter->stats.polled;
2093 (knp++)->value.ui64 = adapter->stats.uphappy;
2094 (knp++)->value.ui64 = adapter->stats.updropped;
2095 (knp++)->value.ui64 = adapter->stats.csummed;
2096 (knp++)->value.ui64 = adapter->stats.no_rcv;
2097 (knp++)->value.ui64 = adapter->stats.rxbytes;
2098 (knp++)->value.ui64 = adapter->stats.rxcopyed;
2099 (knp++)->value.ui64 = adapter->stats.rxmapped;
2100 (knp++)->value.ui64 = adapter->stats.desballocfailed;
2101 (knp++)->value.ui64 = adapter->stats.outofrxbuf;
2102 (knp++)->value.ui64 = adapter->stats.promiscmode;
2103 (knp++)->value.ui64 = adapter->stats.rxbufshort;
2104 (knp++)->value.ui64 = adapter->stats.allocbfailed;
2105
2106 return (0);
2107 }
2108
2109 static kstat_t *
2110 unm_setup_named_kstat(unm_adapter *adapter, int instance, char *name,
2111 const unm_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
2112 {
2113 kstat_t *ksp;
2114 kstat_named_t *knp;
2115 char *np;
2116 int type;
2117 int count = 0;
2118
2119 size /= sizeof (unm_ksindex_t);
2120 ksp = kstat_create(unm_nic_driver_name, instance, name, "net",
2121 KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
2122 if (ksp == NULL)
2123 return (NULL);
2124
2125 ksp->ks_private = adapter;
2126 ksp->ks_update = update;
2127 for (knp = ksp->ks_data; (np = ksip->name) != NULL; ++knp, ++ksip) {
2128 count++;
2129 switch (*np) {
2130 default:
2131 type = KSTAT_DATA_UINT64;
2132 break;
2133 case '%':
2134 np += 1;
2135 type = KSTAT_DATA_UINT32;
2136 break;
2137 case '$':
2138 np += 1;
2139 type = KSTAT_DATA_STRING;
2140 break;
2141 case '&':
2142 np += 1;
2143 type = KSTAT_DATA_CHAR;
2144 break;
2145 }
2146 kstat_named_init(knp, np, type);
2147 }
2148 kstat_install(ksp);
2149
2150 return (ksp);
2151 }
2152
2153 void
2154 unm_init_kstats(unm_adapter* adapter, int instance)
2155 {
2156 adapter->kstats[0] = unm_setup_named_kstat(adapter,
2157 instance, "kstatinfo", unm_kstat,
2158 sizeof (unm_kstat), unm_kstat_update);
2159 }
2160
2161 void
2162 unm_fini_kstats(unm_adapter* adapter)
2163 {
2164
2165 if (adapter->kstats[0] != NULL) {
2166 kstat_delete(adapter->kstats[0]);
2167 adapter->kstats[0] = NULL;
2168 }
2169 }
2170
2171 static int
2172 unm_nic_set_pauseparam(unm_adapter *adapter, unm_pauseparam_t *pause)
2173 {
2174 int ret = 0;
2175
2176 if (adapter->ahw.board_type == UNM_NIC_GBE) {
2177 if (unm_niu_gbe_set_rx_flow_ctl(adapter, pause->rx_pause))
2178 ret = -EIO;
2179
2180 if (unm_niu_gbe_set_tx_flow_ctl(adapter, pause->tx_pause))
2181 ret = -EIO;
2182
2183 } else if (adapter->ahw.board_type == UNM_NIC_XGBE) {
2184 if (unm_niu_xg_set_tx_flow_ctl(adapter, pause->tx_pause))
2185 ret = -EIO;
2186 } else
2187 ret = -EIO;
2188
2189 return (ret);
2190 }
2191
2192 /*
2193 * GLD/MAC interfaces
2194 */
2195 static int
2196 ntxn_m_start(void *arg)
2197 {
2198 unm_adapter *adapter = arg;
2199 int ring;
2200
2201 UNM_SPIN_LOCK(&adapter->lock);
2202 if (adapter->is_up == UNM_ADAPTER_UP_MAGIC) {
2203 UNM_SPIN_UNLOCK(&adapter->lock);
2204 return (DDI_SUCCESS);
2205 }
2206
2207 if (create_rxtx_rings(adapter) != DDI_SUCCESS) {
2208 UNM_SPIN_UNLOCK(&adapter->lock);
2209 return (DDI_FAILURE);
2210 }
2211
2212 if (init_firmware(adapter) != DDI_SUCCESS) {
2213 UNM_SPIN_UNLOCK(&adapter->lock);
2214 cmn_err(CE_WARN, "%s%d: Failed to init firmware\n",
2215 adapter->name, adapter->instance);
2216 goto dest_rings;
2217 }
2218
2219 unm_nic_clear_stats(adapter);
2220
2221 if (unm_nic_hw_resources(adapter) != 0) {
2222 UNM_SPIN_UNLOCK(&adapter->lock);
2223 cmn_err(CE_WARN, "%s%d: Error setting hw resources\n",
2224 adapter->name, adapter->instance);
2225 goto dest_rings;
2226 }
2227
2228 if (adapter->fw_major < 4) {
2229 adapter->crb_addr_cmd_producer =
2230 crb_cmd_producer[adapter->portnum];
2231 adapter->crb_addr_cmd_consumer =
2232 crb_cmd_consumer[adapter->portnum];
2233 unm_nic_update_cmd_producer(adapter, 0);
2234 unm_nic_update_cmd_consumer(adapter, 0);
2235 }
2236
2237 for (ring = 0; ring < adapter->max_rds_rings; ring++) {
2238 if (unm_post_rx_buffers(adapter, ring) != DDI_SUCCESS) {
2239 UNM_SPIN_UNLOCK(&adapter->lock);
2240 goto free_hw_res;
2241 }
2242 }
2243
2244 if (unm_nic_macaddr_set(adapter, adapter->mac_addr) != 0) {
2245 UNM_SPIN_UNLOCK(&adapter->lock);
2246 cmn_err(CE_WARN, "%s%d: Could not set mac address\n",
2247 adapter->name, adapter->instance);
2248 goto free_hw_res;
2249 }
2250
2251 if (unm_nic_init_port(adapter) != 0) {
2252 UNM_SPIN_UNLOCK(&adapter->lock);
2253 cmn_err(CE_WARN, "%s%d: Could not initialize port\n",
2254 adapter->name, adapter->instance);
2255 goto free_hw_res;
2256 }
2257
2258 unm_nic_set_link_parameters(adapter);
2259
2260 /*
2261 * P2 and P3 should be handled similarly.
2262 */
2263 if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
2264 if (unm_nic_set_promisc_mode(adapter) != 0) {
2265 UNM_SPIN_UNLOCK(&adapter->lock);
2266 cmn_err(CE_WARN, "%s%d: Could not set promisc mode\n",
2267 adapter->name, adapter->instance);
2268 goto stop_and_free;
2269 }
2270 } else {
2271 nx_p3_nic_set_multi(adapter);
2272 }
2273 adapter->stats.promiscmode = 1;
2274
2275 if (unm_nic_set_mtu(adapter, adapter->mtu) != 0) {
2276 UNM_SPIN_UNLOCK(&adapter->lock);
2277 cmn_err(CE_WARN, "%s%d: Could not set mtu\n",
2278 adapter->name, adapter->instance);
2279 goto stop_and_free;
2280 }
2281
2282 adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
2283 (void *)adapter, 0);
2284
2285 adapter->is_up = UNM_ADAPTER_UP_MAGIC;
2286
2287 if (adapter->intr_type == DDI_INTR_TYPE_MSI)
2288 (void) ddi_intr_block_enable(&adapter->intr_handle, 1);
2289 else
2290 (void) ddi_intr_enable(adapter->intr_handle);
2291 unm_nic_enable_int(adapter);
2292
2293 UNM_SPIN_UNLOCK(&adapter->lock);
2294 return (GLD_SUCCESS);
2295
2296 stop_and_free:
2297 unm_nic_stop_port(adapter);
2298 free_hw_res:
2299 unm_free_hw_resources(adapter);
2300 dest_rings:
2301 destroy_rxtx_rings(adapter);
2302 return (DDI_FAILURE);
2303 }
2304
2305
2306 /*
2307 * This code is kept here for reference so as to
2308 * see if something different is required to be done
2309 * in GLDV3. This will be deleted later.
2310 */
2311 /* ARGSUSED */
2312 static void
2313 ntxn_m_stop(void *arg)
2314 {
2315 }
2316
2317 /*ARGSUSED*/
2318 static int
2319 ntxn_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
2320 {
2321 /*
2322 * When we correctly implement this, invoke nx_p3_nic_set_multi()
2323 * or nx_p2_nic_set_multi() here.
2324 */
2325 return (GLD_SUCCESS);
2326 }
2327
2328 /*ARGSUSED*/
2329 static int
2330 ntxn_m_promisc(void *arg, boolean_t on)
2331 {
2332 #if 0
2333 int err = 0;
2334 struct unm_adapter_s *adapter = arg;
2335
2336 err = on ? unm_nic_set_promisc_mode(adapter) :
2337 unm_nic_unset_promisc_mode(adapter);
2338
2339 if (err)
2340 return (GLD_FAILURE);
2341 #endif
2342
2343 return (GLD_SUCCESS);
2344 }
2345
2346 static int
2347 ntxn_m_stat(void *arg, uint_t stat, uint64_t *val)
2348 {
2349 struct unm_adapter_s *adapter = arg;
2350 struct unm_adapter_stats *portstat = &adapter->stats;
2351
2352 switch (stat) {
2353 case MAC_STAT_IFSPEED:
2354 if (adapter->ahw.board_type == UNM_NIC_XGBE) {
2355 /* 10 Gigs */
2356 *val = 10000000000ULL;
2357 } else {
2358 /* 1 Gig */
2359 *val = 1000000000;
2360 }
2361 break;
2362
2363 case MAC_STAT_MULTIRCV:
2364 *val = 0;
2365 break;
2366
2367 case MAC_STAT_BRDCSTRCV:
2368 case MAC_STAT_BRDCSTXMT:
2369 *val = 0;
2370 break;
2371
2372 case MAC_STAT_NORCVBUF:
2373 *val = portstat->updropped;
2374 break;
2375
2376 case MAC_STAT_NOXMTBUF:
2377 *val = portstat->txdropped;
2378 break;
2379
2380 case MAC_STAT_RBYTES:
2381 *val = portstat->rxbytes;
2382 break;
2383
2384 case MAC_STAT_OBYTES:
2385 *val = portstat->txbytes;
2386 break;
2387
2388 case MAC_STAT_OPACKETS:
2389 *val = portstat->xmitedframes;
2390 break;
2391
2392 case MAC_STAT_IPACKETS:
2393 *val = portstat->uphappy;
2394 break;
2395
2396 case MAC_STAT_OERRORS:
2397 *val = portstat->xmitcalled - portstat->xmitedframes;
2398 break;
2399
2400 case ETHER_STAT_LINK_DUPLEX:
2401 *val = LINK_DUPLEX_FULL;
2402 break;
2403
2404 default:
2405 /*
2406 * Shouldn't reach here...
2407 */
2408 *val = 0;
2409 DPRINTF(0, (CE_WARN, ": unrecognized parameter = %d, value "
2410 "returned 1\n", stat));
2411
2412 }
2413
2414 return (0);
2415 }
2416
2417 static int
2418 ntxn_m_unicst(void *arg, const uint8_t *mac)
2419 {
2420 struct unm_adapter_s *adapter = arg;
2421
2422 DPRINTF(-1, (CE_CONT, "%s: called\n", __func__));
2423
2424 if (unm_nic_macaddr_set(adapter, (uint8_t *)mac))
2425 return (EAGAIN);
2426 bcopy(mac, adapter->mac_addr, ETHERADDRL);
2427
2428 return (0);
2429 }
2430
2431 static mblk_t *
2432 ntxn_m_tx(void *arg, mblk_t *mp)
2433 {
2434 unm_adapter *adapter = arg;
2435 mblk_t *next;
2436
2437 while (mp != NULL) {
2438 next = mp->b_next;
2439 mp->b_next = NULL;
2440
2441 if (unm_nic_xmit_frame(adapter, mp) != B_TRUE) {
2442 mp->b_next = next;
2443 break;
2444 }
2445 mp = next;
2446 adapter->stats.xmitedframes++;
2447 }
2448
2449 return (mp);
2450 }
2451
2452 static void
2453 ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
2454 {
2455 int cmd;
2456 struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
2457 struct unm_adapter_s *adapter = (struct unm_adapter_s *)arg;
2458 enum ioc_reply status = IOC_DONE;
2459
2460 iocp->ioc_error = 0;
2461 cmd = iocp->ioc_cmd;
2462
2463 if (cmd == ND_GET || cmd == ND_SET) {
2464 status = unm_nd_ioctl(adapter, wq, mp, iocp);
2465 switch (status) {
2466 default:
2467 case IOC_INVAL:
2468 miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
2469 EINVAL : iocp->ioc_error);
2470 break;
2471
2472 case IOC_DONE:
2473 break;
2474
2475 case IOC_RESTART_ACK:
2476 case IOC_ACK:
2477 miocack(wq, mp, 0, 0);
2478 break;
2479
2480 case IOC_RESTART_REPLY:
2481 case IOC_REPLY:
2482 mp->b_datap->db_type = iocp->ioc_error == 0 ?
2483 M_IOCACK : M_IOCNAK;
2484 qreply(wq, mp);
2485 break;
2486 }
2487 } else if (cmd <= UNM_NIC_NAME && cmd >= UNM_CMD_START) {
2488 unm_nic_ioctl(adapter, cmd, wq, mp);
2489 return;
2490 } else {
2491 miocnak(wq, mp, 0, EINVAL);
2492 return;
2493 }
2494 }
2495
2496 /* ARGSUSED */
2497 static boolean_t
2498 ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
2499 {
2500 switch (cap) {
2501 case MAC_CAPAB_HCKSUM:
2502 {
2503 uint32_t *txflags = cap_data;
2504
2505 *txflags = (HCKSUM_ENABLE |
2506 HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM);
2507 }
2508 break;
2509
2510 #ifdef SOLARIS11
2511 case MAC_CAPAB_ANCHOR_VNIC:
2512 case MAC_CAPAB_MULTIFACTADDR:
2513 #else
2514 case MAC_CAPAB_POLL:
2515 case MAC_CAPAB_MULTIADDRESS:
2516 #endif
2517 default:
2518 return (B_FALSE);
2519 }
2520
2521 return (B_TRUE);
2522 }
2523
2524 #define NETXEN_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
2525
2526 static mac_callbacks_t ntxn_m_callbacks = {
2527 NETXEN_M_CALLBACK_FLAGS,
2528 ntxn_m_stat,
2529 ntxn_m_start,
2530 ntxn_m_stop,
2531 ntxn_m_promisc,
2532 ntxn_m_multicst,
2533 ntxn_m_unicst,
2534 ntxn_m_tx,
2535 NULL, /* mc_reserved */
2536 ntxn_m_ioctl,
2537 ntxn_m_getcapab,
2538 NULL, /* mc_open */
2539 NULL, /* mc_close */
2540 NULL, /* mc_setprop */
2541 NULL /* mc_getprop */
2542 };
2543
2544 int
2545 unm_register_mac(unm_adapter *adapter)
2546 {
2547 int ret;
2548 mac_register_t *macp;
2549 unm_pauseparam_t pause;
2550
2551 dev_info_t *dip = adapter->dip;
2552
2553 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
2554 cmn_err(CE_WARN, "Memory not available\n");
2555 return (DDI_FAILURE);
2556 }
2557
2558 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2559 macp->m_driver = adapter;
2560 macp->m_dip = dip;
2561 macp->m_instance = adapter->instance;
2562 macp->m_src_addr = adapter->mac_addr;
2563 macp->m_callbacks = &ntxn_m_callbacks;
2564 macp->m_min_sdu = 0;
2565 macp->m_max_sdu = adapter->mtu;
2566 #ifdef SOLARIS11
2567 macp->m_margin = VLAN_TAGSZ;
2568 #endif /* SOLARIS11 */
2569
2570 ret = mac_register(macp, &adapter->mach);
2571 mac_free(macp);
2572 if (ret != 0) {
2573 cmn_err(CE_WARN, "mac_register failed for port %d\n",
2574 adapter->portnum);
2575 return (DDI_FAILURE);
2576 }
2577
2578 unm_init_kstats(adapter, adapter->instance);
2579
2580 /* Register NDD-tweakable parameters */
2581 if (unm_nd_init(adapter)) {
2582 cmn_err(CE_WARN, "unm_nd_init() failed");
2583 return (DDI_FAILURE);
2584 }
2585
2586 pause.rx_pause = adapter->nd_params[PARAM_ADV_PAUSE_CAP].ndp_val;
2587 pause.tx_pause = adapter->nd_params[PARAM_ADV_ASYM_PAUSE_CAP].ndp_val;
2588
2589 if (unm_nic_set_pauseparam(adapter, &pause)) {
2590 cmn_err(CE_WARN, "\nBad Pause settings RX %d, Tx %d",
2591 pause.rx_pause, pause.tx_pause);
2592 }
2593 adapter->nd_params[PARAM_PAUSE_CAP].ndp_val = pause.rx_pause;
2594 adapter->nd_params[PARAM_ASYM_PAUSE_CAP].ndp_val = pause.tx_pause;
2595
2596 return (DDI_SUCCESS);
2597 }
--- EOF ---