17956Sxiuyan.wang@Sun.COM /*
27956Sxiuyan.wang@Sun.COM * CDDL HEADER START
37956Sxiuyan.wang@Sun.COM *
47956Sxiuyan.wang@Sun.COM * The contents of this file are subject to the terms of the
57956Sxiuyan.wang@Sun.COM * Common Development and Distribution License (the "License").
67956Sxiuyan.wang@Sun.COM * You may not use this file except in compliance with the License.
77956Sxiuyan.wang@Sun.COM *
87956Sxiuyan.wang@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97956Sxiuyan.wang@Sun.COM * or http://www.opensolaris.org/os/licensing.
107956Sxiuyan.wang@Sun.COM * See the License for the specific language governing permissions
117956Sxiuyan.wang@Sun.COM * and limitations under the License.
127956Sxiuyan.wang@Sun.COM *
137956Sxiuyan.wang@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147956Sxiuyan.wang@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157956Sxiuyan.wang@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167956Sxiuyan.wang@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177956Sxiuyan.wang@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187956Sxiuyan.wang@Sun.COM *
197956Sxiuyan.wang@Sun.COM * CDDL HEADER END
207956Sxiuyan.wang@Sun.COM */
217956Sxiuyan.wang@Sun.COM /*
227956Sxiuyan.wang@Sun.COM * Copyright 2008 NetXen, Inc. All rights reserved.
237956Sxiuyan.wang@Sun.COM * Use is subject to license terms.
247956Sxiuyan.wang@Sun.COM */
257956Sxiuyan.wang@Sun.COM /*
26*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
277956Sxiuyan.wang@Sun.COM * Use is subject to license terms.
287956Sxiuyan.wang@Sun.COM */
297956Sxiuyan.wang@Sun.COM #include <sys/types.h>
307956Sxiuyan.wang@Sun.COM #include <sys/conf.h>
317956Sxiuyan.wang@Sun.COM #include <sys/debug.h>
327956Sxiuyan.wang@Sun.COM #include <sys/stropts.h>
337956Sxiuyan.wang@Sun.COM #include <sys/stream.h>
347956Sxiuyan.wang@Sun.COM #include <sys/strlog.h>
357956Sxiuyan.wang@Sun.COM #include <sys/kmem.h>
367956Sxiuyan.wang@Sun.COM #include <sys/stat.h>
377956Sxiuyan.wang@Sun.COM #include <sys/kstat.h>
387956Sxiuyan.wang@Sun.COM #include <sys/vtrace.h>
397956Sxiuyan.wang@Sun.COM #include <sys/dlpi.h>
407956Sxiuyan.wang@Sun.COM #include <sys/strsun.h>
417956Sxiuyan.wang@Sun.COM #include <sys/ethernet.h>
427956Sxiuyan.wang@Sun.COM #include <sys/modctl.h>
437956Sxiuyan.wang@Sun.COM #include <sys/errno.h>
447956Sxiuyan.wang@Sun.COM #include <sys/dditypes.h>
457956Sxiuyan.wang@Sun.COM #include <sys/ddi.h>
467956Sxiuyan.wang@Sun.COM #include <sys/sunddi.h>
477956Sxiuyan.wang@Sun.COM #include <sys/sysmacros.h>
487956Sxiuyan.wang@Sun.COM #include <sys/pci.h>
497956Sxiuyan.wang@Sun.COM
507956Sxiuyan.wang@Sun.COM #include <sys/gld.h>
517956Sxiuyan.wang@Sun.COM #include <netinet/in.h>
527956Sxiuyan.wang@Sun.COM #include <inet/ip.h>
537956Sxiuyan.wang@Sun.COM #include <inet/tcp.h>
547956Sxiuyan.wang@Sun.COM
557956Sxiuyan.wang@Sun.COM #include <sys/rwlock.h>
567956Sxiuyan.wang@Sun.COM #include <sys/mutex.h>
577956Sxiuyan.wang@Sun.COM #include <sys/pattr.h>
587956Sxiuyan.wang@Sun.COM #include <sys/strsubr.h>
597956Sxiuyan.wang@Sun.COM #include <sys/ddi_impldefs.h>
607956Sxiuyan.wang@Sun.COM #include<sys/task.h>
617956Sxiuyan.wang@Sun.COM
627956Sxiuyan.wang@Sun.COM #include "unm_nic_hw.h"
637956Sxiuyan.wang@Sun.COM #include "unm_nic.h"
647956Sxiuyan.wang@Sun.COM
657956Sxiuyan.wang@Sun.COM #include "nic_phan_reg.h"
667956Sxiuyan.wang@Sun.COM #include "unm_nic_ioctl.h"
677956Sxiuyan.wang@Sun.COM #include "nic_cmn.h"
687956Sxiuyan.wang@Sun.COM #include "unm_version.h"
697956Sxiuyan.wang@Sun.COM #include "unm_brdcfg.h"
707956Sxiuyan.wang@Sun.COM
717956Sxiuyan.wang@Sun.COM #if defined(lint)
727956Sxiuyan.wang@Sun.COM #undef MBLKL
737956Sxiuyan.wang@Sun.COM #define MBLKL(_mp_) ((uintptr_t)(_mp_)->b_wptr - (uintptr_t)(_mp_)->b_rptr)
747956Sxiuyan.wang@Sun.COM #endif /* lint */
757956Sxiuyan.wang@Sun.COM
767956Sxiuyan.wang@Sun.COM #undef UNM_LOOPBACK
777956Sxiuyan.wang@Sun.COM #undef SINGLE_DMA_BUF
787956Sxiuyan.wang@Sun.COM
797956Sxiuyan.wang@Sun.COM #define UNM_ADAPTER_UP_MAGIC 777
807956Sxiuyan.wang@Sun.COM #define VLAN_TAGSZ 0x4
817956Sxiuyan.wang@Sun.COM
827956Sxiuyan.wang@Sun.COM #define index2rxbuf(_rdp_, _idx_) ((_rdp_)->rx_buf_pool + (_idx_))
837956Sxiuyan.wang@Sun.COM #define rxbuf2index(_rdp_, _bufp_) ((_bufp_) - (_rdp_)->rx_buf_pool)
847956Sxiuyan.wang@Sun.COM
857956Sxiuyan.wang@Sun.COM /*
867956Sxiuyan.wang@Sun.COM * Receive ISR processes NX_RX_MAXBUFS incoming packets at most, then posts
877956Sxiuyan.wang@Sun.COM * as many buffers as packets processed. This loop repeats as required to
887956Sxiuyan.wang@Sun.COM * process all incoming packets delivered in a single interrupt. Higher
897956Sxiuyan.wang@Sun.COM * value of NX_RX_MAXBUFS improves performance by posting rx buffers less
907956Sxiuyan.wang@Sun.COM * frequently, but at the cost of not posting quickly enough when card is
917956Sxiuyan.wang@Sun.COM * running out of rx buffers.
927956Sxiuyan.wang@Sun.COM */
937956Sxiuyan.wang@Sun.COM #define NX_RX_THRESHOLD 32
947956Sxiuyan.wang@Sun.COM #define NX_RX_MAXBUFS 128
957956Sxiuyan.wang@Sun.COM #define NX_MAX_TXCOMPS 256
967956Sxiuyan.wang@Sun.COM
979436SJing.Xiong@Sun.COM extern int create_rxtx_rings(unm_adapter *adapter);
989436SJing.Xiong@Sun.COM extern void destroy_rxtx_rings(unm_adapter *adapter);
997956Sxiuyan.wang@Sun.COM
1007956Sxiuyan.wang@Sun.COM static void unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
1017956Sxiuyan.wang@Sun.COM uint32_t ringid);
1027956Sxiuyan.wang@Sun.COM static mblk_t *unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc);
1037956Sxiuyan.wang@Sun.COM static int unm_process_rcv_ring(unm_adapter *, int);
1047956Sxiuyan.wang@Sun.COM static int unm_process_cmd_ring(struct unm_adapter_s *adapter);
1057956Sxiuyan.wang@Sun.COM
1067956Sxiuyan.wang@Sun.COM static int unm_nic_do_ioctl(unm_adapter *adapter, queue_t *q, mblk_t *mp);
1077956Sxiuyan.wang@Sun.COM static void unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q,
1087956Sxiuyan.wang@Sun.COM mblk_t *mp);
1097956Sxiuyan.wang@Sun.COM
1107956Sxiuyan.wang@Sun.COM /* GLDv3 interface functions */
1117956Sxiuyan.wang@Sun.COM static int ntxn_m_start(void *);
1127956Sxiuyan.wang@Sun.COM static void ntxn_m_stop(void *);
1137956Sxiuyan.wang@Sun.COM static int ntxn_m_multicst(void *, boolean_t, const uint8_t *);
1147956Sxiuyan.wang@Sun.COM static int ntxn_m_promisc(void *, boolean_t);
1157956Sxiuyan.wang@Sun.COM static int ntxn_m_stat(void *arg, uint_t stat, uint64_t *val);
1167956Sxiuyan.wang@Sun.COM static mblk_t *ntxn_m_tx(void *, mblk_t *);
1177956Sxiuyan.wang@Sun.COM static void ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
1187956Sxiuyan.wang@Sun.COM static boolean_t ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data);
1197956Sxiuyan.wang@Sun.COM
1207956Sxiuyan.wang@Sun.COM /*
1217956Sxiuyan.wang@Sun.COM * Allocates DMA handle, virtual memory and binds them
1227956Sxiuyan.wang@Sun.COM * returns size of actual memory binded and the physical address.
1237956Sxiuyan.wang@Sun.COM */
1247956Sxiuyan.wang@Sun.COM int
unm_pci_alloc_consistent(unm_adapter * adapter,int size,caddr_t * address,ddi_dma_cookie_t * cookie,ddi_dma_handle_t * dma_handle,ddi_acc_handle_t * handlep)1257956Sxiuyan.wang@Sun.COM unm_pci_alloc_consistent(unm_adapter *adapter,
1267956Sxiuyan.wang@Sun.COM int size, caddr_t *address, ddi_dma_cookie_t *cookie,
1277956Sxiuyan.wang@Sun.COM ddi_dma_handle_t *dma_handle, ddi_acc_handle_t *handlep)
1287956Sxiuyan.wang@Sun.COM {
1297956Sxiuyan.wang@Sun.COM int err;
1307956Sxiuyan.wang@Sun.COM uint32_t ncookies;
1317956Sxiuyan.wang@Sun.COM size_t ring_len;
1327956Sxiuyan.wang@Sun.COM uint_t dma_flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
1337956Sxiuyan.wang@Sun.COM
1347956Sxiuyan.wang@Sun.COM *dma_handle = NULL;
1357956Sxiuyan.wang@Sun.COM
1367956Sxiuyan.wang@Sun.COM if (size <= 0)
1377956Sxiuyan.wang@Sun.COM return (DDI_ENOMEM);
1387956Sxiuyan.wang@Sun.COM
1397956Sxiuyan.wang@Sun.COM err = ddi_dma_alloc_handle(adapter->dip,
1407956Sxiuyan.wang@Sun.COM &adapter->gc_dma_attr_desc,
1417956Sxiuyan.wang@Sun.COM DDI_DMA_DONTWAIT, NULL, dma_handle);
1427956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
1437956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "!%s: %s: ddi_dma_alloc_handle FAILED:"
1447956Sxiuyan.wang@Sun.COM " %d", unm_nic_driver_name, __func__, err);
1457956Sxiuyan.wang@Sun.COM return (DDI_ENOMEM);
1467956Sxiuyan.wang@Sun.COM }
1477956Sxiuyan.wang@Sun.COM
1487956Sxiuyan.wang@Sun.COM err = ddi_dma_mem_alloc(*dma_handle,
1497956Sxiuyan.wang@Sun.COM size, &adapter->gc_attr_desc,
1507956Sxiuyan.wang@Sun.COM dma_flags & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT),
1517956Sxiuyan.wang@Sun.COM DDI_DMA_DONTWAIT, NULL, address, &ring_len,
1527956Sxiuyan.wang@Sun.COM handlep);
1537956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
1547956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "!%s: %s: ddi_dma_mem_alloc failed:"
1557956Sxiuyan.wang@Sun.COM "ret %d, request size: %d",
1567956Sxiuyan.wang@Sun.COM unm_nic_driver_name, __func__, err, size);
1577956Sxiuyan.wang@Sun.COM ddi_dma_free_handle(dma_handle);
1587956Sxiuyan.wang@Sun.COM return (DDI_ENOMEM);
1597956Sxiuyan.wang@Sun.COM }
1607956Sxiuyan.wang@Sun.COM
1617956Sxiuyan.wang@Sun.COM if (ring_len < size) {
1627956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s: %s: could not allocate required "
1637956Sxiuyan.wang@Sun.COM "memory :%d\n", unm_nic_driver_name,
1647956Sxiuyan.wang@Sun.COM __func__, err);
1657956Sxiuyan.wang@Sun.COM ddi_dma_mem_free(handlep);
1667956Sxiuyan.wang@Sun.COM ddi_dma_free_handle(dma_handle);
1677956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
1687956Sxiuyan.wang@Sun.COM }
1697956Sxiuyan.wang@Sun.COM
1707956Sxiuyan.wang@Sun.COM (void) memset(*address, 0, size);
1717956Sxiuyan.wang@Sun.COM
1727956Sxiuyan.wang@Sun.COM if (((err = ddi_dma_addr_bind_handle(*dma_handle,
1737956Sxiuyan.wang@Sun.COM NULL, *address, ring_len,
1747956Sxiuyan.wang@Sun.COM dma_flags,
1757956Sxiuyan.wang@Sun.COM DDI_DMA_DONTWAIT, NULL,
1767956Sxiuyan.wang@Sun.COM cookie, &ncookies)) != DDI_DMA_MAPPED) ||
1777956Sxiuyan.wang@Sun.COM (ncookies != 1)) {
1787956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN,
1797956Sxiuyan.wang@Sun.COM "!%s: %s: ddi_dma_addr_bind_handle FAILED: %d",
1807956Sxiuyan.wang@Sun.COM unm_nic_driver_name, __func__, err);
1817956Sxiuyan.wang@Sun.COM ddi_dma_mem_free(handlep);
1827956Sxiuyan.wang@Sun.COM ddi_dma_free_handle(dma_handle);
1837956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
1847956Sxiuyan.wang@Sun.COM }
1857956Sxiuyan.wang@Sun.COM
1867956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
1877956Sxiuyan.wang@Sun.COM }
1887956Sxiuyan.wang@Sun.COM
1897956Sxiuyan.wang@Sun.COM /*
1907956Sxiuyan.wang@Sun.COM * Unbinds the memory, frees the DMA handle and at the end, frees the memory
1917956Sxiuyan.wang@Sun.COM */
1927956Sxiuyan.wang@Sun.COM void
unm_pci_free_consistent(ddi_dma_handle_t * dma_handle,ddi_acc_handle_t * acc_handle)1937956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(ddi_dma_handle_t *dma_handle,
1947956Sxiuyan.wang@Sun.COM ddi_acc_handle_t *acc_handle)
1957956Sxiuyan.wang@Sun.COM {
1967956Sxiuyan.wang@Sun.COM int err;
1977956Sxiuyan.wang@Sun.COM
1987956Sxiuyan.wang@Sun.COM err = ddi_dma_unbind_handle(*dma_handle);
1997956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
2007956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s: Error unbinding memory\n", __func__);
2017956Sxiuyan.wang@Sun.COM return;
2027956Sxiuyan.wang@Sun.COM }
2037956Sxiuyan.wang@Sun.COM
2047956Sxiuyan.wang@Sun.COM ddi_dma_mem_free(acc_handle);
2057956Sxiuyan.wang@Sun.COM ddi_dma_free_handle(dma_handle);
2067956Sxiuyan.wang@Sun.COM }
2077956Sxiuyan.wang@Sun.COM
2087956Sxiuyan.wang@Sun.COM static uint32_t msi_tgt_status[] = {
2097956Sxiuyan.wang@Sun.COM ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
2107956Sxiuyan.wang@Sun.COM ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
2117956Sxiuyan.wang@Sun.COM ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
2127956Sxiuyan.wang@Sun.COM ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
2137956Sxiuyan.wang@Sun.COM };
2147956Sxiuyan.wang@Sun.COM
2157956Sxiuyan.wang@Sun.COM static void
unm_nic_disable_int(unm_adapter * adapter)2167956Sxiuyan.wang@Sun.COM unm_nic_disable_int(unm_adapter *adapter)
2177956Sxiuyan.wang@Sun.COM {
2187956Sxiuyan.wang@Sun.COM __uint32_t temp = 0;
2197956Sxiuyan.wang@Sun.COM
2207956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
2217956Sxiuyan.wang@Sun.COM &temp, 4);
2227956Sxiuyan.wang@Sun.COM }
2237956Sxiuyan.wang@Sun.COM
2249436SJing.Xiong@Sun.COM static inline int
unm_nic_clear_int(unm_adapter * adapter)2257956Sxiuyan.wang@Sun.COM unm_nic_clear_int(unm_adapter *adapter)
2267956Sxiuyan.wang@Sun.COM {
2277956Sxiuyan.wang@Sun.COM uint32_t mask, temp, our_int, status;
2287956Sxiuyan.wang@Sun.COM
2297956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
2307956Sxiuyan.wang@Sun.COM
2317956Sxiuyan.wang@Sun.COM /* check whether it's our interrupt */
2327956Sxiuyan.wang@Sun.COM if (!UNM_IS_MSI_FAMILY(adapter)) {
2337956Sxiuyan.wang@Sun.COM
2347956Sxiuyan.wang@Sun.COM /* Legacy Interrupt case */
2357956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2367956Sxiuyan.wang@Sun.COM &status);
2377956Sxiuyan.wang@Sun.COM
2387956Sxiuyan.wang@Sun.COM if (!(status & adapter->legacy_intr.int_vec_bit)) {
2397956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
2407956Sxiuyan.wang@Sun.COM return (-1);
2417956Sxiuyan.wang@Sun.COM }
2427956Sxiuyan.wang@Sun.COM
2437956Sxiuyan.wang@Sun.COM if (adapter->ahw.revision_id >= NX_P3_B1) {
2447956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_read_immediate(adapter,
2457956Sxiuyan.wang@Sun.COM ISR_INT_STATE_REG, &temp);
2467956Sxiuyan.wang@Sun.COM if (!ISR_IS_LEGACY_INTR_TRIGGERED(temp)) {
2477956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
2487956Sxiuyan.wang@Sun.COM return (-1);
2497956Sxiuyan.wang@Sun.COM }
2507956Sxiuyan.wang@Sun.COM } else if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
2517956Sxiuyan.wang@Sun.COM our_int = adapter->unm_nic_pci_read_normalize(adapter,
2527956Sxiuyan.wang@Sun.COM CRB_INT_VECTOR);
2537956Sxiuyan.wang@Sun.COM
2547956Sxiuyan.wang@Sun.COM /* FIXME: Assumes pci_func is same as ctx */
2557956Sxiuyan.wang@Sun.COM if ((our_int & (0x80 << adapter->portnum)) == 0) {
2567956Sxiuyan.wang@Sun.COM if (our_int != 0) {
2577956Sxiuyan.wang@Sun.COM /* not our interrupt */
2587956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
2597956Sxiuyan.wang@Sun.COM return (-1);
2607956Sxiuyan.wang@Sun.COM }
2617956Sxiuyan.wang@Sun.COM }
2627956Sxiuyan.wang@Sun.COM temp = our_int & ~((u32)(0x80 << adapter->portnum));
2637956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_write_normalize(adapter,
2647956Sxiuyan.wang@Sun.COM CRB_INT_VECTOR, temp);
2657956Sxiuyan.wang@Sun.COM }
2667956Sxiuyan.wang@Sun.COM
2677956Sxiuyan.wang@Sun.COM if (adapter->fw_major < 4)
2687956Sxiuyan.wang@Sun.COM unm_nic_disable_int(adapter);
2697956Sxiuyan.wang@Sun.COM
2707956Sxiuyan.wang@Sun.COM /* claim interrupt */
2717956Sxiuyan.wang@Sun.COM temp = 0xffffffff;
2727956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_write_immediate(adapter,
2737956Sxiuyan.wang@Sun.COM adapter->legacy_intr.tgt_status_reg, &temp);
2747956Sxiuyan.wang@Sun.COM
2757956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2767956Sxiuyan.wang@Sun.COM &mask);
2777956Sxiuyan.wang@Sun.COM
2787956Sxiuyan.wang@Sun.COM /*
2797956Sxiuyan.wang@Sun.COM * Read again to make sure the legacy interrupt message got
2807956Sxiuyan.wang@Sun.COM * flushed out
2817956Sxiuyan.wang@Sun.COM */
2827956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2837956Sxiuyan.wang@Sun.COM &mask);
2847956Sxiuyan.wang@Sun.COM } else if (adapter->flags & UNM_NIC_MSI_ENABLED) {
2857956Sxiuyan.wang@Sun.COM /* clear interrupt */
2867956Sxiuyan.wang@Sun.COM temp = 0xffffffff;
2877956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_write_immediate(adapter,
2887956Sxiuyan.wang@Sun.COM msi_tgt_status[adapter->ahw.pci_func], &temp);
2897956Sxiuyan.wang@Sun.COM }
2907956Sxiuyan.wang@Sun.COM
2917956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
2927956Sxiuyan.wang@Sun.COM
2937956Sxiuyan.wang@Sun.COM return (0);
2947956Sxiuyan.wang@Sun.COM }
2957956Sxiuyan.wang@Sun.COM
2967956Sxiuyan.wang@Sun.COM static void
unm_nic_enable_int(unm_adapter * adapter)2977956Sxiuyan.wang@Sun.COM unm_nic_enable_int(unm_adapter *adapter)
2987956Sxiuyan.wang@Sun.COM {
2997956Sxiuyan.wang@Sun.COM u32 temp = 1;
3007956Sxiuyan.wang@Sun.COM
3017956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
3027956Sxiuyan.wang@Sun.COM &temp, 4);
3037956Sxiuyan.wang@Sun.COM
3047956Sxiuyan.wang@Sun.COM if (!UNM_IS_MSI_FAMILY(adapter)) {
3057956Sxiuyan.wang@Sun.COM u32 mask = 0xfbff;
3067956Sxiuyan.wang@Sun.COM
3077956Sxiuyan.wang@Sun.COM adapter->unm_nic_pci_write_immediate(adapter,
3087956Sxiuyan.wang@Sun.COM adapter->legacy_intr.tgt_mask_reg, &mask);
3097956Sxiuyan.wang@Sun.COM }
3107956Sxiuyan.wang@Sun.COM }
3117956Sxiuyan.wang@Sun.COM
3127956Sxiuyan.wang@Sun.COM static void
unm_free_hw_resources(unm_adapter * adapter)3137956Sxiuyan.wang@Sun.COM unm_free_hw_resources(unm_adapter *adapter)
3147956Sxiuyan.wang@Sun.COM {
3157956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx;
3167956Sxiuyan.wang@Sun.COM unm_rcv_desc_ctx_t *rcv_desc;
3177956Sxiuyan.wang@Sun.COM int ctx, ring;
3187956Sxiuyan.wang@Sun.COM
3197956Sxiuyan.wang@Sun.COM if (adapter->context_alloced == 1) {
3207956Sxiuyan.wang@Sun.COM netxen_destroy_rxtx(adapter);
3217956Sxiuyan.wang@Sun.COM adapter->context_alloced = 0;
3227956Sxiuyan.wang@Sun.COM }
3237956Sxiuyan.wang@Sun.COM
3247956Sxiuyan.wang@Sun.COM if (adapter->ctxDesc != NULL) {
3257956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(&adapter->ctxDesc_dma_handle,
3267956Sxiuyan.wang@Sun.COM &adapter->ctxDesc_acc_handle);
3277956Sxiuyan.wang@Sun.COM adapter->ctxDesc = NULL;
3287956Sxiuyan.wang@Sun.COM }
3297956Sxiuyan.wang@Sun.COM
3307956Sxiuyan.wang@Sun.COM if (adapter->ahw.cmdDescHead != NULL) {
3317956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(&adapter->ahw.cmd_desc_dma_handle,
3327956Sxiuyan.wang@Sun.COM &adapter->ahw.cmd_desc_acc_handle);
3337956Sxiuyan.wang@Sun.COM adapter->ahw.cmdDesc_physAddr = NULL;
3347956Sxiuyan.wang@Sun.COM adapter->ahw.cmdDescHead = NULL;
3357956Sxiuyan.wang@Sun.COM }
3367956Sxiuyan.wang@Sun.COM
3377956Sxiuyan.wang@Sun.COM for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
3387956Sxiuyan.wang@Sun.COM recv_ctx = &adapter->recv_ctx[ctx];
3397956Sxiuyan.wang@Sun.COM for (ring = 0; ring < adapter->max_rds_rings; ring++) {
3407956Sxiuyan.wang@Sun.COM rcv_desc = &recv_ctx->rcv_desc[ring];
3417956Sxiuyan.wang@Sun.COM
3427956Sxiuyan.wang@Sun.COM if (rcv_desc->desc_head != NULL) {
3437956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(
3447956Sxiuyan.wang@Sun.COM &rcv_desc->rx_desc_dma_handle,
3457956Sxiuyan.wang@Sun.COM &rcv_desc->rx_desc_acc_handle);
3467956Sxiuyan.wang@Sun.COM rcv_desc->desc_head = NULL;
3477956Sxiuyan.wang@Sun.COM rcv_desc->phys_addr = NULL;
3487956Sxiuyan.wang@Sun.COM }
3497956Sxiuyan.wang@Sun.COM }
3507956Sxiuyan.wang@Sun.COM
3517956Sxiuyan.wang@Sun.COM if (recv_ctx->rcvStatusDescHead != NULL) {
3527956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(
3537956Sxiuyan.wang@Sun.COM &recv_ctx->status_desc_dma_handle,
3547956Sxiuyan.wang@Sun.COM &recv_ctx->status_desc_acc_handle);
3557956Sxiuyan.wang@Sun.COM recv_ctx->rcvStatusDesc_physAddr = NULL;
3567956Sxiuyan.wang@Sun.COM recv_ctx->rcvStatusDescHead = NULL;
3577956Sxiuyan.wang@Sun.COM }
3587956Sxiuyan.wang@Sun.COM }
3597956Sxiuyan.wang@Sun.COM }
3607956Sxiuyan.wang@Sun.COM
3617956Sxiuyan.wang@Sun.COM static void
cleanup_adapter(struct unm_adapter_s * adapter)3627956Sxiuyan.wang@Sun.COM cleanup_adapter(struct unm_adapter_s *adapter)
3637956Sxiuyan.wang@Sun.COM {
3647956Sxiuyan.wang@Sun.COM ddi_regs_map_free(&(adapter->regs_handle));
3657956Sxiuyan.wang@Sun.COM ddi_regs_map_free(&(adapter->db_handle));
3667956Sxiuyan.wang@Sun.COM kmem_free(adapter, sizeof (unm_adapter));
3677956Sxiuyan.wang@Sun.COM }
3687956Sxiuyan.wang@Sun.COM
3697956Sxiuyan.wang@Sun.COM void
unm_nic_remove(unm_adapter * adapter)3707956Sxiuyan.wang@Sun.COM unm_nic_remove(unm_adapter *adapter)
3717956Sxiuyan.wang@Sun.COM {
3727956Sxiuyan.wang@Sun.COM mac_link_update(adapter->mach, LINK_STATE_DOWN);
3737956Sxiuyan.wang@Sun.COM unm_nic_stop_port(adapter);
3747956Sxiuyan.wang@Sun.COM
3757956Sxiuyan.wang@Sun.COM if (adapter->interrupt_crb) {
3767956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
3777956Sxiuyan.wang@Sun.COM unm_nic_disable_int(adapter);
3787956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
3797956Sxiuyan.wang@Sun.COM }
3807956Sxiuyan.wang@Sun.COM (void) untimeout(adapter->watchdog_timer);
3817956Sxiuyan.wang@Sun.COM
3827956Sxiuyan.wang@Sun.COM unm_free_hw_resources(adapter);
3839436SJing.Xiong@Sun.COM
3849436SJing.Xiong@Sun.COM if (adapter->is_up == UNM_ADAPTER_UP_MAGIC)
3859436SJing.Xiong@Sun.COM destroy_rxtx_rings(adapter);
3867956Sxiuyan.wang@Sun.COM
3877956Sxiuyan.wang@Sun.COM if (adapter->portnum == 0)
3887956Sxiuyan.wang@Sun.COM unm_free_dummy_dma(adapter);
3897956Sxiuyan.wang@Sun.COM
3907956Sxiuyan.wang@Sun.COM unm_destroy_intr(adapter);
3917956Sxiuyan.wang@Sun.COM
3927956Sxiuyan.wang@Sun.COM ddi_set_driver_private(adapter->dip, NULL);
3937956Sxiuyan.wang@Sun.COM cleanup_adapter(adapter);
3947956Sxiuyan.wang@Sun.COM }
3957956Sxiuyan.wang@Sun.COM
3967956Sxiuyan.wang@Sun.COM static int
init_firmware(unm_adapter * adapter)3977956Sxiuyan.wang@Sun.COM init_firmware(unm_adapter *adapter)
3987956Sxiuyan.wang@Sun.COM {
3997956Sxiuyan.wang@Sun.COM uint32_t state = 0, loops = 0, tempout;
4007956Sxiuyan.wang@Sun.COM
4017956Sxiuyan.wang@Sun.COM /* Window 1 call */
4027956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
4037956Sxiuyan.wang@Sun.COM state = adapter->unm_nic_pci_read_normalize(adapter, CRB_CMDPEG_STATE);
4047956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
4057956Sxiuyan.wang@Sun.COM
4067956Sxiuyan.wang@Sun.COM if (state == PHAN_INITIALIZE_ACK)
4077956Sxiuyan.wang@Sun.COM return (0);
4087956Sxiuyan.wang@Sun.COM
4097956Sxiuyan.wang@Sun.COM while (state != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
4107956Sxiuyan.wang@Sun.COM drv_usecwait(100);
4117956Sxiuyan.wang@Sun.COM /* Window 1 call */
4127956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
4137956Sxiuyan.wang@Sun.COM state = adapter->unm_nic_pci_read_normalize(adapter,
4147956Sxiuyan.wang@Sun.COM CRB_CMDPEG_STATE);
4157956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
4167956Sxiuyan.wang@Sun.COM loops++;
4177956Sxiuyan.wang@Sun.COM }
4187956Sxiuyan.wang@Sun.COM
4197956Sxiuyan.wang@Sun.COM if (loops >= 200000) {
4207956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: CmdPeg init incomplete:%x\n",
4217956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance, state);
4227956Sxiuyan.wang@Sun.COM return (-EIO);
4237956Sxiuyan.wang@Sun.COM }
4247956Sxiuyan.wang@Sun.COM
4257956Sxiuyan.wang@Sun.COM /* Window 1 call */
4267956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
4277956Sxiuyan.wang@Sun.COM tempout = INTR_SCHEME_PERPORT;
4287956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_CAPABILITIES_HOST,
4297956Sxiuyan.wang@Sun.COM &tempout, 4);
4307956Sxiuyan.wang@Sun.COM tempout = MSI_MODE_MULTIFUNC;
4317956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_MSI_MODE_HOST,
4327956Sxiuyan.wang@Sun.COM &tempout, 4);
4337956Sxiuyan.wang@Sun.COM tempout = MPORT_MULTI_FUNCTION_MODE;
4347956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, CRB_MPORT_MODE, &tempout, 4);
4357956Sxiuyan.wang@Sun.COM tempout = PHAN_INITIALIZE_ACK;
4367956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, CRB_CMDPEG_STATE, &tempout, 4);
4377956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
4387956Sxiuyan.wang@Sun.COM
4397956Sxiuyan.wang@Sun.COM return (0);
4407956Sxiuyan.wang@Sun.COM }
4417956Sxiuyan.wang@Sun.COM
4427956Sxiuyan.wang@Sun.COM /*
4437956Sxiuyan.wang@Sun.COM * Utility to synchronize with receive peg.
4447956Sxiuyan.wang@Sun.COM * Returns 0 on sucess
4457956Sxiuyan.wang@Sun.COM * -EIO on error
4467956Sxiuyan.wang@Sun.COM */
4477956Sxiuyan.wang@Sun.COM int
receive_peg_ready(struct unm_adapter_s * adapter)4487956Sxiuyan.wang@Sun.COM receive_peg_ready(struct unm_adapter_s *adapter)
4497956Sxiuyan.wang@Sun.COM {
4507956Sxiuyan.wang@Sun.COM uint32_t state = 0;
4517956Sxiuyan.wang@Sun.COM int loops = 0, err = 0;
4527956Sxiuyan.wang@Sun.COM
4537956Sxiuyan.wang@Sun.COM /* Window 1 call */
4547956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
4557956Sxiuyan.wang@Sun.COM state = adapter->unm_nic_pci_read_normalize(adapter, CRB_RCVPEG_STATE);
4567956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
4577956Sxiuyan.wang@Sun.COM
4587956Sxiuyan.wang@Sun.COM while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 20000)) {
4597956Sxiuyan.wang@Sun.COM drv_usecwait(100);
4607956Sxiuyan.wang@Sun.COM /* Window 1 call */
4617956Sxiuyan.wang@Sun.COM
4627956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
4637956Sxiuyan.wang@Sun.COM state = adapter->unm_nic_pci_read_normalize(adapter,
4647956Sxiuyan.wang@Sun.COM CRB_RCVPEG_STATE);
4657956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
4667956Sxiuyan.wang@Sun.COM
4677956Sxiuyan.wang@Sun.COM loops++;
4687956Sxiuyan.wang@Sun.COM }
4697956Sxiuyan.wang@Sun.COM
4707956Sxiuyan.wang@Sun.COM if (loops >= 20000) {
4717956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Receive Peg initialization incomplete 0x%x\n",
4727956Sxiuyan.wang@Sun.COM state);
4737956Sxiuyan.wang@Sun.COM err = -EIO;
4747956Sxiuyan.wang@Sun.COM }
4757956Sxiuyan.wang@Sun.COM
4767956Sxiuyan.wang@Sun.COM return (err);
4777956Sxiuyan.wang@Sun.COM }
4787956Sxiuyan.wang@Sun.COM
4797956Sxiuyan.wang@Sun.COM /*
4807956Sxiuyan.wang@Sun.COM * check if the firmware has been downloaded and ready to run and
4817956Sxiuyan.wang@Sun.COM * setup the address for the descriptors in the adapter
4827956Sxiuyan.wang@Sun.COM */
4837956Sxiuyan.wang@Sun.COM static int
unm_nic_hw_resources(unm_adapter * adapter)4847956Sxiuyan.wang@Sun.COM unm_nic_hw_resources(unm_adapter *adapter)
4857956Sxiuyan.wang@Sun.COM {
4867956Sxiuyan.wang@Sun.COM hardware_context *hw = &adapter->ahw;
4877956Sxiuyan.wang@Sun.COM void *addr;
4887956Sxiuyan.wang@Sun.COM int err;
4897956Sxiuyan.wang@Sun.COM int ctx, ring;
4907956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx;
4917956Sxiuyan.wang@Sun.COM unm_rcv_desc_ctx_t *rcv_desc;
4927956Sxiuyan.wang@Sun.COM ddi_dma_cookie_t cookie;
4937956Sxiuyan.wang@Sun.COM int size;
4947956Sxiuyan.wang@Sun.COM
4957956Sxiuyan.wang@Sun.COM if (err = receive_peg_ready(adapter))
4967956Sxiuyan.wang@Sun.COM return (err);
4977956Sxiuyan.wang@Sun.COM
4987956Sxiuyan.wang@Sun.COM size = (sizeof (RingContext) + sizeof (uint32_t));
4997956Sxiuyan.wang@Sun.COM
5007956Sxiuyan.wang@Sun.COM err = unm_pci_alloc_consistent(adapter,
5017956Sxiuyan.wang@Sun.COM size, (caddr_t *)&addr, &cookie,
5027956Sxiuyan.wang@Sun.COM &adapter->ctxDesc_dma_handle,
5037956Sxiuyan.wang@Sun.COM &adapter->ctxDesc_acc_handle);
5047956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
5057956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Failed to allocate HW context\n");
5067956Sxiuyan.wang@Sun.COM return (err);
5077956Sxiuyan.wang@Sun.COM }
5087956Sxiuyan.wang@Sun.COM
5097956Sxiuyan.wang@Sun.COM adapter->ctxDesc_physAddr = cookie.dmac_laddress;
5107956Sxiuyan.wang@Sun.COM
5117956Sxiuyan.wang@Sun.COM (void) memset(addr, 0, sizeof (RingContext));
5127956Sxiuyan.wang@Sun.COM
5137956Sxiuyan.wang@Sun.COM adapter->ctxDesc = (RingContext *) addr;
5147956Sxiuyan.wang@Sun.COM adapter->ctxDesc->CtxId = adapter->portnum;
5157956Sxiuyan.wang@Sun.COM adapter->ctxDesc->CMD_CONSUMER_OFFSET =
5167956Sxiuyan.wang@Sun.COM adapter->ctxDesc_physAddr + sizeof (RingContext);
5177956Sxiuyan.wang@Sun.COM adapter->cmdConsumer =
5187956Sxiuyan.wang@Sun.COM (uint32_t *)(uintptr_t)(((char *)addr) + sizeof (RingContext));
5197956Sxiuyan.wang@Sun.COM
5207956Sxiuyan.wang@Sun.COM ASSERT(!((unsigned long)adapter->ctxDesc_physAddr & 0x3f));
5217956Sxiuyan.wang@Sun.COM
5227956Sxiuyan.wang@Sun.COM /*
5237956Sxiuyan.wang@Sun.COM * Allocate command descriptor ring.
5247956Sxiuyan.wang@Sun.COM */
5257956Sxiuyan.wang@Sun.COM size = (sizeof (cmdDescType0_t) * adapter->MaxTxDescCount);
5267956Sxiuyan.wang@Sun.COM err = unm_pci_alloc_consistent(adapter,
5277956Sxiuyan.wang@Sun.COM size, (caddr_t *)&addr, &cookie,
5287956Sxiuyan.wang@Sun.COM &hw->cmd_desc_dma_handle,
5297956Sxiuyan.wang@Sun.COM &hw->cmd_desc_acc_handle);
5307956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
5317956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Failed to allocate cmd desc ring\n");
5327956Sxiuyan.wang@Sun.COM return (err);
5337956Sxiuyan.wang@Sun.COM }
5347956Sxiuyan.wang@Sun.COM
5357956Sxiuyan.wang@Sun.COM hw->cmdDesc_physAddr = cookie.dmac_laddress;
5367956Sxiuyan.wang@Sun.COM hw->cmdDescHead = (cmdDescType0_t *)addr;
5377956Sxiuyan.wang@Sun.COM
5387956Sxiuyan.wang@Sun.COM for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
5397956Sxiuyan.wang@Sun.COM recv_ctx = &adapter->recv_ctx[ctx];
5407956Sxiuyan.wang@Sun.COM
5417956Sxiuyan.wang@Sun.COM size = (sizeof (statusDesc_t)* adapter->MaxRxDescCount);
5427956Sxiuyan.wang@Sun.COM err = unm_pci_alloc_consistent(adapter,
5437956Sxiuyan.wang@Sun.COM size, (caddr_t *)&addr,
5447956Sxiuyan.wang@Sun.COM &recv_ctx->status_desc_dma_cookie,
5457956Sxiuyan.wang@Sun.COM &recv_ctx->status_desc_dma_handle,
5467956Sxiuyan.wang@Sun.COM &recv_ctx->status_desc_acc_handle);
5477956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
5487956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Failed to allocate sts desc ring\n");
5497956Sxiuyan.wang@Sun.COM goto free_cmd_desc;
5507956Sxiuyan.wang@Sun.COM }
5517956Sxiuyan.wang@Sun.COM
5527956Sxiuyan.wang@Sun.COM (void) memset(addr, 0, size);
5537956Sxiuyan.wang@Sun.COM recv_ctx->rcvStatusDesc_physAddr =
5547956Sxiuyan.wang@Sun.COM recv_ctx->status_desc_dma_cookie.dmac_laddress;
5557956Sxiuyan.wang@Sun.COM recv_ctx->rcvStatusDescHead = (statusDesc_t *)addr;
5567956Sxiuyan.wang@Sun.COM
5577956Sxiuyan.wang@Sun.COM /* rds rings */
5587956Sxiuyan.wang@Sun.COM for (ring = 0; ring < adapter->max_rds_rings; ring++) {
5597956Sxiuyan.wang@Sun.COM rcv_desc = &recv_ctx->rcv_desc[ring];
5607956Sxiuyan.wang@Sun.COM
5617956Sxiuyan.wang@Sun.COM size = (sizeof (rcvDesc_t) * adapter->MaxRxDescCount);
5627956Sxiuyan.wang@Sun.COM err = unm_pci_alloc_consistent(adapter,
5637956Sxiuyan.wang@Sun.COM size, (caddr_t *)&addr,
5647956Sxiuyan.wang@Sun.COM &rcv_desc->rx_desc_dma_cookie,
5657956Sxiuyan.wang@Sun.COM &rcv_desc->rx_desc_dma_handle,
5667956Sxiuyan.wang@Sun.COM &rcv_desc->rx_desc_acc_handle);
5677956Sxiuyan.wang@Sun.COM if (err != DDI_SUCCESS) {
5687956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Failed to allocate "
5697956Sxiuyan.wang@Sun.COM "rx desc ring %d\n", ring);
5707956Sxiuyan.wang@Sun.COM goto free_status_desc;
5717956Sxiuyan.wang@Sun.COM }
5727956Sxiuyan.wang@Sun.COM
5737956Sxiuyan.wang@Sun.COM rcv_desc->phys_addr =
5747956Sxiuyan.wang@Sun.COM rcv_desc->rx_desc_dma_cookie.dmac_laddress;
5757956Sxiuyan.wang@Sun.COM rcv_desc->desc_head = (rcvDesc_t *)addr;
5767956Sxiuyan.wang@Sun.COM }
5777956Sxiuyan.wang@Sun.COM }
5787956Sxiuyan.wang@Sun.COM
5797956Sxiuyan.wang@Sun.COM if (err = netxen_create_rxtx(adapter))
5807956Sxiuyan.wang@Sun.COM goto free_statusrx_desc;
5817956Sxiuyan.wang@Sun.COM adapter->context_alloced = 1;
5827956Sxiuyan.wang@Sun.COM
5837956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
5847956Sxiuyan.wang@Sun.COM
5857956Sxiuyan.wang@Sun.COM free_statusrx_desc:
5867956Sxiuyan.wang@Sun.COM free_status_desc:
5877956Sxiuyan.wang@Sun.COM free_cmd_desc:
5887956Sxiuyan.wang@Sun.COM unm_free_hw_resources(adapter);
5897956Sxiuyan.wang@Sun.COM
5907956Sxiuyan.wang@Sun.COM return (err);
5917956Sxiuyan.wang@Sun.COM }
5927956Sxiuyan.wang@Sun.COM
unm_desc_dma_sync(ddi_dma_handle_t handle,uint_t start,uint_t count,uint_t range,uint_t unit_size,uint_t direction)5937956Sxiuyan.wang@Sun.COM void unm_desc_dma_sync(ddi_dma_handle_t handle, uint_t start, uint_t count,
5947956Sxiuyan.wang@Sun.COM uint_t range, uint_t unit_size, uint_t direction)
5957956Sxiuyan.wang@Sun.COM {
5967956Sxiuyan.wang@Sun.COM if ((start + count) < range) {
5977956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(handle, start * unit_size,
5987956Sxiuyan.wang@Sun.COM count * unit_size, direction);
5997956Sxiuyan.wang@Sun.COM } else {
6007956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(handle, start * unit_size, 0, direction);
6017956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(handle, 0,
6027956Sxiuyan.wang@Sun.COM (start + count - range) * unit_size, DDI_DMA_SYNC_FORCPU);
6037956Sxiuyan.wang@Sun.COM }
6047956Sxiuyan.wang@Sun.COM }
6057956Sxiuyan.wang@Sun.COM
6067956Sxiuyan.wang@Sun.COM static uint32_t crb_cmd_producer[4] = { CRB_CMD_PRODUCER_OFFSET,
6077956Sxiuyan.wang@Sun.COM CRB_CMD_PRODUCER_OFFSET_1, CRB_CMD_PRODUCER_OFFSET_2,
6087956Sxiuyan.wang@Sun.COM CRB_CMD_PRODUCER_OFFSET_3 };
6097956Sxiuyan.wang@Sun.COM
6107956Sxiuyan.wang@Sun.COM static uint32_t crb_cmd_consumer[4] = { CRB_CMD_CONSUMER_OFFSET,
6117956Sxiuyan.wang@Sun.COM CRB_CMD_CONSUMER_OFFSET_1, CRB_CMD_CONSUMER_OFFSET_2,
6127956Sxiuyan.wang@Sun.COM CRB_CMD_CONSUMER_OFFSET_3 };
6137956Sxiuyan.wang@Sun.COM
6147956Sxiuyan.wang@Sun.COM void
unm_nic_update_cmd_producer(struct unm_adapter_s * adapter,uint32_t crb_producer)6157956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_producer(struct unm_adapter_s *adapter,
6167956Sxiuyan.wang@Sun.COM uint32_t crb_producer)
6177956Sxiuyan.wang@Sun.COM {
6187956Sxiuyan.wang@Sun.COM int data = crb_producer;
6197956Sxiuyan.wang@Sun.COM
6207956Sxiuyan.wang@Sun.COM if (adapter->crb_addr_cmd_producer) {
6217956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
6227956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter,
6237956Sxiuyan.wang@Sun.COM adapter->crb_addr_cmd_producer, &data, 4);
6247956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
6257956Sxiuyan.wang@Sun.COM }
6267956Sxiuyan.wang@Sun.COM }
6277956Sxiuyan.wang@Sun.COM
6287956Sxiuyan.wang@Sun.COM static void
unm_nic_update_cmd_consumer(struct unm_adapter_s * adapter,uint32_t crb_producer)6297956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_consumer(struct unm_adapter_s *adapter,
6307956Sxiuyan.wang@Sun.COM uint32_t crb_producer)
6317956Sxiuyan.wang@Sun.COM {
6327956Sxiuyan.wang@Sun.COM int data = crb_producer;
6337956Sxiuyan.wang@Sun.COM
6347956Sxiuyan.wang@Sun.COM if (adapter->crb_addr_cmd_consumer)
6357956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter,
6367956Sxiuyan.wang@Sun.COM adapter->crb_addr_cmd_consumer, &data, 4);
6377956Sxiuyan.wang@Sun.COM }
6387956Sxiuyan.wang@Sun.COM
6397956Sxiuyan.wang@Sun.COM /*
6407956Sxiuyan.wang@Sun.COM * Looks for type of packet and sets opcode accordingly
6417956Sxiuyan.wang@Sun.COM * so that checksum offload can be used.
6427956Sxiuyan.wang@Sun.COM */
6437956Sxiuyan.wang@Sun.COM static void
unm_tx_csum(cmdDescType0_t * desc,mblk_t * mp,pktinfo_t * pktinfo)6447956Sxiuyan.wang@Sun.COM unm_tx_csum(cmdDescType0_t *desc, mblk_t *mp, pktinfo_t *pktinfo)
6457956Sxiuyan.wang@Sun.COM {
6467956Sxiuyan.wang@Sun.COM if (pktinfo->mac_hlen == sizeof (struct ether_vlan_header))
6477956Sxiuyan.wang@Sun.COM desc->u1.s1.flags = FLAGS_VLAN_TAGGED;
6487956Sxiuyan.wang@Sun.COM
6497956Sxiuyan.wang@Sun.COM if (pktinfo->etype == htons(ETHERTYPE_IP)) {
6507956Sxiuyan.wang@Sun.COM uint32_t start, flags;
6517956Sxiuyan.wang@Sun.COM
652*11878SVenu.Iyer@Sun.COM mac_hcksum_get(mp, &start, NULL, NULL, NULL, &flags);
6537956Sxiuyan.wang@Sun.COM if ((flags & (HCK_FULLCKSUM | HCK_IPV4_HDRCKSUM)) == 0)
6547956Sxiuyan.wang@Sun.COM return;
6557956Sxiuyan.wang@Sun.COM
6567956Sxiuyan.wang@Sun.COM /*
6577956Sxiuyan.wang@Sun.COM * For TCP/UDP, ask hardware to do both IP header and
6587956Sxiuyan.wang@Sun.COM * full checksum, even if stack has already done one or
6597956Sxiuyan.wang@Sun.COM * the other. Hardware will always get it correct even
6607956Sxiuyan.wang@Sun.COM * if stack has already done it.
6617956Sxiuyan.wang@Sun.COM */
6627956Sxiuyan.wang@Sun.COM switch (pktinfo->l4_proto) {
6637956Sxiuyan.wang@Sun.COM case IPPROTO_TCP:
6647956Sxiuyan.wang@Sun.COM desc->u1.s1.opcode = TX_TCP_PKT;
6657956Sxiuyan.wang@Sun.COM break;
6667956Sxiuyan.wang@Sun.COM case IPPROTO_UDP:
6677956Sxiuyan.wang@Sun.COM desc->u1.s1.opcode = TX_UDP_PKT;
6687956Sxiuyan.wang@Sun.COM break;
6697956Sxiuyan.wang@Sun.COM default:
6707956Sxiuyan.wang@Sun.COM /* Must be here with HCK_IPV4_HDRCKSUM */
6717956Sxiuyan.wang@Sun.COM desc->u1.s1.opcode = TX_IP_PKT;
6727956Sxiuyan.wang@Sun.COM return;
6737956Sxiuyan.wang@Sun.COM }
6747956Sxiuyan.wang@Sun.COM
6757956Sxiuyan.wang@Sun.COM desc->u1.s1.ipHdrOffset = pktinfo->mac_hlen;
6767956Sxiuyan.wang@Sun.COM desc->u1.s1.tcpHdrOffset = pktinfo->mac_hlen + pktinfo->ip_hlen;
6777956Sxiuyan.wang@Sun.COM }
6787956Sxiuyan.wang@Sun.COM }
6797956Sxiuyan.wang@Sun.COM
6807956Sxiuyan.wang@Sun.COM /*
6817956Sxiuyan.wang@Sun.COM * For IP/UDP/TCP checksum offload, this checks for MAC+IP header in one
6827956Sxiuyan.wang@Sun.COM * contiguous block ending at 8 byte aligned address as required by hardware.
6837956Sxiuyan.wang@Sun.COM * Caller assumes pktinfo->total_len will be updated by this function and
6847956Sxiuyan.wang@Sun.COM * if pktinfo->etype is set to 0, it will need to linearize the mblk and
6857956Sxiuyan.wang@Sun.COM * invoke unm_update_pkt_info() to determine ethertype, IP header len and
6867956Sxiuyan.wang@Sun.COM * protocol.
6877956Sxiuyan.wang@Sun.COM */
6887956Sxiuyan.wang@Sun.COM static boolean_t
unm_get_pkt_info(mblk_t * mp,pktinfo_t * pktinfo)6897956Sxiuyan.wang@Sun.COM unm_get_pkt_info(mblk_t *mp, pktinfo_t *pktinfo)
6907956Sxiuyan.wang@Sun.COM {
6917956Sxiuyan.wang@Sun.COM mblk_t *bp;
6927956Sxiuyan.wang@Sun.COM ushort_t type;
6937956Sxiuyan.wang@Sun.COM
6947956Sxiuyan.wang@Sun.COM (void) memset(pktinfo, 0, sizeof (pktinfo_t));
6957956Sxiuyan.wang@Sun.COM
6967956Sxiuyan.wang@Sun.COM for (bp = mp; bp != NULL; bp = bp->b_cont) {
6977956Sxiuyan.wang@Sun.COM if (MBLKL(bp) == 0)
6987956Sxiuyan.wang@Sun.COM continue;
6997956Sxiuyan.wang@Sun.COM pktinfo->mblk_no++;
7007956Sxiuyan.wang@Sun.COM pktinfo->total_len += MBLKL(bp);
7017956Sxiuyan.wang@Sun.COM }
7027956Sxiuyan.wang@Sun.COM
7037956Sxiuyan.wang@Sun.COM if (MBLKL(mp) < (sizeof (struct ether_header) + sizeof (ipha_t)))
7047956Sxiuyan.wang@Sun.COM return (B_FALSE);
7057956Sxiuyan.wang@Sun.COM
7067956Sxiuyan.wang@Sun.COM /*
7077956Sxiuyan.wang@Sun.COM * We just need non 1 byte aligned address, since ether_type is
7087956Sxiuyan.wang@Sun.COM * ushort.
7097956Sxiuyan.wang@Sun.COM */
7107956Sxiuyan.wang@Sun.COM if ((uintptr_t)mp->b_rptr & 1)
7117956Sxiuyan.wang@Sun.COM return (B_FALSE);
7127956Sxiuyan.wang@Sun.COM
7137956Sxiuyan.wang@Sun.COM type = ((struct ether_header *)(uintptr_t)mp->b_rptr)->ether_type;
7147956Sxiuyan.wang@Sun.COM if (type == htons(ETHERTYPE_VLAN)) {
7157956Sxiuyan.wang@Sun.COM if (MBLKL(mp) < (sizeof (struct ether_vlan_header) +
7167956Sxiuyan.wang@Sun.COM sizeof (ipha_t)))
7177956Sxiuyan.wang@Sun.COM return (B_FALSE);
7187956Sxiuyan.wang@Sun.COM type = ((struct ether_vlan_header *) \
7197956Sxiuyan.wang@Sun.COM (uintptr_t)mp->b_rptr)->ether_type;
7207956Sxiuyan.wang@Sun.COM pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
7217956Sxiuyan.wang@Sun.COM } else {
7227956Sxiuyan.wang@Sun.COM pktinfo->mac_hlen = sizeof (struct ether_header);
7237956Sxiuyan.wang@Sun.COM }
7247956Sxiuyan.wang@Sun.COM pktinfo->etype = type;
7257956Sxiuyan.wang@Sun.COM
7267956Sxiuyan.wang@Sun.COM if (pktinfo->etype == htons(ETHERTYPE_IP)) {
7277956Sxiuyan.wang@Sun.COM uchar_t *ip_off = mp->b_rptr + pktinfo->mac_hlen;
7287956Sxiuyan.wang@Sun.COM
7297956Sxiuyan.wang@Sun.COM pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ip_off);
7307956Sxiuyan.wang@Sun.COM pktinfo->l4_proto =
7317956Sxiuyan.wang@Sun.COM ((ipha_t *)(uintptr_t)ip_off)->ipha_protocol;
7327956Sxiuyan.wang@Sun.COM
7337956Sxiuyan.wang@Sun.COM /* IP header not aligned to quadward boundary? */
7347956Sxiuyan.wang@Sun.COM if ((unsigned long)(ip_off + pktinfo->ip_hlen) % 8 != 0)
7357956Sxiuyan.wang@Sun.COM return (B_FALSE);
7367956Sxiuyan.wang@Sun.COM }
7377956Sxiuyan.wang@Sun.COM
7387956Sxiuyan.wang@Sun.COM return (B_TRUE);
7397956Sxiuyan.wang@Sun.COM }
7407956Sxiuyan.wang@Sun.COM
7417956Sxiuyan.wang@Sun.COM static void
unm_update_pkt_info(char * ptr,pktinfo_t * pktinfo)7427956Sxiuyan.wang@Sun.COM unm_update_pkt_info(char *ptr, pktinfo_t *pktinfo)
7437956Sxiuyan.wang@Sun.COM {
7447956Sxiuyan.wang@Sun.COM ushort_t type;
7457956Sxiuyan.wang@Sun.COM
7467956Sxiuyan.wang@Sun.COM type = ((struct ether_header *)(uintptr_t)ptr)->ether_type;
7477956Sxiuyan.wang@Sun.COM if (type == htons(ETHERTYPE_VLAN)) {
7487956Sxiuyan.wang@Sun.COM type = ((struct ether_vlan_header *)(uintptr_t)ptr)->ether_type;
7497956Sxiuyan.wang@Sun.COM pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
7507956Sxiuyan.wang@Sun.COM } else {
7517956Sxiuyan.wang@Sun.COM pktinfo->mac_hlen = sizeof (struct ether_header);
7527956Sxiuyan.wang@Sun.COM }
7537956Sxiuyan.wang@Sun.COM pktinfo->etype = type;
7547956Sxiuyan.wang@Sun.COM
7557956Sxiuyan.wang@Sun.COM if (pktinfo->etype == htons(ETHERTYPE_IP)) {
7567956Sxiuyan.wang@Sun.COM char *ipp = ptr + pktinfo->mac_hlen;
7577956Sxiuyan.wang@Sun.COM
7587956Sxiuyan.wang@Sun.COM pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ipp);
7597956Sxiuyan.wang@Sun.COM pktinfo->l4_proto = ((ipha_t *)(uintptr_t)ipp)->ipha_protocol;
7607956Sxiuyan.wang@Sun.COM }
7617956Sxiuyan.wang@Sun.COM }
7627956Sxiuyan.wang@Sun.COM
7637956Sxiuyan.wang@Sun.COM static boolean_t
unm_send_copy(struct unm_adapter_s * adapter,mblk_t * mp,pktinfo_t * pktinfo)7647956Sxiuyan.wang@Sun.COM unm_send_copy(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
7657956Sxiuyan.wang@Sun.COM {
7667956Sxiuyan.wang@Sun.COM hardware_context *hw;
7677956Sxiuyan.wang@Sun.COM u32 producer = 0;
7687956Sxiuyan.wang@Sun.COM cmdDescType0_t *hwdesc;
7697956Sxiuyan.wang@Sun.COM struct unm_cmd_buffer *pbuf = NULL;
7707956Sxiuyan.wang@Sun.COM u32 mblen;
7717956Sxiuyan.wang@Sun.COM int no_of_desc = 1;
7727956Sxiuyan.wang@Sun.COM int MaxTxDescCount;
7737956Sxiuyan.wang@Sun.COM mblk_t *bp;
7747956Sxiuyan.wang@Sun.COM char *txb;
7757956Sxiuyan.wang@Sun.COM
7767956Sxiuyan.wang@Sun.COM hw = &adapter->ahw;
7777956Sxiuyan.wang@Sun.COM MaxTxDescCount = adapter->MaxTxDescCount;
7787956Sxiuyan.wang@Sun.COM
7797956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK(&adapter->tx_lock);
7807956Sxiuyan.wang@Sun.COM membar_enter();
7817956Sxiuyan.wang@Sun.COM
7827956Sxiuyan.wang@Sun.COM if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
7837956Sxiuyan.wang@Sun.COM MaxTxDescCount) <= 2) {
7847956Sxiuyan.wang@Sun.COM adapter->stats.outofcmddesc++;
7857956Sxiuyan.wang@Sun.COM adapter->resched_needed = 1;
7867956Sxiuyan.wang@Sun.COM membar_exit();
7877956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->tx_lock);
7887956Sxiuyan.wang@Sun.COM return (B_FALSE);
7897956Sxiuyan.wang@Sun.COM }
7907956Sxiuyan.wang@Sun.COM adapter->freecmds -= no_of_desc;
7917956Sxiuyan.wang@Sun.COM
7927956Sxiuyan.wang@Sun.COM producer = adapter->cmdProducer;
7937956Sxiuyan.wang@Sun.COM
7947956Sxiuyan.wang@Sun.COM adapter->cmdProducer = get_index_range(adapter->cmdProducer,
7957956Sxiuyan.wang@Sun.COM MaxTxDescCount, no_of_desc);
7967956Sxiuyan.wang@Sun.COM
7977956Sxiuyan.wang@Sun.COM hwdesc = &hw->cmdDescHead[producer];
7987956Sxiuyan.wang@Sun.COM (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
7997956Sxiuyan.wang@Sun.COM pbuf = &adapter->cmd_buf_arr[producer];
8007956Sxiuyan.wang@Sun.COM
8017956Sxiuyan.wang@Sun.COM pbuf->msg = NULL;
8027956Sxiuyan.wang@Sun.COM pbuf->head = NULL;
8037956Sxiuyan.wang@Sun.COM pbuf->tail = NULL;
8047956Sxiuyan.wang@Sun.COM
8057956Sxiuyan.wang@Sun.COM txb = pbuf->dma_area.vaddr;
8067956Sxiuyan.wang@Sun.COM
8077956Sxiuyan.wang@Sun.COM for (bp = mp; bp != NULL; bp = bp->b_cont) {
8087956Sxiuyan.wang@Sun.COM if ((mblen = MBLKL(bp)) == 0)
8097956Sxiuyan.wang@Sun.COM continue;
8107956Sxiuyan.wang@Sun.COM bcopy(bp->b_rptr, txb, mblen);
8117956Sxiuyan.wang@Sun.COM txb += mblen;
8127956Sxiuyan.wang@Sun.COM }
8137956Sxiuyan.wang@Sun.COM
8147956Sxiuyan.wang@Sun.COM /*
8157956Sxiuyan.wang@Sun.COM * Determine metadata if not previously done due to fragmented mblk.
8167956Sxiuyan.wang@Sun.COM */
8177956Sxiuyan.wang@Sun.COM if (pktinfo->etype == 0)
8187956Sxiuyan.wang@Sun.COM unm_update_pkt_info(pbuf->dma_area.vaddr, pktinfo);
8197956Sxiuyan.wang@Sun.COM
8207956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(pbuf->dma_area.dma_hdl,
8217956Sxiuyan.wang@Sun.COM 0, pktinfo->total_len, DDI_DMA_SYNC_FORDEV);
8227956Sxiuyan.wang@Sun.COM
8237956Sxiuyan.wang@Sun.COM /* hwdesc->u1.s1.tcpHdrOffset = 0; */
8247956Sxiuyan.wang@Sun.COM /* hwdesc->mss = 0; */
8257956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.opcode = TX_ETHER_PKT;
8267956Sxiuyan.wang@Sun.COM hwdesc->u3.s1.port = adapter->portnum;
8277956Sxiuyan.wang@Sun.COM hwdesc->u3.s1.ctx_id = adapter->portnum;
8287956Sxiuyan.wang@Sun.COM
8297956Sxiuyan.wang@Sun.COM hwdesc->u6.s1.buffer1Length = pktinfo->total_len;
8307956Sxiuyan.wang@Sun.COM hwdesc->u5.AddrBuffer1 = pbuf->dma_area.dma_addr;
8317956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.numOfBuffers = 1;
8327956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.totalLength = pktinfo->total_len;
8337956Sxiuyan.wang@Sun.COM
8347956Sxiuyan.wang@Sun.COM unm_tx_csum(hwdesc, mp, pktinfo);
8357956Sxiuyan.wang@Sun.COM
8367956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(hw->cmd_desc_dma_handle,
8377956Sxiuyan.wang@Sun.COM producer,
8387956Sxiuyan.wang@Sun.COM no_of_desc,
8397956Sxiuyan.wang@Sun.COM MaxTxDescCount,
8407956Sxiuyan.wang@Sun.COM sizeof (cmdDescType0_t),
8417956Sxiuyan.wang@Sun.COM DDI_DMA_SYNC_FORDEV);
8427956Sxiuyan.wang@Sun.COM
8437956Sxiuyan.wang@Sun.COM hw->cmdProducer = adapter->cmdProducer;
8447956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
8457956Sxiuyan.wang@Sun.COM
8467956Sxiuyan.wang@Sun.COM adapter->stats.txbytes += pktinfo->total_len;
8477956Sxiuyan.wang@Sun.COM adapter->stats.xmitfinished++;
8487956Sxiuyan.wang@Sun.COM adapter->stats.txcopyed++;
8497956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->tx_lock);
8507956Sxiuyan.wang@Sun.COM
8517956Sxiuyan.wang@Sun.COM freemsg(mp);
8527956Sxiuyan.wang@Sun.COM return (B_TRUE);
8537956Sxiuyan.wang@Sun.COM }
8547956Sxiuyan.wang@Sun.COM
8557956Sxiuyan.wang@Sun.COM /* Should be called with adapter->tx_lock held. */
8567956Sxiuyan.wang@Sun.COM static void
unm_return_dma_handle(unm_adapter * adapter,unm_dmah_node_t * head,unm_dmah_node_t * tail,uint32_t num)8577956Sxiuyan.wang@Sun.COM unm_return_dma_handle(unm_adapter *adapter, unm_dmah_node_t *head,
8587956Sxiuyan.wang@Sun.COM unm_dmah_node_t *tail, uint32_t num)
8597956Sxiuyan.wang@Sun.COM {
8607956Sxiuyan.wang@Sun.COM ASSERT(tail != NULL);
8617956Sxiuyan.wang@Sun.COM tail->next = adapter->dmahdl_pool;
8627956Sxiuyan.wang@Sun.COM adapter->dmahdl_pool = head;
8637956Sxiuyan.wang@Sun.COM adapter->freehdls += num;
8647956Sxiuyan.wang@Sun.COM }
8657956Sxiuyan.wang@Sun.COM
8667956Sxiuyan.wang@Sun.COM static unm_dmah_node_t *
unm_reserve_dma_handle(unm_adapter * adapter)8677956Sxiuyan.wang@Sun.COM unm_reserve_dma_handle(unm_adapter* adapter)
8687956Sxiuyan.wang@Sun.COM {
8697956Sxiuyan.wang@Sun.COM unm_dmah_node_t *dmah = NULL;
8707956Sxiuyan.wang@Sun.COM
8717956Sxiuyan.wang@Sun.COM dmah = adapter->dmahdl_pool;
8727956Sxiuyan.wang@Sun.COM if (dmah != NULL) {
8737956Sxiuyan.wang@Sun.COM adapter->dmahdl_pool = dmah->next;
8747956Sxiuyan.wang@Sun.COM dmah->next = NULL;
8757956Sxiuyan.wang@Sun.COM adapter->freehdls--;
8767956Sxiuyan.wang@Sun.COM membar_exit();
8777956Sxiuyan.wang@Sun.COM }
8787956Sxiuyan.wang@Sun.COM
8797956Sxiuyan.wang@Sun.COM return (dmah);
8807956Sxiuyan.wang@Sun.COM }
8817956Sxiuyan.wang@Sun.COM
8827956Sxiuyan.wang@Sun.COM static boolean_t
unm_send_mapped(struct unm_adapter_s * adapter,mblk_t * mp,pktinfo_t * pktinfo)8837956Sxiuyan.wang@Sun.COM unm_send_mapped(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
8847956Sxiuyan.wang@Sun.COM {
8857956Sxiuyan.wang@Sun.COM hardware_context *hw;
8867956Sxiuyan.wang@Sun.COM u32 producer = 0;
8877956Sxiuyan.wang@Sun.COM u32 saved_producer = 0;
8887956Sxiuyan.wang@Sun.COM cmdDescType0_t *hwdesc;
8897956Sxiuyan.wang@Sun.COM struct unm_cmd_buffer *pbuf = NULL;
8907956Sxiuyan.wang@Sun.COM int no_of_desc;
8917956Sxiuyan.wang@Sun.COM int k;
8927956Sxiuyan.wang@Sun.COM int MaxTxDescCount;
8937956Sxiuyan.wang@Sun.COM mblk_t *bp;
8947956Sxiuyan.wang@Sun.COM
8957956Sxiuyan.wang@Sun.COM unm_dmah_node_t *dmah, *head = NULL, *tail = NULL, *hdlp;
8967956Sxiuyan.wang@Sun.COM ddi_dma_cookie_t cookie[MAX_COOKIES_PER_CMD + 1];
8977956Sxiuyan.wang@Sun.COM int ret, i;
8987956Sxiuyan.wang@Sun.COM uint32_t hdl_reserved = 0;
8997956Sxiuyan.wang@Sun.COM uint32_t mblen;
9007956Sxiuyan.wang@Sun.COM uint32_t ncookies, index = 0, total_cookies = 0;
9017956Sxiuyan.wang@Sun.COM
9027956Sxiuyan.wang@Sun.COM MaxTxDescCount = adapter->MaxTxDescCount;
9037956Sxiuyan.wang@Sun.COM
9047956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK(&adapter->tx_lock);
9057956Sxiuyan.wang@Sun.COM
9067956Sxiuyan.wang@Sun.COM /* bind all the mblks of the packet first */
9077956Sxiuyan.wang@Sun.COM for (bp = mp; bp != NULL; bp = bp->b_cont) {
9087956Sxiuyan.wang@Sun.COM mblen = MBLKL(bp);
9097956Sxiuyan.wang@Sun.COM if (mblen == 0)
9107956Sxiuyan.wang@Sun.COM continue;
9117956Sxiuyan.wang@Sun.COM
9127956Sxiuyan.wang@Sun.COM dmah = unm_reserve_dma_handle(adapter);
9137956Sxiuyan.wang@Sun.COM if (dmah == NULL) {
9147956Sxiuyan.wang@Sun.COM adapter->stats.outoftxdmahdl++;
9157956Sxiuyan.wang@Sun.COM goto err_map;
9167956Sxiuyan.wang@Sun.COM }
9177956Sxiuyan.wang@Sun.COM
9187956Sxiuyan.wang@Sun.COM ret = ddi_dma_addr_bind_handle(dmah->dmahdl,
9197956Sxiuyan.wang@Sun.COM NULL, (caddr_t)bp->b_rptr, mblen,
9207956Sxiuyan.wang@Sun.COM DDI_DMA_STREAMING | DDI_DMA_WRITE,
9217956Sxiuyan.wang@Sun.COM DDI_DMA_DONTWAIT, NULL, &cookie[index], &ncookies);
9227956Sxiuyan.wang@Sun.COM
9237956Sxiuyan.wang@Sun.COM if (ret != DDI_DMA_MAPPED)
9247956Sxiuyan.wang@Sun.COM goto err_map;
9257956Sxiuyan.wang@Sun.COM
9267956Sxiuyan.wang@Sun.COM if (tail == NULL) {
9277956Sxiuyan.wang@Sun.COM head = tail = dmah;
9287956Sxiuyan.wang@Sun.COM } else {
9297956Sxiuyan.wang@Sun.COM tail->next = dmah;
9307956Sxiuyan.wang@Sun.COM tail = dmah;
9317956Sxiuyan.wang@Sun.COM }
9327956Sxiuyan.wang@Sun.COM hdl_reserved++;
9337956Sxiuyan.wang@Sun.COM
9347956Sxiuyan.wang@Sun.COM total_cookies += ncookies;
9357956Sxiuyan.wang@Sun.COM if (total_cookies > MAX_COOKIES_PER_CMD) {
9367956Sxiuyan.wang@Sun.COM dmah = NULL;
9377956Sxiuyan.wang@Sun.COM goto err_map;
9387956Sxiuyan.wang@Sun.COM }
9397956Sxiuyan.wang@Sun.COM
9407956Sxiuyan.wang@Sun.COM if (index == 0) {
9417956Sxiuyan.wang@Sun.COM size_t hsize = cookie[0].dmac_size;
9427956Sxiuyan.wang@Sun.COM
9437956Sxiuyan.wang@Sun.COM /*
9447956Sxiuyan.wang@Sun.COM * For TCP/UDP packets with checksum offload,
9457956Sxiuyan.wang@Sun.COM * MAC/IP headers need to be contiguous. Otherwise,
9467956Sxiuyan.wang@Sun.COM * there must be at least 16 bytes in the first
9477956Sxiuyan.wang@Sun.COM * descriptor.
9487956Sxiuyan.wang@Sun.COM */
9497956Sxiuyan.wang@Sun.COM if ((pktinfo->l4_proto == IPPROTO_TCP) ||
9507956Sxiuyan.wang@Sun.COM (pktinfo->l4_proto == IPPROTO_UDP)) {
9517956Sxiuyan.wang@Sun.COM if (hsize < (pktinfo->mac_hlen +
9527956Sxiuyan.wang@Sun.COM pktinfo->ip_hlen)) {
9537956Sxiuyan.wang@Sun.COM dmah = NULL;
9547956Sxiuyan.wang@Sun.COM goto err_map;
9557956Sxiuyan.wang@Sun.COM }
9567956Sxiuyan.wang@Sun.COM } else {
9577956Sxiuyan.wang@Sun.COM if (hsize < 16) {
9587956Sxiuyan.wang@Sun.COM dmah = NULL;
9597956Sxiuyan.wang@Sun.COM goto err_map;
9607956Sxiuyan.wang@Sun.COM }
9617956Sxiuyan.wang@Sun.COM }
9627956Sxiuyan.wang@Sun.COM }
9637956Sxiuyan.wang@Sun.COM
9647956Sxiuyan.wang@Sun.COM index++;
9657956Sxiuyan.wang@Sun.COM ncookies--;
9667956Sxiuyan.wang@Sun.COM for (i = 0; i < ncookies; i++, index++)
9677956Sxiuyan.wang@Sun.COM ddi_dma_nextcookie(dmah->dmahdl, &cookie[index]);
9687956Sxiuyan.wang@Sun.COM }
9697956Sxiuyan.wang@Sun.COM
9707956Sxiuyan.wang@Sun.COM dmah = NULL;
9717956Sxiuyan.wang@Sun.COM hw = &adapter->ahw;
9727956Sxiuyan.wang@Sun.COM no_of_desc = (total_cookies + 3) >> 2;
9737956Sxiuyan.wang@Sun.COM
9747956Sxiuyan.wang@Sun.COM membar_enter();
9757956Sxiuyan.wang@Sun.COM if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
9767956Sxiuyan.wang@Sun.COM MaxTxDescCount) < no_of_desc+2) {
9777956Sxiuyan.wang@Sun.COM /*
9787956Sxiuyan.wang@Sun.COM * If we are going to be trying the copy path, no point
9797956Sxiuyan.wang@Sun.COM * scheduling an upcall when Tx resources are freed.
9807956Sxiuyan.wang@Sun.COM */
9817956Sxiuyan.wang@Sun.COM if (pktinfo->total_len > adapter->maxmtu) {
9827956Sxiuyan.wang@Sun.COM adapter->stats.outofcmddesc++;
9837956Sxiuyan.wang@Sun.COM adapter->resched_needed = 1;
9847956Sxiuyan.wang@Sun.COM }
9857956Sxiuyan.wang@Sun.COM membar_exit();
9867956Sxiuyan.wang@Sun.COM goto err_alloc_desc;
9877956Sxiuyan.wang@Sun.COM }
9887956Sxiuyan.wang@Sun.COM adapter->freecmds -= no_of_desc;
9897956Sxiuyan.wang@Sun.COM
9907956Sxiuyan.wang@Sun.COM /* Copy the descriptors into the hardware */
9917956Sxiuyan.wang@Sun.COM producer = adapter->cmdProducer;
9927956Sxiuyan.wang@Sun.COM saved_producer = producer;
9937956Sxiuyan.wang@Sun.COM hwdesc = &hw->cmdDescHead[producer];
9947956Sxiuyan.wang@Sun.COM (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
9957956Sxiuyan.wang@Sun.COM pbuf = &adapter->cmd_buf_arr[producer];
9967956Sxiuyan.wang@Sun.COM
9977956Sxiuyan.wang@Sun.COM pbuf->msg = mp;
9987956Sxiuyan.wang@Sun.COM pbuf->head = head;
9997956Sxiuyan.wang@Sun.COM pbuf->tail = tail;
10007956Sxiuyan.wang@Sun.COM
10017956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.numOfBuffers = total_cookies;
10027956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.opcode = TX_ETHER_PKT;
10037956Sxiuyan.wang@Sun.COM hwdesc->u3.s1.port = adapter->portnum;
10047956Sxiuyan.wang@Sun.COM /* hwdesc->u1.s1.tcpHdrOffset = 0; */
10057956Sxiuyan.wang@Sun.COM /* hwdesc->mss = 0; */
10067956Sxiuyan.wang@Sun.COM hwdesc->u3.s1.ctx_id = adapter->portnum;
10077956Sxiuyan.wang@Sun.COM hwdesc->u1.s1.totalLength = pktinfo->total_len;
10087956Sxiuyan.wang@Sun.COM unm_tx_csum(hwdesc, mp, pktinfo);
10097956Sxiuyan.wang@Sun.COM
10107956Sxiuyan.wang@Sun.COM for (i = k = 0; i < total_cookies; i++) {
10117956Sxiuyan.wang@Sun.COM if (k == 4) {
10127956Sxiuyan.wang@Sun.COM /* Move to the next descriptor */
10137956Sxiuyan.wang@Sun.COM k = 0;
10147956Sxiuyan.wang@Sun.COM producer = get_next_index(producer, MaxTxDescCount);
10157956Sxiuyan.wang@Sun.COM hwdesc = &hw->cmdDescHead[producer];
10167956Sxiuyan.wang@Sun.COM (void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
10177956Sxiuyan.wang@Sun.COM }
10187956Sxiuyan.wang@Sun.COM
10197956Sxiuyan.wang@Sun.COM switch (k) {
10207956Sxiuyan.wang@Sun.COM case 0:
10217956Sxiuyan.wang@Sun.COM hwdesc->u6.s1.buffer1Length = cookie[i].dmac_size;
10227956Sxiuyan.wang@Sun.COM hwdesc->u5.AddrBuffer1 = cookie[i].dmac_laddress;
10237956Sxiuyan.wang@Sun.COM break;
10247956Sxiuyan.wang@Sun.COM case 1:
10257956Sxiuyan.wang@Sun.COM hwdesc->u6.s1.buffer2Length = cookie[i].dmac_size;
10267956Sxiuyan.wang@Sun.COM hwdesc->u2.AddrBuffer2 = cookie[i].dmac_laddress;
10277956Sxiuyan.wang@Sun.COM break;
10287956Sxiuyan.wang@Sun.COM case 2:
10297956Sxiuyan.wang@Sun.COM hwdesc->u6.s1.buffer3Length = cookie[i].dmac_size;
10307956Sxiuyan.wang@Sun.COM hwdesc->u4.AddrBuffer3 = cookie[i].dmac_laddress;
10317956Sxiuyan.wang@Sun.COM break;
10327956Sxiuyan.wang@Sun.COM case 3:
10337956Sxiuyan.wang@Sun.COM hwdesc->u6.s1.buffer4Length = cookie[i].dmac_size;
10347956Sxiuyan.wang@Sun.COM hwdesc->u7.AddrBuffer4 = cookie[i].dmac_laddress;
10357956Sxiuyan.wang@Sun.COM break;
10367956Sxiuyan.wang@Sun.COM }
10377956Sxiuyan.wang@Sun.COM k++;
10387956Sxiuyan.wang@Sun.COM }
10397956Sxiuyan.wang@Sun.COM
10407956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(hw->cmd_desc_dma_handle, saved_producer, no_of_desc,
10417956Sxiuyan.wang@Sun.COM MaxTxDescCount, sizeof (cmdDescType0_t), DDI_DMA_SYNC_FORDEV);
10427956Sxiuyan.wang@Sun.COM
10437956Sxiuyan.wang@Sun.COM adapter->cmdProducer = get_next_index(producer, MaxTxDescCount);
10447956Sxiuyan.wang@Sun.COM hw->cmdProducer = adapter->cmdProducer;
10457956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
10467956Sxiuyan.wang@Sun.COM
10477956Sxiuyan.wang@Sun.COM adapter->stats.txbytes += pktinfo->total_len;
10487956Sxiuyan.wang@Sun.COM adapter->stats.xmitfinished++;
10497956Sxiuyan.wang@Sun.COM adapter->stats.txmapped++;
10507956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->tx_lock);
10517956Sxiuyan.wang@Sun.COM return (B_TRUE);
10527956Sxiuyan.wang@Sun.COM
10537956Sxiuyan.wang@Sun.COM err_alloc_desc:
10547956Sxiuyan.wang@Sun.COM err_map:
10557956Sxiuyan.wang@Sun.COM
10567956Sxiuyan.wang@Sun.COM hdlp = head;
10577956Sxiuyan.wang@Sun.COM while (hdlp != NULL) {
10587956Sxiuyan.wang@Sun.COM (void) ddi_dma_unbind_handle(hdlp->dmahdl);
10597956Sxiuyan.wang@Sun.COM hdlp = hdlp->next;
10607956Sxiuyan.wang@Sun.COM }
10617956Sxiuyan.wang@Sun.COM
10627956Sxiuyan.wang@Sun.COM /*
10637956Sxiuyan.wang@Sun.COM * add the reserved but bind failed one to the list to be returned
10647956Sxiuyan.wang@Sun.COM */
10657956Sxiuyan.wang@Sun.COM if (dmah != NULL) {
10667956Sxiuyan.wang@Sun.COM if (tail == NULL)
10677956Sxiuyan.wang@Sun.COM head = tail = dmah;
10687956Sxiuyan.wang@Sun.COM else {
10697956Sxiuyan.wang@Sun.COM tail->next = dmah;
10707956Sxiuyan.wang@Sun.COM tail = dmah;
10717956Sxiuyan.wang@Sun.COM }
10727956Sxiuyan.wang@Sun.COM hdl_reserved++;
10737956Sxiuyan.wang@Sun.COM }
10747956Sxiuyan.wang@Sun.COM
10757956Sxiuyan.wang@Sun.COM if (head != NULL)
10767956Sxiuyan.wang@Sun.COM unm_return_dma_handle(adapter, head, tail, hdl_reserved);
10777956Sxiuyan.wang@Sun.COM
10787956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->tx_lock);
10797956Sxiuyan.wang@Sun.COM return (B_FALSE);
10807956Sxiuyan.wang@Sun.COM }
10817956Sxiuyan.wang@Sun.COM
10827956Sxiuyan.wang@Sun.COM static boolean_t
unm_nic_xmit_frame(unm_adapter * adapter,mblk_t * mp)10837956Sxiuyan.wang@Sun.COM unm_nic_xmit_frame(unm_adapter *adapter, mblk_t *mp)
10847956Sxiuyan.wang@Sun.COM {
10857956Sxiuyan.wang@Sun.COM pktinfo_t pktinfo;
10867956Sxiuyan.wang@Sun.COM boolean_t status = B_FALSE, send_mapped;
10877956Sxiuyan.wang@Sun.COM
10887956Sxiuyan.wang@Sun.COM adapter->stats.xmitcalled++;
10897956Sxiuyan.wang@Sun.COM
10907956Sxiuyan.wang@Sun.COM send_mapped = unm_get_pkt_info(mp, &pktinfo);
10917956Sxiuyan.wang@Sun.COM
10927956Sxiuyan.wang@Sun.COM if (pktinfo.total_len <= adapter->tx_bcopy_threshold ||
10939436SJing.Xiong@Sun.COM pktinfo.mblk_no >= MAX_COOKIES_PER_CMD)
10947956Sxiuyan.wang@Sun.COM send_mapped = B_FALSE;
10957956Sxiuyan.wang@Sun.COM
10967956Sxiuyan.wang@Sun.COM if (send_mapped == B_TRUE)
10977956Sxiuyan.wang@Sun.COM status = unm_send_mapped(adapter, mp, &pktinfo);
10987956Sxiuyan.wang@Sun.COM
10997956Sxiuyan.wang@Sun.COM if (status != B_TRUE) {
11007956Sxiuyan.wang@Sun.COM if (pktinfo.total_len <= adapter->maxmtu)
11017956Sxiuyan.wang@Sun.COM return (unm_send_copy(adapter, mp, &pktinfo));
11027956Sxiuyan.wang@Sun.COM
11037956Sxiuyan.wang@Sun.COM /* message too large */
11047956Sxiuyan.wang@Sun.COM freemsg(mp);
11057956Sxiuyan.wang@Sun.COM adapter->stats.txdropped++;
11067956Sxiuyan.wang@Sun.COM status = B_TRUE;
11077956Sxiuyan.wang@Sun.COM }
11087956Sxiuyan.wang@Sun.COM
11097956Sxiuyan.wang@Sun.COM return (status);
11107956Sxiuyan.wang@Sun.COM }
11117956Sxiuyan.wang@Sun.COM
11127956Sxiuyan.wang@Sun.COM static int
unm_nic_check_temp(struct unm_adapter_s * adapter)11137956Sxiuyan.wang@Sun.COM unm_nic_check_temp(struct unm_adapter_s *adapter)
11147956Sxiuyan.wang@Sun.COM {
11157956Sxiuyan.wang@Sun.COM uint32_t temp, temp_state, temp_val;
11167956Sxiuyan.wang@Sun.COM int rv = 0;
11177956Sxiuyan.wang@Sun.COM
11187956Sxiuyan.wang@Sun.COM if ((adapter->ahw.revision_id == NX_P3_A2) ||
11197956Sxiuyan.wang@Sun.COM (adapter->ahw.revision_id == NX_P3_A0))
11207956Sxiuyan.wang@Sun.COM return (0);
11217956Sxiuyan.wang@Sun.COM
11227956Sxiuyan.wang@Sun.COM temp = adapter->unm_nic_pci_read_normalize(adapter, CRB_TEMP_STATE);
11237956Sxiuyan.wang@Sun.COM
11247956Sxiuyan.wang@Sun.COM temp_state = nx_get_temp_state(temp);
11257956Sxiuyan.wang@Sun.COM temp_val = nx_get_temp_val(temp);
11267956Sxiuyan.wang@Sun.COM
11277956Sxiuyan.wang@Sun.COM if (temp_state == NX_TEMP_PANIC) {
11287956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s: Device temperature %d C exceeds "
11297956Sxiuyan.wang@Sun.COM "maximum allowed, device has been shut down\n",
11307956Sxiuyan.wang@Sun.COM unm_nic_driver_name, temp_val);
11317956Sxiuyan.wang@Sun.COM rv = 1;
11327956Sxiuyan.wang@Sun.COM } else if (temp_state == NX_TEMP_WARN) {
11337956Sxiuyan.wang@Sun.COM if (adapter->temp == NX_TEMP_NORMAL) {
11347956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s: Device temperature %d C exceeds"
11357956Sxiuyan.wang@Sun.COM "operating range. Immediate action needed.\n",
11367956Sxiuyan.wang@Sun.COM unm_nic_driver_name, temp_val);
11377956Sxiuyan.wang@Sun.COM }
11387956Sxiuyan.wang@Sun.COM } else {
11397956Sxiuyan.wang@Sun.COM if (adapter->temp == NX_TEMP_WARN) {
11407956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s: Device temperature is now %d "
11417956Sxiuyan.wang@Sun.COM "degrees C in normal range.\n",
11427956Sxiuyan.wang@Sun.COM unm_nic_driver_name, temp_val);
11437956Sxiuyan.wang@Sun.COM }
11447956Sxiuyan.wang@Sun.COM }
11457956Sxiuyan.wang@Sun.COM
11467956Sxiuyan.wang@Sun.COM adapter->temp = temp_state;
11477956Sxiuyan.wang@Sun.COM return (rv);
11487956Sxiuyan.wang@Sun.COM }
11497956Sxiuyan.wang@Sun.COM
11507956Sxiuyan.wang@Sun.COM static void
unm_watchdog(unsigned long v)11517956Sxiuyan.wang@Sun.COM unm_watchdog(unsigned long v)
11527956Sxiuyan.wang@Sun.COM {
11537956Sxiuyan.wang@Sun.COM unm_adapter *adapter = (unm_adapter *)v;
11547956Sxiuyan.wang@Sun.COM
11557956Sxiuyan.wang@Sun.COM if ((adapter->portnum == 0) && unm_nic_check_temp(adapter)) {
11567956Sxiuyan.wang@Sun.COM /*
11577956Sxiuyan.wang@Sun.COM * We return without turning on the netdev queue as there
11587956Sxiuyan.wang@Sun.COM * was an overheated device
11597956Sxiuyan.wang@Sun.COM */
11607956Sxiuyan.wang@Sun.COM return;
11617956Sxiuyan.wang@Sun.COM }
11627956Sxiuyan.wang@Sun.COM
11637956Sxiuyan.wang@Sun.COM unm_nic_handle_phy_intr(adapter);
11647956Sxiuyan.wang@Sun.COM
11657956Sxiuyan.wang@Sun.COM /*
11667956Sxiuyan.wang@Sun.COM * This function schedules a call for itself.
11677956Sxiuyan.wang@Sun.COM */
11687956Sxiuyan.wang@Sun.COM adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
11697956Sxiuyan.wang@Sun.COM (void *)adapter, 2 * drv_usectohz(1000000));
11707956Sxiuyan.wang@Sun.COM
11717956Sxiuyan.wang@Sun.COM }
11727956Sxiuyan.wang@Sun.COM
unm_nic_clear_stats(unm_adapter * adapter)11737956Sxiuyan.wang@Sun.COM static void unm_nic_clear_stats(unm_adapter *adapter)
11747956Sxiuyan.wang@Sun.COM {
11757956Sxiuyan.wang@Sun.COM (void) memset(&adapter->stats, 0, sizeof (adapter->stats));
11767956Sxiuyan.wang@Sun.COM }
11777956Sxiuyan.wang@Sun.COM
11787956Sxiuyan.wang@Sun.COM static void
unm_nic_poll(unm_adapter * adapter)11797956Sxiuyan.wang@Sun.COM unm_nic_poll(unm_adapter *adapter)
11807956Sxiuyan.wang@Sun.COM {
11817956Sxiuyan.wang@Sun.COM int work_done, tx_complete;
11827956Sxiuyan.wang@Sun.COM
11837956Sxiuyan.wang@Sun.COM adapter->stats.polled++;
11847956Sxiuyan.wang@Sun.COM
11857956Sxiuyan.wang@Sun.COM loop:
11867956Sxiuyan.wang@Sun.COM tx_complete = unm_process_cmd_ring(adapter);
11877956Sxiuyan.wang@Sun.COM work_done = unm_process_rcv_ring(adapter, NX_RX_MAXBUFS);
11887956Sxiuyan.wang@Sun.COM if ((!tx_complete) || (!(work_done < NX_RX_MAXBUFS)))
11897956Sxiuyan.wang@Sun.COM goto loop;
11907956Sxiuyan.wang@Sun.COM
11917956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
11927956Sxiuyan.wang@Sun.COM unm_nic_enable_int(adapter);
11937956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
11947956Sxiuyan.wang@Sun.COM }
11957956Sxiuyan.wang@Sun.COM
11967956Sxiuyan.wang@Sun.COM /* ARGSUSED */
11977956Sxiuyan.wang@Sun.COM uint_t
unm_intr(caddr_t data,caddr_t arg)11987956Sxiuyan.wang@Sun.COM unm_intr(caddr_t data, caddr_t arg)
11997956Sxiuyan.wang@Sun.COM {
12007956Sxiuyan.wang@Sun.COM unm_adapter *adapter = (unm_adapter *)(uintptr_t)data;
12017956Sxiuyan.wang@Sun.COM
12027956Sxiuyan.wang@Sun.COM if (unm_nic_clear_int(adapter))
12037956Sxiuyan.wang@Sun.COM return (DDI_INTR_UNCLAIMED);
12047956Sxiuyan.wang@Sun.COM
12057956Sxiuyan.wang@Sun.COM unm_nic_poll(adapter);
12067956Sxiuyan.wang@Sun.COM return (DDI_INTR_CLAIMED);
12077956Sxiuyan.wang@Sun.COM }
12087956Sxiuyan.wang@Sun.COM
12097956Sxiuyan.wang@Sun.COM /*
12107956Sxiuyan.wang@Sun.COM * This is invoked from receive isr. Due to the single threaded nature
12117956Sxiuyan.wang@Sun.COM * of the invocation, pool_lock acquisition is not neccesary to protect
12127956Sxiuyan.wang@Sun.COM * pool_list.
12137956Sxiuyan.wang@Sun.COM */
12147956Sxiuyan.wang@Sun.COM static void
unm_free_rx_buffer(unm_rcv_desc_ctx_t * rcv_desc,unm_rx_buffer_t * rx_buffer)12157956Sxiuyan.wang@Sun.COM unm_free_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc, unm_rx_buffer_t *rx_buffer)
12167956Sxiuyan.wang@Sun.COM {
12177956Sxiuyan.wang@Sun.COM /* mutex_enter(rcv_desc->pool_lock); */
12187956Sxiuyan.wang@Sun.COM rx_buffer->next = rcv_desc->pool_list;
12197956Sxiuyan.wang@Sun.COM rcv_desc->pool_list = rx_buffer;
12207956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_free++;
12217956Sxiuyan.wang@Sun.COM /* mutex_exit(rcv_desc->pool_lock); */
12227956Sxiuyan.wang@Sun.COM }
12237956Sxiuyan.wang@Sun.COM
12247956Sxiuyan.wang@Sun.COM /*
12257956Sxiuyan.wang@Sun.COM * unm_process_rcv() send the received packet to the protocol stack.
12267956Sxiuyan.wang@Sun.COM */
12277956Sxiuyan.wang@Sun.COM static mblk_t *
unm_process_rcv(unm_adapter * adapter,statusDesc_t * desc)12287956Sxiuyan.wang@Sun.COM unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc)
12297956Sxiuyan.wang@Sun.COM {
12307956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
12317956Sxiuyan.wang@Sun.COM unm_rx_buffer_t *rx_buffer;
12327956Sxiuyan.wang@Sun.COM mblk_t *mp;
12337956Sxiuyan.wang@Sun.COM u32 desc_ctx = desc->u1.s1.type;
12347956Sxiuyan.wang@Sun.COM unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[desc_ctx];
12357956Sxiuyan.wang@Sun.COM u32 pkt_length = desc->u1.s1.totalLength;
12367956Sxiuyan.wang@Sun.COM int poff = desc->u1.s1.pkt_offset;
12377956Sxiuyan.wang@Sun.COM int index, cksum_flags, docopy;
12387956Sxiuyan.wang@Sun.COM int index_lo = desc->u1.s1.referenceHandle_lo;
12397956Sxiuyan.wang@Sun.COM char *vaddr;
12407956Sxiuyan.wang@Sun.COM
12417956Sxiuyan.wang@Sun.COM index = ((desc->u1.s1.referenceHandle_hi << 4) | index_lo);
12427956Sxiuyan.wang@Sun.COM
12437956Sxiuyan.wang@Sun.COM rx_buffer = index2rxbuf(rcv_desc, index);
12447956Sxiuyan.wang@Sun.COM
12457956Sxiuyan.wang@Sun.COM if (rx_buffer == NULL) {
12467956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "\r\nNULL rx_buffer idx=%d", index);
12477956Sxiuyan.wang@Sun.COM return (NULL);
12487956Sxiuyan.wang@Sun.COM }
12497956Sxiuyan.wang@Sun.COM vaddr = (char *)rx_buffer->dma_info.vaddr;
12507956Sxiuyan.wang@Sun.COM if (vaddr == NULL) {
12517956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "\r\nNULL vaddr");
12527956Sxiuyan.wang@Sun.COM return (NULL);
12537956Sxiuyan.wang@Sun.COM }
12547956Sxiuyan.wang@Sun.COM rcv_desc->rx_desc_handled++;
12557956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_card--;
12567956Sxiuyan.wang@Sun.COM
12577956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(rx_buffer->dma_info.dma_hdl, 0,
12587956Sxiuyan.wang@Sun.COM pkt_length + poff + (adapter->ahw.cut_through ? 0 :
12597956Sxiuyan.wang@Sun.COM IP_ALIGNMENT_BYTES), DDI_DMA_SYNC_FORCPU);
12607956Sxiuyan.wang@Sun.COM
12617956Sxiuyan.wang@Sun.COM /*
12627956Sxiuyan.wang@Sun.COM * Copy packet into new allocated message buffer, if pkt_length
12637956Sxiuyan.wang@Sun.COM * is below copy threshold.
12647956Sxiuyan.wang@Sun.COM */
12657956Sxiuyan.wang@Sun.COM docopy = (pkt_length <= adapter->rx_bcopy_threshold) ? 1 : 0;
12667956Sxiuyan.wang@Sun.COM
12677956Sxiuyan.wang@Sun.COM /*
12687956Sxiuyan.wang@Sun.COM * If card is running out of rx buffers, then attempt to allocate
12697956Sxiuyan.wang@Sun.COM * new mblk so we can feed this rx buffer back to card (we
12707956Sxiuyan.wang@Sun.COM * _could_ look at what's pending on free and recycle lists).
12717956Sxiuyan.wang@Sun.COM */
12727956Sxiuyan.wang@Sun.COM if (rcv_desc->rx_buf_card < NX_RX_THRESHOLD) {
12737956Sxiuyan.wang@Sun.COM docopy = 1;
12747956Sxiuyan.wang@Sun.COM adapter->stats.rxbufshort++;
12757956Sxiuyan.wang@Sun.COM }
12767956Sxiuyan.wang@Sun.COM
12777956Sxiuyan.wang@Sun.COM if (docopy == 1) {
12787956Sxiuyan.wang@Sun.COM if ((mp = allocb(pkt_length + IP_ALIGNMENT_BYTES, 0)) == NULL) {
12797956Sxiuyan.wang@Sun.COM adapter->stats.allocbfailed++;
12807956Sxiuyan.wang@Sun.COM goto freebuf;
12817956Sxiuyan.wang@Sun.COM }
12827956Sxiuyan.wang@Sun.COM
12837956Sxiuyan.wang@Sun.COM mp->b_rptr += IP_ALIGNMENT_BYTES;
12847956Sxiuyan.wang@Sun.COM vaddr += poff;
12857956Sxiuyan.wang@Sun.COM bcopy(vaddr, mp->b_rptr, pkt_length);
12867956Sxiuyan.wang@Sun.COM adapter->stats.rxcopyed++;
12877956Sxiuyan.wang@Sun.COM unm_free_rx_buffer(rcv_desc, rx_buffer);
12887956Sxiuyan.wang@Sun.COM } else {
12897956Sxiuyan.wang@Sun.COM mp = (mblk_t *)rx_buffer->mp;
12907956Sxiuyan.wang@Sun.COM if (mp == NULL) {
12917956Sxiuyan.wang@Sun.COM mp = desballoc(rx_buffer->dma_info.vaddr,
12927956Sxiuyan.wang@Sun.COM rcv_desc->dma_size, 0, &rx_buffer->rx_recycle);
12937956Sxiuyan.wang@Sun.COM if (mp == NULL) {
12947956Sxiuyan.wang@Sun.COM adapter->stats.desballocfailed++;
12957956Sxiuyan.wang@Sun.COM goto freebuf;
12967956Sxiuyan.wang@Sun.COM }
12977956Sxiuyan.wang@Sun.COM rx_buffer->mp = mp;
12987956Sxiuyan.wang@Sun.COM }
12997956Sxiuyan.wang@Sun.COM mp->b_rptr += poff;
13007956Sxiuyan.wang@Sun.COM adapter->stats.rxmapped++;
13017956Sxiuyan.wang@Sun.COM }
13027956Sxiuyan.wang@Sun.COM
13037956Sxiuyan.wang@Sun.COM mp->b_wptr = (uchar_t *)((unsigned long)mp->b_rptr + pkt_length);
13047956Sxiuyan.wang@Sun.COM
13057956Sxiuyan.wang@Sun.COM if (desc->u1.s1.status == STATUS_CKSUM_OK) {
13067956Sxiuyan.wang@Sun.COM adapter->stats.csummed++;
13077956Sxiuyan.wang@Sun.COM cksum_flags =
1308*11878SVenu.Iyer@Sun.COM HCK_FULLCKSUM_OK | HCK_IPV4_HDRCKSUM_OK;
13097956Sxiuyan.wang@Sun.COM } else {
13107956Sxiuyan.wang@Sun.COM cksum_flags = 0;
13117956Sxiuyan.wang@Sun.COM }
1312*11878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
13137956Sxiuyan.wang@Sun.COM
13147956Sxiuyan.wang@Sun.COM adapter->stats.no_rcv++;
13157956Sxiuyan.wang@Sun.COM adapter->stats.rxbytes += pkt_length;
13167956Sxiuyan.wang@Sun.COM adapter->stats.uphappy++;
13177956Sxiuyan.wang@Sun.COM
13187956Sxiuyan.wang@Sun.COM return (mp);
13197956Sxiuyan.wang@Sun.COM
13207956Sxiuyan.wang@Sun.COM freebuf:
13217956Sxiuyan.wang@Sun.COM unm_free_rx_buffer(rcv_desc, rx_buffer);
13227956Sxiuyan.wang@Sun.COM return (NULL);
13237956Sxiuyan.wang@Sun.COM }
13247956Sxiuyan.wang@Sun.COM
13257956Sxiuyan.wang@Sun.COM /* Process Receive status ring */
13267956Sxiuyan.wang@Sun.COM static int
unm_process_rcv_ring(unm_adapter * adapter,int max)13277956Sxiuyan.wang@Sun.COM unm_process_rcv_ring(unm_adapter *adapter, int max)
13287956Sxiuyan.wang@Sun.COM {
13297956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
13307956Sxiuyan.wang@Sun.COM statusDesc_t *desc_head = recv_ctx->rcvStatusDescHead;
13317956Sxiuyan.wang@Sun.COM statusDesc_t *desc = NULL;
13327956Sxiuyan.wang@Sun.COM uint32_t consumer, start;
13337956Sxiuyan.wang@Sun.COM int count = 0, ring;
13347956Sxiuyan.wang@Sun.COM mblk_t *mp;
13357956Sxiuyan.wang@Sun.COM
13367956Sxiuyan.wang@Sun.COM start = consumer = recv_ctx->statusRxConsumer;
13377956Sxiuyan.wang@Sun.COM
13387956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start, max,
13397956Sxiuyan.wang@Sun.COM adapter->MaxRxDescCount, sizeof (statusDesc_t),
13407956Sxiuyan.wang@Sun.COM DDI_DMA_SYNC_FORCPU);
13417956Sxiuyan.wang@Sun.COM
13427956Sxiuyan.wang@Sun.COM while (count < max) {
13437956Sxiuyan.wang@Sun.COM desc = &desc_head[consumer];
13447956Sxiuyan.wang@Sun.COM if (!(desc->u1.s1.owner & STATUS_OWNER_HOST))
13457956Sxiuyan.wang@Sun.COM break;
13467956Sxiuyan.wang@Sun.COM
13477956Sxiuyan.wang@Sun.COM mp = unm_process_rcv(adapter, desc);
13487956Sxiuyan.wang@Sun.COM desc->u1.s1.owner = STATUS_OWNER_PHANTOM;
13497956Sxiuyan.wang@Sun.COM
13507956Sxiuyan.wang@Sun.COM consumer = (consumer + 1) % adapter->MaxRxDescCount;
13517956Sxiuyan.wang@Sun.COM count++;
13527956Sxiuyan.wang@Sun.COM if (mp != NULL)
13537956Sxiuyan.wang@Sun.COM mac_rx(adapter->mach, NULL, mp);
13547956Sxiuyan.wang@Sun.COM }
13557956Sxiuyan.wang@Sun.COM
13567956Sxiuyan.wang@Sun.COM for (ring = 0; ring < adapter->max_rds_rings; ring++) {
13577956Sxiuyan.wang@Sun.COM if (recv_ctx->rcv_desc[ring].rx_desc_handled > 0)
13587956Sxiuyan.wang@Sun.COM unm_post_rx_buffers_nodb(adapter, ring);
13597956Sxiuyan.wang@Sun.COM }
13607956Sxiuyan.wang@Sun.COM
13617956Sxiuyan.wang@Sun.COM if (count) {
13627956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start,
13637956Sxiuyan.wang@Sun.COM count, adapter->MaxRxDescCount, sizeof (statusDesc_t),
13647956Sxiuyan.wang@Sun.COM DDI_DMA_SYNC_FORDEV);
13657956Sxiuyan.wang@Sun.COM
13667956Sxiuyan.wang@Sun.COM /* update the consumer index in phantom */
13677956Sxiuyan.wang@Sun.COM recv_ctx->statusRxConsumer = consumer;
13687956Sxiuyan.wang@Sun.COM
13697956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
13707956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter,
13717956Sxiuyan.wang@Sun.COM recv_ctx->host_sds_consumer, &consumer, 4);
13727956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
13737956Sxiuyan.wang@Sun.COM }
13747956Sxiuyan.wang@Sun.COM
13757956Sxiuyan.wang@Sun.COM return (count);
13767956Sxiuyan.wang@Sun.COM }
13777956Sxiuyan.wang@Sun.COM
13787956Sxiuyan.wang@Sun.COM /* Process Command status ring */
13797956Sxiuyan.wang@Sun.COM static int
unm_process_cmd_ring(struct unm_adapter_s * adapter)13807956Sxiuyan.wang@Sun.COM unm_process_cmd_ring(struct unm_adapter_s *adapter)
13817956Sxiuyan.wang@Sun.COM {
13827956Sxiuyan.wang@Sun.COM u32 last_consumer;
13837956Sxiuyan.wang@Sun.COM u32 consumer;
13847956Sxiuyan.wang@Sun.COM int count = 0;
13857956Sxiuyan.wang@Sun.COM struct unm_cmd_buffer *buffer;
13867956Sxiuyan.wang@Sun.COM int done;
13877956Sxiuyan.wang@Sun.COM unm_dmah_node_t *dmah, *head = NULL, *tail = NULL;
13887956Sxiuyan.wang@Sun.COM uint32_t free_hdls = 0;
13897956Sxiuyan.wang@Sun.COM
13907956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
13917956Sxiuyan.wang@Sun.COM sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
13927956Sxiuyan.wang@Sun.COM
13937956Sxiuyan.wang@Sun.COM last_consumer = adapter->lastCmdConsumer;
13947956Sxiuyan.wang@Sun.COM consumer = *(adapter->cmdConsumer);
13957956Sxiuyan.wang@Sun.COM
13967956Sxiuyan.wang@Sun.COM while (last_consumer != consumer) {
13977956Sxiuyan.wang@Sun.COM buffer = &adapter->cmd_buf_arr[last_consumer];
13987956Sxiuyan.wang@Sun.COM if (buffer->head != NULL) {
13997956Sxiuyan.wang@Sun.COM dmah = buffer->head;
14007956Sxiuyan.wang@Sun.COM while (dmah != NULL) {
14017956Sxiuyan.wang@Sun.COM (void) ddi_dma_unbind_handle(dmah->dmahdl);
14027956Sxiuyan.wang@Sun.COM dmah = dmah->next;
14037956Sxiuyan.wang@Sun.COM free_hdls++;
14047956Sxiuyan.wang@Sun.COM }
14057956Sxiuyan.wang@Sun.COM
14067956Sxiuyan.wang@Sun.COM if (head == NULL) {
14077956Sxiuyan.wang@Sun.COM head = buffer->head;
14087956Sxiuyan.wang@Sun.COM tail = buffer->tail;
14097956Sxiuyan.wang@Sun.COM } else {
14107956Sxiuyan.wang@Sun.COM tail->next = buffer->head;
14117956Sxiuyan.wang@Sun.COM tail = buffer->tail;
14127956Sxiuyan.wang@Sun.COM }
14137956Sxiuyan.wang@Sun.COM
14147956Sxiuyan.wang@Sun.COM buffer->head = NULL;
14157956Sxiuyan.wang@Sun.COM buffer->tail = NULL;
14167956Sxiuyan.wang@Sun.COM
14177956Sxiuyan.wang@Sun.COM if (buffer->msg != NULL) {
14187956Sxiuyan.wang@Sun.COM freemsg(buffer->msg);
14197956Sxiuyan.wang@Sun.COM buffer->msg = NULL;
14207956Sxiuyan.wang@Sun.COM }
14217956Sxiuyan.wang@Sun.COM }
14227956Sxiuyan.wang@Sun.COM
14237956Sxiuyan.wang@Sun.COM last_consumer = get_next_index(last_consumer,
14247956Sxiuyan.wang@Sun.COM adapter->MaxTxDescCount);
14257956Sxiuyan.wang@Sun.COM if (++count > NX_MAX_TXCOMPS)
14267956Sxiuyan.wang@Sun.COM break;
14277956Sxiuyan.wang@Sun.COM }
14287956Sxiuyan.wang@Sun.COM
14297956Sxiuyan.wang@Sun.COM if (count) {
14307956Sxiuyan.wang@Sun.COM int doresched;
14317956Sxiuyan.wang@Sun.COM
14327956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK(&adapter->tx_lock);
14337956Sxiuyan.wang@Sun.COM adapter->lastCmdConsumer = last_consumer;
14347956Sxiuyan.wang@Sun.COM adapter->freecmds += count;
14357956Sxiuyan.wang@Sun.COM membar_exit();
14367956Sxiuyan.wang@Sun.COM
14377956Sxiuyan.wang@Sun.COM doresched = adapter->resched_needed;
14387956Sxiuyan.wang@Sun.COM if (doresched)
14397956Sxiuyan.wang@Sun.COM adapter->resched_needed = 0;
14407956Sxiuyan.wang@Sun.COM
14417956Sxiuyan.wang@Sun.COM if (head != NULL)
14427956Sxiuyan.wang@Sun.COM unm_return_dma_handle(adapter, head, tail, free_hdls);
14437956Sxiuyan.wang@Sun.COM
14447956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->tx_lock);
14457956Sxiuyan.wang@Sun.COM
14467956Sxiuyan.wang@Sun.COM if (doresched)
14477956Sxiuyan.wang@Sun.COM mac_tx_update(adapter->mach);
14487956Sxiuyan.wang@Sun.COM }
14497956Sxiuyan.wang@Sun.COM
14507956Sxiuyan.wang@Sun.COM (void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
14517956Sxiuyan.wang@Sun.COM sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
14527956Sxiuyan.wang@Sun.COM
14537956Sxiuyan.wang@Sun.COM consumer = *(adapter->cmdConsumer);
14547956Sxiuyan.wang@Sun.COM done = (adapter->lastCmdConsumer == consumer);
14557956Sxiuyan.wang@Sun.COM
14567956Sxiuyan.wang@Sun.COM return (done);
14577956Sxiuyan.wang@Sun.COM }
14587956Sxiuyan.wang@Sun.COM
14597956Sxiuyan.wang@Sun.COM /*
14607956Sxiuyan.wang@Sun.COM * This is invoked from receive isr, and at initialization time when no
14617956Sxiuyan.wang@Sun.COM * rx buffers have been posted to card. Due to the single threaded nature
14627956Sxiuyan.wang@Sun.COM * of the invocation, pool_lock acquisition is not neccesary to protect
14637956Sxiuyan.wang@Sun.COM * pool_list.
14647956Sxiuyan.wang@Sun.COM */
14657956Sxiuyan.wang@Sun.COM static unm_rx_buffer_t *
unm_reserve_rx_buffer(unm_rcv_desc_ctx_t * rcv_desc)14667956Sxiuyan.wang@Sun.COM unm_reserve_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc)
14677956Sxiuyan.wang@Sun.COM {
14687956Sxiuyan.wang@Sun.COM unm_rx_buffer_t *rx_buffer = NULL;
14697956Sxiuyan.wang@Sun.COM
14707956Sxiuyan.wang@Sun.COM /* mutex_enter(rcv_desc->pool_lock); */
14717956Sxiuyan.wang@Sun.COM if (rcv_desc->rx_buf_free) {
14727956Sxiuyan.wang@Sun.COM rx_buffer = rcv_desc->pool_list;
14737956Sxiuyan.wang@Sun.COM rcv_desc->pool_list = rx_buffer->next;
14747956Sxiuyan.wang@Sun.COM rx_buffer->next = NULL;
14757956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_free--;
14767956Sxiuyan.wang@Sun.COM } else {
14777956Sxiuyan.wang@Sun.COM mutex_enter(rcv_desc->recycle_lock);
14787956Sxiuyan.wang@Sun.COM
14797956Sxiuyan.wang@Sun.COM if (rcv_desc->rx_buf_recycle) {
14807956Sxiuyan.wang@Sun.COM rcv_desc->pool_list = rcv_desc->recycle_list;
14817956Sxiuyan.wang@Sun.COM rcv_desc->recycle_list = NULL;
14827956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_free += rcv_desc->rx_buf_recycle;
14837956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_recycle = 0;
14847956Sxiuyan.wang@Sun.COM
14857956Sxiuyan.wang@Sun.COM rx_buffer = rcv_desc->pool_list;
14867956Sxiuyan.wang@Sun.COM rcv_desc->pool_list = rx_buffer->next;
14877956Sxiuyan.wang@Sun.COM rx_buffer->next = NULL;
14887956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_free--;
14897956Sxiuyan.wang@Sun.COM }
14907956Sxiuyan.wang@Sun.COM
14917956Sxiuyan.wang@Sun.COM mutex_exit(rcv_desc->recycle_lock);
14927956Sxiuyan.wang@Sun.COM }
14937956Sxiuyan.wang@Sun.COM
14947956Sxiuyan.wang@Sun.COM /* mutex_exit(rcv_desc->pool_lock); */
14957956Sxiuyan.wang@Sun.COM return (rx_buffer);
14967956Sxiuyan.wang@Sun.COM }
14977956Sxiuyan.wang@Sun.COM
14987956Sxiuyan.wang@Sun.COM static void
post_rx_doorbell(struct unm_adapter_s * adapter,uint32_t ringid,int count)14997956Sxiuyan.wang@Sun.COM post_rx_doorbell(struct unm_adapter_s *adapter, uint32_t ringid, int count)
15007956Sxiuyan.wang@Sun.COM {
15017956Sxiuyan.wang@Sun.COM #define UNM_RCV_PEG_DB_ID 2
15027956Sxiuyan.wang@Sun.COM #define UNM_RCV_PRODUCER_OFFSET 0
15037956Sxiuyan.wang@Sun.COM ctx_msg msg = {0};
15047956Sxiuyan.wang@Sun.COM
15057956Sxiuyan.wang@Sun.COM /*
15067956Sxiuyan.wang@Sun.COM * Write a doorbell msg to tell phanmon of change in
15077956Sxiuyan.wang@Sun.COM * receive ring producer
15087956Sxiuyan.wang@Sun.COM */
15097956Sxiuyan.wang@Sun.COM msg.PegId = UNM_RCV_PEG_DB_ID;
15107956Sxiuyan.wang@Sun.COM msg.privId = 1;
15117956Sxiuyan.wang@Sun.COM msg.Count = count;
15127956Sxiuyan.wang@Sun.COM msg.CtxId = adapter->portnum;
15137956Sxiuyan.wang@Sun.COM msg.Opcode = UNM_RCV_PRODUCER(ringid);
15147956Sxiuyan.wang@Sun.COM dbwritel(*((__uint32_t *)&msg),
15157956Sxiuyan.wang@Sun.COM (void *)(DB_NORMALIZE(adapter, UNM_RCV_PRODUCER_OFFSET)));
15167956Sxiuyan.wang@Sun.COM }
15177956Sxiuyan.wang@Sun.COM
15187956Sxiuyan.wang@Sun.COM static int
unm_post_rx_buffers(struct unm_adapter_s * adapter,uint32_t ringid)15197956Sxiuyan.wang@Sun.COM unm_post_rx_buffers(struct unm_adapter_s *adapter, uint32_t ringid)
15207956Sxiuyan.wang@Sun.COM {
15217956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
15227956Sxiuyan.wang@Sun.COM unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[ringid];
15237956Sxiuyan.wang@Sun.COM unm_rx_buffer_t *rx_buffer;
15247956Sxiuyan.wang@Sun.COM rcvDesc_t *pdesc;
15257956Sxiuyan.wang@Sun.COM int count;
15267956Sxiuyan.wang@Sun.COM
15277956Sxiuyan.wang@Sun.COM for (count = 0; count < rcv_desc->MaxRxDescCount; count++) {
15287956Sxiuyan.wang@Sun.COM rx_buffer = unm_reserve_rx_buffer(rcv_desc);
15297956Sxiuyan.wang@Sun.COM if (rx_buffer != NULL) {
15307956Sxiuyan.wang@Sun.COM pdesc = &rcv_desc->desc_head[count];
15317956Sxiuyan.wang@Sun.COM pdesc->referenceHandle = rxbuf2index(rcv_desc,
15327956Sxiuyan.wang@Sun.COM rx_buffer);
15337956Sxiuyan.wang@Sun.COM pdesc->flags = ringid;
15347956Sxiuyan.wang@Sun.COM pdesc->bufferLength = rcv_desc->dma_size;
15357956Sxiuyan.wang@Sun.COM pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
15367956Sxiuyan.wang@Sun.COM }
15377956Sxiuyan.wang@Sun.COM else
15387956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
15397956Sxiuyan.wang@Sun.COM }
15407956Sxiuyan.wang@Sun.COM
15417956Sxiuyan.wang@Sun.COM rcv_desc->producer = count % rcv_desc->MaxRxDescCount;
15427956Sxiuyan.wang@Sun.COM count--;
15437956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle,
15447956Sxiuyan.wang@Sun.COM 0, /* start */
15457956Sxiuyan.wang@Sun.COM count, /* count */
15467956Sxiuyan.wang@Sun.COM count, /* range */
15477956Sxiuyan.wang@Sun.COM sizeof (rcvDesc_t), /* unit_size */
15487956Sxiuyan.wang@Sun.COM DDI_DMA_SYNC_FORDEV); /* direction */
15497956Sxiuyan.wang@Sun.COM
15507956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_card = rcv_desc->MaxRxDescCount;
15517956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
15527956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter, rcv_desc->host_rx_producer,
15537956Sxiuyan.wang@Sun.COM &count, 4);
15547956Sxiuyan.wang@Sun.COM if (adapter->fw_major < 4)
15557956Sxiuyan.wang@Sun.COM post_rx_doorbell(adapter, ringid, count);
15567956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
15577956Sxiuyan.wang@Sun.COM
15587956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
15597956Sxiuyan.wang@Sun.COM }
15607956Sxiuyan.wang@Sun.COM
15617956Sxiuyan.wang@Sun.COM static void
unm_post_rx_buffers_nodb(struct unm_adapter_s * adapter,uint32_t ringid)15627956Sxiuyan.wang@Sun.COM unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
15637956Sxiuyan.wang@Sun.COM uint32_t ringid)
15647956Sxiuyan.wang@Sun.COM {
15657956Sxiuyan.wang@Sun.COM unm_recv_context_t *recv_ctx = &(adapter->recv_ctx[0]);
15667956Sxiuyan.wang@Sun.COM unm_rcv_desc_ctx_t *rcv_desc = &recv_ctx->rcv_desc[ringid];
15677956Sxiuyan.wang@Sun.COM struct unm_rx_buffer *rx_buffer;
15687956Sxiuyan.wang@Sun.COM rcvDesc_t *pdesc;
15697956Sxiuyan.wang@Sun.COM int count, producer = rcv_desc->producer;
15707956Sxiuyan.wang@Sun.COM int last_producer = producer;
15717956Sxiuyan.wang@Sun.COM
15727956Sxiuyan.wang@Sun.COM for (count = 0; count < rcv_desc->rx_desc_handled; count++) {
15737956Sxiuyan.wang@Sun.COM rx_buffer = unm_reserve_rx_buffer(rcv_desc);
15747956Sxiuyan.wang@Sun.COM if (rx_buffer != NULL) {
15757956Sxiuyan.wang@Sun.COM pdesc = &rcv_desc->desc_head[producer];
15767956Sxiuyan.wang@Sun.COM pdesc->referenceHandle = rxbuf2index(rcv_desc,
15777956Sxiuyan.wang@Sun.COM rx_buffer);
15787956Sxiuyan.wang@Sun.COM pdesc->flags = ringid;
15797956Sxiuyan.wang@Sun.COM pdesc->bufferLength = rcv_desc->dma_size;
15807956Sxiuyan.wang@Sun.COM pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
15817956Sxiuyan.wang@Sun.COM } else {
15827956Sxiuyan.wang@Sun.COM adapter->stats.outofrxbuf++;
15837956Sxiuyan.wang@Sun.COM break;
15847956Sxiuyan.wang@Sun.COM }
15857956Sxiuyan.wang@Sun.COM producer = get_next_index(producer, rcv_desc->MaxRxDescCount);
15867956Sxiuyan.wang@Sun.COM }
15877956Sxiuyan.wang@Sun.COM
15887956Sxiuyan.wang@Sun.COM /* if we did allocate buffers, then write the count to Phantom */
15897956Sxiuyan.wang@Sun.COM if (count) {
15907956Sxiuyan.wang@Sun.COM /* Sync rx ring, considering case for wrap around */
15917956Sxiuyan.wang@Sun.COM unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle, last_producer,
15927956Sxiuyan.wang@Sun.COM count, rcv_desc->MaxRxDescCount, sizeof (rcvDesc_t),
15937956Sxiuyan.wang@Sun.COM DDI_DMA_SYNC_FORDEV);
15947956Sxiuyan.wang@Sun.COM
15957956Sxiuyan.wang@Sun.COM rcv_desc->producer = producer;
15967956Sxiuyan.wang@Sun.COM rcv_desc->rx_desc_handled -= count;
15977956Sxiuyan.wang@Sun.COM rcv_desc->rx_buf_card += count;
15987956Sxiuyan.wang@Sun.COM
15997956Sxiuyan.wang@Sun.COM producer = (producer - 1) % rcv_desc->MaxRxDescCount;
16007956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
16017956Sxiuyan.wang@Sun.COM adapter->unm_nic_hw_write_wx(adapter,
16027956Sxiuyan.wang@Sun.COM rcv_desc->host_rx_producer, &producer, 4);
16037956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
16047956Sxiuyan.wang@Sun.COM }
16057956Sxiuyan.wang@Sun.COM }
16067956Sxiuyan.wang@Sun.COM
16077956Sxiuyan.wang@Sun.COM int
unm_nic_fill_statistics_128M(struct unm_adapter_s * adapter,struct unm_statistics * unm_stats)16087956Sxiuyan.wang@Sun.COM unm_nic_fill_statistics_128M(struct unm_adapter_s *adapter,
16097956Sxiuyan.wang@Sun.COM struct unm_statistics *unm_stats)
16107956Sxiuyan.wang@Sun.COM {
16117956Sxiuyan.wang@Sun.COM void *addr;
16127956Sxiuyan.wang@Sun.COM if (adapter->ahw.board_type == UNM_NIC_XGBE) {
16137956Sxiuyan.wang@Sun.COM UNM_WRITE_LOCK(&adapter->adapter_lock);
16147956Sxiuyan.wang@Sun.COM unm_nic_pci_change_crbwindow_128M(adapter, 0);
16157956Sxiuyan.wang@Sun.COM
16167956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16177956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_BYTE_CNT,
16187956Sxiuyan.wang@Sun.COM &(unm_stats->tx_bytes));
16197956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16207956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_FRAME_CNT,
16217956Sxiuyan.wang@Sun.COM &(unm_stats->tx_packets));
16227956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16237956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_BYTE_CNT,
16247956Sxiuyan.wang@Sun.COM &(unm_stats->rx_bytes));
16257956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16267956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_FRAME_CNT,
16277956Sxiuyan.wang@Sun.COM &(unm_stats->rx_packets));
16287956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16297956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_AGGR_ERROR_CNT,
16307956Sxiuyan.wang@Sun.COM &(unm_stats->rx_errors));
16317956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16327956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_CRC_ERROR_CNT,
16337956Sxiuyan.wang@Sun.COM &(unm_stats->rx_CRC_errors));
16347956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16357956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
16367956Sxiuyan.wang@Sun.COM &(unm_stats->rx_long_length_error));
16377956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
16387956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
16397956Sxiuyan.wang@Sun.COM &(unm_stats->rx_short_length_error));
16407956Sxiuyan.wang@Sun.COM
16417956Sxiuyan.wang@Sun.COM /*
16427956Sxiuyan.wang@Sun.COM * For reading rx_MAC_error bit different procedure
16437956Sxiuyan.wang@Sun.COM * UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_TEST_MUX_CTL, 0x15);
16447956Sxiuyan.wang@Sun.COM * UNM_NIC_LOCKED_READ_REG((UNM_CRB_NIU + 0xC0), &temp);
16457956Sxiuyan.wang@Sun.COM * unm_stats->rx_MAC_errors = temp & 0xff;
16467956Sxiuyan.wang@Sun.COM */
16477956Sxiuyan.wang@Sun.COM
16487956Sxiuyan.wang@Sun.COM unm_nic_pci_change_crbwindow_128M(adapter, 1);
16497956Sxiuyan.wang@Sun.COM UNM_WRITE_UNLOCK(&adapter->adapter_lock);
16507956Sxiuyan.wang@Sun.COM } else {
16517956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
16527956Sxiuyan.wang@Sun.COM unm_stats->tx_bytes = adapter->stats.txbytes;
16537956Sxiuyan.wang@Sun.COM unm_stats->tx_packets = adapter->stats.xmitedframes +
16547956Sxiuyan.wang@Sun.COM adapter->stats.xmitfinished;
16557956Sxiuyan.wang@Sun.COM unm_stats->rx_bytes = adapter->stats.rxbytes;
16567956Sxiuyan.wang@Sun.COM unm_stats->rx_packets = adapter->stats.no_rcv;
16577956Sxiuyan.wang@Sun.COM unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
16587956Sxiuyan.wang@Sun.COM unm_stats->tx_errors = adapter->stats.nocmddescriptor;
16597956Sxiuyan.wang@Sun.COM unm_stats->rx_short_length_error = adapter->stats.uplcong;
16607956Sxiuyan.wang@Sun.COM unm_stats->rx_long_length_error = adapter->stats.uphcong;
16617956Sxiuyan.wang@Sun.COM unm_stats->rx_CRC_errors = 0;
16627956Sxiuyan.wang@Sun.COM unm_stats->rx_MAC_errors = 0;
16637956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
16647956Sxiuyan.wang@Sun.COM }
16657956Sxiuyan.wang@Sun.COM return (0);
16667956Sxiuyan.wang@Sun.COM }
16677956Sxiuyan.wang@Sun.COM
16687956Sxiuyan.wang@Sun.COM int
unm_nic_fill_statistics_2M(struct unm_adapter_s * adapter,struct unm_statistics * unm_stats)16697956Sxiuyan.wang@Sun.COM unm_nic_fill_statistics_2M(struct unm_adapter_s *adapter,
16707956Sxiuyan.wang@Sun.COM struct unm_statistics *unm_stats)
16717956Sxiuyan.wang@Sun.COM {
16727956Sxiuyan.wang@Sun.COM if (adapter->ahw.board_type == UNM_NIC_XGBE) {
16737956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
16747956Sxiuyan.wang@Sun.COM &(unm_stats->tx_bytes), 4);
16757956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
16767956Sxiuyan.wang@Sun.COM &(unm_stats->tx_packets), 4);
16777956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
16787956Sxiuyan.wang@Sun.COM &(unm_stats->rx_bytes), 4);
16797956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
16807956Sxiuyan.wang@Sun.COM &(unm_stats->rx_packets), 4);
16817956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter,
16827956Sxiuyan.wang@Sun.COM UNM_NIU_XGE_AGGR_ERROR_CNT, &(unm_stats->rx_errors), 4);
16837956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
16847956Sxiuyan.wang@Sun.COM &(unm_stats->rx_CRC_errors), 4);
16857956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter,
16867956Sxiuyan.wang@Sun.COM UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
16877956Sxiuyan.wang@Sun.COM &(unm_stats->rx_long_length_error), 4);
16887956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_read_wx_2M(adapter,
16897956Sxiuyan.wang@Sun.COM UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
16907956Sxiuyan.wang@Sun.COM &(unm_stats->rx_short_length_error), 4);
16917956Sxiuyan.wang@Sun.COM } else {
16927956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
16937956Sxiuyan.wang@Sun.COM unm_stats->tx_bytes = adapter->stats.txbytes;
16947956Sxiuyan.wang@Sun.COM unm_stats->tx_packets = adapter->stats.xmitedframes +
16957956Sxiuyan.wang@Sun.COM adapter->stats.xmitfinished;
16967956Sxiuyan.wang@Sun.COM unm_stats->rx_bytes = adapter->stats.rxbytes;
16977956Sxiuyan.wang@Sun.COM unm_stats->rx_packets = adapter->stats.no_rcv;
16987956Sxiuyan.wang@Sun.COM unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
16997956Sxiuyan.wang@Sun.COM unm_stats->tx_errors = adapter->stats.nocmddescriptor;
17007956Sxiuyan.wang@Sun.COM unm_stats->rx_short_length_error = adapter->stats.uplcong;
17017956Sxiuyan.wang@Sun.COM unm_stats->rx_long_length_error = adapter->stats.uphcong;
17027956Sxiuyan.wang@Sun.COM unm_stats->rx_CRC_errors = 0;
17037956Sxiuyan.wang@Sun.COM unm_stats->rx_MAC_errors = 0;
17047956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
17057956Sxiuyan.wang@Sun.COM }
17067956Sxiuyan.wang@Sun.COM return (0);
17077956Sxiuyan.wang@Sun.COM }
17087956Sxiuyan.wang@Sun.COM
17097956Sxiuyan.wang@Sun.COM int
unm_nic_clear_statistics_128M(struct unm_adapter_s * adapter)17107956Sxiuyan.wang@Sun.COM unm_nic_clear_statistics_128M(struct unm_adapter_s *adapter)
17117956Sxiuyan.wang@Sun.COM {
17127956Sxiuyan.wang@Sun.COM void *addr;
17137956Sxiuyan.wang@Sun.COM int data = 0;
17147956Sxiuyan.wang@Sun.COM
17157956Sxiuyan.wang@Sun.COM UNM_WRITE_LOCK(&adapter->adapter_lock);
17167956Sxiuyan.wang@Sun.COM unm_nic_pci_change_crbwindow_128M(adapter, 0);
17177956Sxiuyan.wang@Sun.COM
17187956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17197956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_BYTE_CNT, &data);
17207956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17217956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_FRAME_CNT, &data);
17227956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17237956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_BYTE_CNT, &data);
17247956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17257956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_FRAME_CNT, &data);
17267956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17277956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_AGGR_ERROR_CNT, &data);
17287956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17297956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_CRC_ERROR_CNT, &data);
17307956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17317956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR, &data);
17327956Sxiuyan.wang@Sun.COM /* LINTED: E_FALSE_LOGICAL_EXPR */
17337956Sxiuyan.wang@Sun.COM UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR, &data);
17347956Sxiuyan.wang@Sun.COM
17357956Sxiuyan.wang@Sun.COM unm_nic_pci_change_crbwindow_128M(adapter, 1);
17367956Sxiuyan.wang@Sun.COM UNM_WRITE_UNLOCK(&adapter->adapter_lock);
17377956Sxiuyan.wang@Sun.COM unm_nic_clear_stats(adapter);
17387956Sxiuyan.wang@Sun.COM return (0);
17397956Sxiuyan.wang@Sun.COM }
17407956Sxiuyan.wang@Sun.COM
17417956Sxiuyan.wang@Sun.COM int
unm_nic_clear_statistics_2M(struct unm_adapter_s * adapter)17427956Sxiuyan.wang@Sun.COM unm_nic_clear_statistics_2M(struct unm_adapter_s *adapter)
17437956Sxiuyan.wang@Sun.COM {
17447956Sxiuyan.wang@Sun.COM int data = 0;
17457956Sxiuyan.wang@Sun.COM
17467956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
17477956Sxiuyan.wang@Sun.COM &data, 4);
17487956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
17497956Sxiuyan.wang@Sun.COM &data, 4);
17507956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
17517956Sxiuyan.wang@Sun.COM &data, 4);
17527956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
17537956Sxiuyan.wang@Sun.COM &data, 4);
17547956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_AGGR_ERROR_CNT,
17557956Sxiuyan.wang@Sun.COM &data, 4);
17567956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
17577956Sxiuyan.wang@Sun.COM &data, 4);
17587956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
17597956Sxiuyan.wang@Sun.COM &data, 4);
17607956Sxiuyan.wang@Sun.COM (void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
17617956Sxiuyan.wang@Sun.COM &data, 4);
17627956Sxiuyan.wang@Sun.COM unm_nic_clear_stats(adapter);
17637956Sxiuyan.wang@Sun.COM return (0);
17647956Sxiuyan.wang@Sun.COM }
17657956Sxiuyan.wang@Sun.COM
17667956Sxiuyan.wang@Sun.COM /*
17677956Sxiuyan.wang@Sun.COM * unm_nic_ioctl () We provide the tcl/phanmon support
17687956Sxiuyan.wang@Sun.COM * through these ioctls.
17697956Sxiuyan.wang@Sun.COM */
17707956Sxiuyan.wang@Sun.COM static void
unm_nic_ioctl(struct unm_adapter_s * adapter,int cmd,queue_t * q,mblk_t * mp)17717956Sxiuyan.wang@Sun.COM unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q, mblk_t *mp)
17727956Sxiuyan.wang@Sun.COM {
17737956Sxiuyan.wang@Sun.COM void *ptr;
17747956Sxiuyan.wang@Sun.COM
17757956Sxiuyan.wang@Sun.COM switch (cmd) {
17767956Sxiuyan.wang@Sun.COM case UNM_NIC_CMD:
17777956Sxiuyan.wang@Sun.COM (void) unm_nic_do_ioctl(adapter, q, mp);
17787956Sxiuyan.wang@Sun.COM break;
17797956Sxiuyan.wang@Sun.COM
17807956Sxiuyan.wang@Sun.COM case UNM_NIC_NAME:
17817956Sxiuyan.wang@Sun.COM ptr = (void *) mp->b_cont->b_rptr;
17827956Sxiuyan.wang@Sun.COM
17837956Sxiuyan.wang@Sun.COM /*
17847956Sxiuyan.wang@Sun.COM * Phanmon checks for "UNM-UNM" string
17857956Sxiuyan.wang@Sun.COM * Replace the hardcoded value with appropriate macro
17867956Sxiuyan.wang@Sun.COM */
17877956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_CONT, "UNM_NIC_NAME ioctl executed %d %d\n",
17887956Sxiuyan.wang@Sun.COM cmd, __LINE__));
17897956Sxiuyan.wang@Sun.COM (void) memcpy(ptr, "UNM-UNM", 10);
17907956Sxiuyan.wang@Sun.COM miocack(q, mp, 10, 0);
17917956Sxiuyan.wang@Sun.COM break;
17927956Sxiuyan.wang@Sun.COM
17937956Sxiuyan.wang@Sun.COM default:
17947956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Netxen ioctl cmd %x not supported\n", cmd);
17957956Sxiuyan.wang@Sun.COM
17967956Sxiuyan.wang@Sun.COM miocnak(q, mp, 0, EINVAL);
17977956Sxiuyan.wang@Sun.COM break;
17987956Sxiuyan.wang@Sun.COM }
17997956Sxiuyan.wang@Sun.COM }
18007956Sxiuyan.wang@Sun.COM
18017956Sxiuyan.wang@Sun.COM int
unm_nic_resume(unm_adapter * adapter)18027956Sxiuyan.wang@Sun.COM unm_nic_resume(unm_adapter *adapter)
18037956Sxiuyan.wang@Sun.COM {
18047956Sxiuyan.wang@Sun.COM
18057956Sxiuyan.wang@Sun.COM adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
18067956Sxiuyan.wang@Sun.COM (void *) adapter, 50000);
18077956Sxiuyan.wang@Sun.COM
18087956Sxiuyan.wang@Sun.COM if (adapter->intr_type == DDI_INTR_TYPE_MSI)
18097956Sxiuyan.wang@Sun.COM (void) ddi_intr_block_enable(&adapter->intr_handle, 1);
18107956Sxiuyan.wang@Sun.COM else
18117956Sxiuyan.wang@Sun.COM (void) ddi_intr_enable(adapter->intr_handle);
18127956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
18137956Sxiuyan.wang@Sun.COM unm_nic_enable_int(adapter);
18147956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
18157956Sxiuyan.wang@Sun.COM
18167956Sxiuyan.wang@Sun.COM mac_link_update(adapter->mach, LINK_STATE_UP);
18177956Sxiuyan.wang@Sun.COM
18187956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
18197956Sxiuyan.wang@Sun.COM }
18207956Sxiuyan.wang@Sun.COM
18217956Sxiuyan.wang@Sun.COM int
unm_nic_suspend(unm_adapter * adapter)18227956Sxiuyan.wang@Sun.COM unm_nic_suspend(unm_adapter *adapter)
18237956Sxiuyan.wang@Sun.COM {
18247956Sxiuyan.wang@Sun.COM mac_link_update(adapter->mach, LINK_STATE_DOWN);
18257956Sxiuyan.wang@Sun.COM
18267956Sxiuyan.wang@Sun.COM (void) untimeout(adapter->watchdog_timer);
18277956Sxiuyan.wang@Sun.COM
18287956Sxiuyan.wang@Sun.COM UNM_READ_LOCK(&adapter->adapter_lock);
18297956Sxiuyan.wang@Sun.COM unm_nic_disable_int(adapter);
18307956Sxiuyan.wang@Sun.COM UNM_READ_UNLOCK(&adapter->adapter_lock);
18317956Sxiuyan.wang@Sun.COM if (adapter->intr_type == DDI_INTR_TYPE_MSI)
18327956Sxiuyan.wang@Sun.COM (void) ddi_intr_block_disable(&adapter->intr_handle, 1);
18337956Sxiuyan.wang@Sun.COM else
18347956Sxiuyan.wang@Sun.COM (void) ddi_intr_disable(adapter->intr_handle);
18357956Sxiuyan.wang@Sun.COM
18367956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
18377956Sxiuyan.wang@Sun.COM }
18387956Sxiuyan.wang@Sun.COM
18397956Sxiuyan.wang@Sun.COM static int
unm_nic_do_ioctl(unm_adapter * adapter,queue_t * wq,mblk_t * mp)18407956Sxiuyan.wang@Sun.COM unm_nic_do_ioctl(unm_adapter *adapter, queue_t *wq, mblk_t *mp)
18417956Sxiuyan.wang@Sun.COM {
18427956Sxiuyan.wang@Sun.COM unm_nic_ioctl_data_t data;
18437956Sxiuyan.wang@Sun.COM struct unm_nic_ioctl_data *up_data;
18447956Sxiuyan.wang@Sun.COM ddi_acc_handle_t conf_handle;
18457956Sxiuyan.wang@Sun.COM int retval = 0;
18469436SJing.Xiong@Sun.COM uint64_t efuse_chip_id = 0;
18477956Sxiuyan.wang@Sun.COM char *ptr1;
18487956Sxiuyan.wang@Sun.COM short *ptr2;
18497956Sxiuyan.wang@Sun.COM int *ptr4;
18507956Sxiuyan.wang@Sun.COM
18517956Sxiuyan.wang@Sun.COM up_data = (struct unm_nic_ioctl_data *)(mp->b_cont->b_rptr);
18527956Sxiuyan.wang@Sun.COM (void) memcpy(&data, (void **)(uintptr_t)(mp->b_cont->b_rptr),
18537956Sxiuyan.wang@Sun.COM sizeof (data));
18547956Sxiuyan.wang@Sun.COM
18557956Sxiuyan.wang@Sun.COM /* Shouldn't access beyond legal limits of "char u[64];" member */
18567956Sxiuyan.wang@Sun.COM if (data.size > sizeof (data.uabc)) {
18577956Sxiuyan.wang@Sun.COM /* evil user tried to crash the kernel */
18587956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "bad size: %d\n", data.size);
18597956Sxiuyan.wang@Sun.COM retval = GLD_BADARG;
18607956Sxiuyan.wang@Sun.COM goto error_out;
18617956Sxiuyan.wang@Sun.COM }
18627956Sxiuyan.wang@Sun.COM
18637956Sxiuyan.wang@Sun.COM switch (data.cmd) {
18647956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_read:
18657956Sxiuyan.wang@Sun.COM
18667956Sxiuyan.wang@Sun.COM if ((retval = adapter->unm_nic_hw_read_ioctl(adapter,
18677956Sxiuyan.wang@Sun.COM data.off, up_data, data.size))) {
18687956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_read_wx "
18697956Sxiuyan.wang@Sun.COM "returned %d\n", __FUNCTION__, __LINE__, retval));
18707956Sxiuyan.wang@Sun.COM
18717956Sxiuyan.wang@Sun.COM retval = data.rv;
18727956Sxiuyan.wang@Sun.COM goto error_out;
18737956Sxiuyan.wang@Sun.COM }
18747956Sxiuyan.wang@Sun.COM
18757956Sxiuyan.wang@Sun.COM data.rv = 0;
18767956Sxiuyan.wang@Sun.COM break;
18777956Sxiuyan.wang@Sun.COM
18787956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_write:
18797956Sxiuyan.wang@Sun.COM if ((data.rv = adapter->unm_nic_hw_write_ioctl(adapter,
18807956Sxiuyan.wang@Sun.COM data.off, &(data.uabc), data.size))) {
18817956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_write_wx "
18827956Sxiuyan.wang@Sun.COM "returned %d\n", __FUNCTION__,
18837956Sxiuyan.wang@Sun.COM __LINE__, data.rv));
18847956Sxiuyan.wang@Sun.COM retval = data.rv;
18857956Sxiuyan.wang@Sun.COM goto error_out;
18867956Sxiuyan.wang@Sun.COM }
18877956Sxiuyan.wang@Sun.COM data.size = 0;
18887956Sxiuyan.wang@Sun.COM break;
18897956Sxiuyan.wang@Sun.COM
18907956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_mem_read:
18917956Sxiuyan.wang@Sun.COM if ((data.rv = adapter->unm_nic_pci_mem_read(adapter,
18927956Sxiuyan.wang@Sun.COM data.off, up_data, data.size))) {
18937956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_pci_mem_read "
18947956Sxiuyan.wang@Sun.COM "returned %d\n", __FUNCTION__,
18957956Sxiuyan.wang@Sun.COM __LINE__, data.rv));
18967956Sxiuyan.wang@Sun.COM retval = data.rv;
18977956Sxiuyan.wang@Sun.COM goto error_out;
18987956Sxiuyan.wang@Sun.COM }
18997956Sxiuyan.wang@Sun.COM data.rv = 0;
19007956Sxiuyan.wang@Sun.COM break;
19017956Sxiuyan.wang@Sun.COM
19027956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_mem_write:
19037956Sxiuyan.wang@Sun.COM if ((data.rv = adapter->unm_nic_pci_mem_write(adapter,
19047956Sxiuyan.wang@Sun.COM data.off, &(data.uabc), data.size))) {
19057956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN,
19067956Sxiuyan.wang@Sun.COM "%s(%d) unm_nic_cmd_pci_mem_write "
19077956Sxiuyan.wang@Sun.COM "returned %d\n",
19087956Sxiuyan.wang@Sun.COM __FUNCTION__, __LINE__, data.rv));
19097956Sxiuyan.wang@Sun.COM retval = data.rv;
19107956Sxiuyan.wang@Sun.COM goto error_out;
19117956Sxiuyan.wang@Sun.COM }
19127956Sxiuyan.wang@Sun.COM
19137956Sxiuyan.wang@Sun.COM data.size = 0;
19147956Sxiuyan.wang@Sun.COM data.rv = 0;
19157956Sxiuyan.wang@Sun.COM break;
19167956Sxiuyan.wang@Sun.COM
19177956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_config_read:
19187956Sxiuyan.wang@Sun.COM
19197956Sxiuyan.wang@Sun.COM if (adapter->pci_cfg_handle != NULL) {
19207956Sxiuyan.wang@Sun.COM conf_handle = adapter->pci_cfg_handle;
19217956Sxiuyan.wang@Sun.COM
19227956Sxiuyan.wang@Sun.COM } else if ((retval = pci_config_setup(adapter->dip,
19237956Sxiuyan.wang@Sun.COM &conf_handle)) != DDI_SUCCESS) {
19247956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
19257956Sxiuyan.wang@Sun.COM " error:%d\n", unm_nic_driver_name, retval));
19267956Sxiuyan.wang@Sun.COM goto error_out;
19277956Sxiuyan.wang@Sun.COM
19287956Sxiuyan.wang@Sun.COM } else
19297956Sxiuyan.wang@Sun.COM adapter->pci_cfg_handle = conf_handle;
19307956Sxiuyan.wang@Sun.COM
19317956Sxiuyan.wang@Sun.COM switch (data.size) {
19327956Sxiuyan.wang@Sun.COM case 1:
19337956Sxiuyan.wang@Sun.COM ptr1 = (char *)up_data;
19347956Sxiuyan.wang@Sun.COM *ptr1 = (char)pci_config_get8(conf_handle, data.off);
19357956Sxiuyan.wang@Sun.COM break;
19367956Sxiuyan.wang@Sun.COM case 2:
19377956Sxiuyan.wang@Sun.COM ptr2 = (short *)up_data;
19387956Sxiuyan.wang@Sun.COM *ptr2 = (short)pci_config_get16(conf_handle, data.off);
19397956Sxiuyan.wang@Sun.COM break;
19407956Sxiuyan.wang@Sun.COM case 4:
19417956Sxiuyan.wang@Sun.COM ptr4 = (int *)up_data;
19427956Sxiuyan.wang@Sun.COM *ptr4 = (int)pci_config_get32(conf_handle, data.off);
19437956Sxiuyan.wang@Sun.COM break;
19447956Sxiuyan.wang@Sun.COM }
19457956Sxiuyan.wang@Sun.COM
19467956Sxiuyan.wang@Sun.COM break;
19477956Sxiuyan.wang@Sun.COM
19487956Sxiuyan.wang@Sun.COM case unm_nic_cmd_pci_config_write:
19497956Sxiuyan.wang@Sun.COM
19507956Sxiuyan.wang@Sun.COM if (adapter->pci_cfg_handle != NULL) {
19517956Sxiuyan.wang@Sun.COM conf_handle = adapter->pci_cfg_handle;
19527956Sxiuyan.wang@Sun.COM } else if ((retval = pci_config_setup(adapter->dip,
19537956Sxiuyan.wang@Sun.COM &conf_handle)) != DDI_SUCCESS) {
19547956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
19557956Sxiuyan.wang@Sun.COM " error:%d\n", unm_nic_driver_name, retval));
19567956Sxiuyan.wang@Sun.COM goto error_out;
19577956Sxiuyan.wang@Sun.COM } else {
19587956Sxiuyan.wang@Sun.COM adapter->pci_cfg_handle = conf_handle;
19597956Sxiuyan.wang@Sun.COM }
19607956Sxiuyan.wang@Sun.COM
19617956Sxiuyan.wang@Sun.COM switch (data.size) {
19627956Sxiuyan.wang@Sun.COM case 1:
19637956Sxiuyan.wang@Sun.COM pci_config_put8(conf_handle,
19647956Sxiuyan.wang@Sun.COM data.off, *(char *)&(data.uabc));
19657956Sxiuyan.wang@Sun.COM break;
19667956Sxiuyan.wang@Sun.COM case 2:
19677956Sxiuyan.wang@Sun.COM pci_config_put16(conf_handle,
19687956Sxiuyan.wang@Sun.COM data.off, *(short *)(uintptr_t)&(data.uabc));
19697956Sxiuyan.wang@Sun.COM break;
19707956Sxiuyan.wang@Sun.COM case 4:
19717956Sxiuyan.wang@Sun.COM pci_config_put32(conf_handle,
19727956Sxiuyan.wang@Sun.COM data.off, *(u32 *)(uintptr_t)&(data.uabc));
19737956Sxiuyan.wang@Sun.COM break;
19747956Sxiuyan.wang@Sun.COM }
19757956Sxiuyan.wang@Sun.COM data.size = 0;
19767956Sxiuyan.wang@Sun.COM break;
19777956Sxiuyan.wang@Sun.COM
19787956Sxiuyan.wang@Sun.COM case unm_nic_cmd_get_stats:
19797956Sxiuyan.wang@Sun.COM data.rv = adapter->unm_nic_fill_statistics(adapter,
19807956Sxiuyan.wang@Sun.COM (struct unm_statistics *)up_data);
19817956Sxiuyan.wang@Sun.COM data.size = sizeof (struct unm_statistics);
19827956Sxiuyan.wang@Sun.COM
19837956Sxiuyan.wang@Sun.COM break;
19847956Sxiuyan.wang@Sun.COM
19857956Sxiuyan.wang@Sun.COM case unm_nic_cmd_clear_stats:
19867956Sxiuyan.wang@Sun.COM data.rv = adapter->unm_nic_clear_statistics(adapter);
19877956Sxiuyan.wang@Sun.COM break;
19887956Sxiuyan.wang@Sun.COM
19897956Sxiuyan.wang@Sun.COM case unm_nic_cmd_get_version:
19907956Sxiuyan.wang@Sun.COM (void) memcpy(up_data, UNM_NIC_VERSIONID,
19917956Sxiuyan.wang@Sun.COM sizeof (UNM_NIC_VERSIONID));
19927956Sxiuyan.wang@Sun.COM data.size = sizeof (UNM_NIC_VERSIONID);
19937956Sxiuyan.wang@Sun.COM
19947956Sxiuyan.wang@Sun.COM break;
19957956Sxiuyan.wang@Sun.COM
19967956Sxiuyan.wang@Sun.COM case unm_nic_cmd_get_phy_type:
19977956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "unm_nic_cmd_get_phy_type unimplemented\n");
19987956Sxiuyan.wang@Sun.COM break;
19997956Sxiuyan.wang@Sun.COM
20007956Sxiuyan.wang@Sun.COM case unm_nic_cmd_efuse_chip_id:
20017956Sxiuyan.wang@Sun.COM efuse_chip_id = adapter->unm_nic_pci_read_normalize(adapter,
20029436SJing.Xiong@Sun.COM UNM_EFUSE_CHIP_ID_HIGH);
20039436SJing.Xiong@Sun.COM efuse_chip_id <<= 32;
20049436SJing.Xiong@Sun.COM efuse_chip_id |= adapter->unm_nic_pci_read_normalize(adapter,
20059436SJing.Xiong@Sun.COM UNM_EFUSE_CHIP_ID_LOW);
20069436SJing.Xiong@Sun.COM (void) memcpy(up_data, &efuse_chip_id, sizeof (uint64_t));
20077956Sxiuyan.wang@Sun.COM data.rv = 0;
20087956Sxiuyan.wang@Sun.COM break;
20097956Sxiuyan.wang@Sun.COM
20107956Sxiuyan.wang@Sun.COM default:
20117956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: bad command %d\n", adapter->name,
20127956Sxiuyan.wang@Sun.COM adapter->instance, data.cmd);
20137956Sxiuyan.wang@Sun.COM data.rv = GLD_NOTSUPPORTED;
20147956Sxiuyan.wang@Sun.COM data.size = 0;
20157956Sxiuyan.wang@Sun.COM goto error_out;
20167956Sxiuyan.wang@Sun.COM }
20177956Sxiuyan.wang@Sun.COM
20187956Sxiuyan.wang@Sun.COM work_done:
20197956Sxiuyan.wang@Sun.COM miocack(wq, mp, data.size, data.rv);
20207956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
20217956Sxiuyan.wang@Sun.COM
20227956Sxiuyan.wang@Sun.COM error_out:
20237956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s(%d) ioctl error\n", __FUNCTION__, data.cmd);
20247956Sxiuyan.wang@Sun.COM miocnak(wq, mp, 0, EINVAL);
20257956Sxiuyan.wang@Sun.COM return (retval);
20267956Sxiuyan.wang@Sun.COM }
20277956Sxiuyan.wang@Sun.COM
20287956Sxiuyan.wang@Sun.COM /*
20297956Sxiuyan.wang@Sun.COM * Local datatype for defining tables of (Offset, Name) pairs
20307956Sxiuyan.wang@Sun.COM */
20317956Sxiuyan.wang@Sun.COM typedef struct {
20327956Sxiuyan.wang@Sun.COM offset_t index;
20337956Sxiuyan.wang@Sun.COM char *name;
20347956Sxiuyan.wang@Sun.COM } unm_ksindex_t;
20357956Sxiuyan.wang@Sun.COM
20367956Sxiuyan.wang@Sun.COM static const unm_ksindex_t unm_kstat[] = {
20377956Sxiuyan.wang@Sun.COM { 0, "freehdls" },
20387956Sxiuyan.wang@Sun.COM { 1, "freecmds" },
20397956Sxiuyan.wang@Sun.COM { 2, "tx_bcopy_threshold" },
20407956Sxiuyan.wang@Sun.COM { 3, "rx_bcopy_threshold" },
20417956Sxiuyan.wang@Sun.COM { 4, "xmitcalled" },
20427956Sxiuyan.wang@Sun.COM { 5, "xmitedframes" },
20437956Sxiuyan.wang@Sun.COM { 6, "xmitfinished" },
20447956Sxiuyan.wang@Sun.COM { 7, "txbytes" },
20457956Sxiuyan.wang@Sun.COM { 8, "txcopyed" },
20467956Sxiuyan.wang@Sun.COM { 9, "txmapped" },
20477956Sxiuyan.wang@Sun.COM { 10, "outoftxdmahdl" },
20487956Sxiuyan.wang@Sun.COM { 11, "outofcmddesc" },
20497956Sxiuyan.wang@Sun.COM { 12, "txdropped" },
20507956Sxiuyan.wang@Sun.COM { 13, "polled" },
20517956Sxiuyan.wang@Sun.COM { 14, "uphappy" },
20527956Sxiuyan.wang@Sun.COM { 15, "updropped" },
20537956Sxiuyan.wang@Sun.COM { 16, "csummed" },
20547956Sxiuyan.wang@Sun.COM { 17, "no_rcv" },
20557956Sxiuyan.wang@Sun.COM { 18, "rxbytes" },
20567956Sxiuyan.wang@Sun.COM { 19, "rxcopyed" },
20577956Sxiuyan.wang@Sun.COM { 20, "rxmapped" },
20587956Sxiuyan.wang@Sun.COM { 21, "desballocfailed" },
20597956Sxiuyan.wang@Sun.COM { 22, "outofrxbuf" },
20607956Sxiuyan.wang@Sun.COM { 23, "promiscmode" },
20617956Sxiuyan.wang@Sun.COM { 24, "rxbufshort" },
20627956Sxiuyan.wang@Sun.COM { 25, "allocbfailed" },
20637956Sxiuyan.wang@Sun.COM { -1, NULL }
20647956Sxiuyan.wang@Sun.COM };
20657956Sxiuyan.wang@Sun.COM
20667956Sxiuyan.wang@Sun.COM static int
unm_kstat_update(kstat_t * ksp,int flag)20677956Sxiuyan.wang@Sun.COM unm_kstat_update(kstat_t *ksp, int flag)
20687956Sxiuyan.wang@Sun.COM {
20697956Sxiuyan.wang@Sun.COM unm_adapter *adapter;
20707956Sxiuyan.wang@Sun.COM kstat_named_t *knp;
20717956Sxiuyan.wang@Sun.COM
20727956Sxiuyan.wang@Sun.COM if (flag != KSTAT_READ)
20737956Sxiuyan.wang@Sun.COM return (EACCES);
20747956Sxiuyan.wang@Sun.COM
20757956Sxiuyan.wang@Sun.COM adapter = ksp->ks_private;
20767956Sxiuyan.wang@Sun.COM knp = ksp->ks_data;
20777956Sxiuyan.wang@Sun.COM
20787956Sxiuyan.wang@Sun.COM (knp++)->value.ui32 = adapter->freehdls;
20797956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->freecmds;
20807956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->tx_bcopy_threshold;
20817956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->rx_bcopy_threshold;
20827956Sxiuyan.wang@Sun.COM
20837956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.xmitcalled;
20847956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.xmitedframes;
20857956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.xmitfinished;
20867956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.txbytes;
20877956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.txcopyed;
20887956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.txmapped;
20897956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.outoftxdmahdl;
20907956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.outofcmddesc;
20917956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.txdropped;
20927956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.polled;
20937956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.uphappy;
20947956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.updropped;
20957956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.csummed;
20967956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.no_rcv;
20977956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.rxbytes;
20987956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.rxcopyed;
20997956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.rxmapped;
21007956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.desballocfailed;
21017956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.outofrxbuf;
21027956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.promiscmode;
21037956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.rxbufshort;
21047956Sxiuyan.wang@Sun.COM (knp++)->value.ui64 = adapter->stats.allocbfailed;
21057956Sxiuyan.wang@Sun.COM
21067956Sxiuyan.wang@Sun.COM return (0);
21077956Sxiuyan.wang@Sun.COM }
21087956Sxiuyan.wang@Sun.COM
21097956Sxiuyan.wang@Sun.COM static kstat_t *
unm_setup_named_kstat(unm_adapter * adapter,int instance,char * name,const unm_ksindex_t * ksip,size_t size,int (* update)(kstat_t *,int))21107956Sxiuyan.wang@Sun.COM unm_setup_named_kstat(unm_adapter *adapter, int instance, char *name,
21117956Sxiuyan.wang@Sun.COM const unm_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
21127956Sxiuyan.wang@Sun.COM {
21137956Sxiuyan.wang@Sun.COM kstat_t *ksp;
21147956Sxiuyan.wang@Sun.COM kstat_named_t *knp;
21157956Sxiuyan.wang@Sun.COM char *np;
21167956Sxiuyan.wang@Sun.COM int type;
21177956Sxiuyan.wang@Sun.COM int count = 0;
21187956Sxiuyan.wang@Sun.COM
21197956Sxiuyan.wang@Sun.COM size /= sizeof (unm_ksindex_t);
21207956Sxiuyan.wang@Sun.COM ksp = kstat_create(unm_nic_driver_name, instance, name, "net",
21217956Sxiuyan.wang@Sun.COM KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
21227956Sxiuyan.wang@Sun.COM if (ksp == NULL)
21237956Sxiuyan.wang@Sun.COM return (NULL);
21247956Sxiuyan.wang@Sun.COM
21257956Sxiuyan.wang@Sun.COM ksp->ks_private = adapter;
21267956Sxiuyan.wang@Sun.COM ksp->ks_update = update;
21277956Sxiuyan.wang@Sun.COM for (knp = ksp->ks_data; (np = ksip->name) != NULL; ++knp, ++ksip) {
21287956Sxiuyan.wang@Sun.COM count++;
21297956Sxiuyan.wang@Sun.COM switch (*np) {
21307956Sxiuyan.wang@Sun.COM default:
21317956Sxiuyan.wang@Sun.COM type = KSTAT_DATA_UINT64;
21327956Sxiuyan.wang@Sun.COM break;
21337956Sxiuyan.wang@Sun.COM case '%':
21347956Sxiuyan.wang@Sun.COM np += 1;
21357956Sxiuyan.wang@Sun.COM type = KSTAT_DATA_UINT32;
21367956Sxiuyan.wang@Sun.COM break;
21377956Sxiuyan.wang@Sun.COM case '$':
21387956Sxiuyan.wang@Sun.COM np += 1;
21397956Sxiuyan.wang@Sun.COM type = KSTAT_DATA_STRING;
21407956Sxiuyan.wang@Sun.COM break;
21417956Sxiuyan.wang@Sun.COM case '&':
21427956Sxiuyan.wang@Sun.COM np += 1;
21437956Sxiuyan.wang@Sun.COM type = KSTAT_DATA_CHAR;
21447956Sxiuyan.wang@Sun.COM break;
21457956Sxiuyan.wang@Sun.COM }
21467956Sxiuyan.wang@Sun.COM kstat_named_init(knp, np, type);
21477956Sxiuyan.wang@Sun.COM }
21487956Sxiuyan.wang@Sun.COM kstat_install(ksp);
21497956Sxiuyan.wang@Sun.COM
21507956Sxiuyan.wang@Sun.COM return (ksp);
21517956Sxiuyan.wang@Sun.COM }
21527956Sxiuyan.wang@Sun.COM
21537956Sxiuyan.wang@Sun.COM void
unm_init_kstats(unm_adapter * adapter,int instance)21547956Sxiuyan.wang@Sun.COM unm_init_kstats(unm_adapter* adapter, int instance)
21557956Sxiuyan.wang@Sun.COM {
21567956Sxiuyan.wang@Sun.COM adapter->kstats[0] = unm_setup_named_kstat(adapter,
21577956Sxiuyan.wang@Sun.COM instance, "kstatinfo", unm_kstat,
21587956Sxiuyan.wang@Sun.COM sizeof (unm_kstat), unm_kstat_update);
21597956Sxiuyan.wang@Sun.COM }
21607956Sxiuyan.wang@Sun.COM
21617956Sxiuyan.wang@Sun.COM void
unm_fini_kstats(unm_adapter * adapter)21627956Sxiuyan.wang@Sun.COM unm_fini_kstats(unm_adapter* adapter)
21637956Sxiuyan.wang@Sun.COM {
21647956Sxiuyan.wang@Sun.COM
21657956Sxiuyan.wang@Sun.COM if (adapter->kstats[0] != NULL) {
21667956Sxiuyan.wang@Sun.COM kstat_delete(adapter->kstats[0]);
21677956Sxiuyan.wang@Sun.COM adapter->kstats[0] = NULL;
21687956Sxiuyan.wang@Sun.COM }
21697956Sxiuyan.wang@Sun.COM }
21707956Sxiuyan.wang@Sun.COM
21717956Sxiuyan.wang@Sun.COM static int
unm_nic_set_pauseparam(unm_adapter * adapter,unm_pauseparam_t * pause)21727956Sxiuyan.wang@Sun.COM unm_nic_set_pauseparam(unm_adapter *adapter, unm_pauseparam_t *pause)
21737956Sxiuyan.wang@Sun.COM {
21747956Sxiuyan.wang@Sun.COM int ret = 0;
21757956Sxiuyan.wang@Sun.COM
21767956Sxiuyan.wang@Sun.COM if (adapter->ahw.board_type == UNM_NIC_GBE) {
21777956Sxiuyan.wang@Sun.COM if (unm_niu_gbe_set_rx_flow_ctl(adapter, pause->rx_pause))
21787956Sxiuyan.wang@Sun.COM ret = -EIO;
21797956Sxiuyan.wang@Sun.COM
21807956Sxiuyan.wang@Sun.COM if (unm_niu_gbe_set_tx_flow_ctl(adapter, pause->tx_pause))
21817956Sxiuyan.wang@Sun.COM ret = -EIO;
21827956Sxiuyan.wang@Sun.COM
21837956Sxiuyan.wang@Sun.COM } else if (adapter->ahw.board_type == UNM_NIC_XGBE) {
21847956Sxiuyan.wang@Sun.COM if (unm_niu_xg_set_tx_flow_ctl(adapter, pause->tx_pause))
21857956Sxiuyan.wang@Sun.COM ret = -EIO;
21867956Sxiuyan.wang@Sun.COM } else
21877956Sxiuyan.wang@Sun.COM ret = -EIO;
21887956Sxiuyan.wang@Sun.COM
21897956Sxiuyan.wang@Sun.COM return (ret);
21907956Sxiuyan.wang@Sun.COM }
21917956Sxiuyan.wang@Sun.COM
21927956Sxiuyan.wang@Sun.COM /*
21937956Sxiuyan.wang@Sun.COM * GLD/MAC interfaces
21947956Sxiuyan.wang@Sun.COM */
21957956Sxiuyan.wang@Sun.COM static int
ntxn_m_start(void * arg)21967956Sxiuyan.wang@Sun.COM ntxn_m_start(void *arg)
21977956Sxiuyan.wang@Sun.COM {
21987956Sxiuyan.wang@Sun.COM unm_adapter *adapter = arg;
21997956Sxiuyan.wang@Sun.COM int ring;
22007956Sxiuyan.wang@Sun.COM
22017956Sxiuyan.wang@Sun.COM UNM_SPIN_LOCK(&adapter->lock);
22027956Sxiuyan.wang@Sun.COM if (adapter->is_up == UNM_ADAPTER_UP_MAGIC) {
22037956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22047956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
22057956Sxiuyan.wang@Sun.COM }
22067956Sxiuyan.wang@Sun.COM
22079436SJing.Xiong@Sun.COM if (create_rxtx_rings(adapter) != DDI_SUCCESS) {
22089436SJing.Xiong@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22099436SJing.Xiong@Sun.COM return (DDI_FAILURE);
22109436SJing.Xiong@Sun.COM }
22119436SJing.Xiong@Sun.COM
22127956Sxiuyan.wang@Sun.COM if (init_firmware(adapter) != DDI_SUCCESS) {
22137956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22147956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Failed to init firmware\n",
22157956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22169436SJing.Xiong@Sun.COM goto dest_rings;
22177956Sxiuyan.wang@Sun.COM }
22187956Sxiuyan.wang@Sun.COM
22197956Sxiuyan.wang@Sun.COM unm_nic_clear_stats(adapter);
22207956Sxiuyan.wang@Sun.COM
22217956Sxiuyan.wang@Sun.COM if (unm_nic_hw_resources(adapter) != 0) {
22227956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22237956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Error setting hw resources\n",
22247956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22259436SJing.Xiong@Sun.COM goto dest_rings;
22267956Sxiuyan.wang@Sun.COM }
22277956Sxiuyan.wang@Sun.COM
22287956Sxiuyan.wang@Sun.COM if (adapter->fw_major < 4) {
22297956Sxiuyan.wang@Sun.COM adapter->crb_addr_cmd_producer =
22307956Sxiuyan.wang@Sun.COM crb_cmd_producer[adapter->portnum];
22317956Sxiuyan.wang@Sun.COM adapter->crb_addr_cmd_consumer =
22327956Sxiuyan.wang@Sun.COM crb_cmd_consumer[adapter->portnum];
22337956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_producer(adapter, 0);
22347956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_consumer(adapter, 0);
22357956Sxiuyan.wang@Sun.COM }
22367956Sxiuyan.wang@Sun.COM
22377956Sxiuyan.wang@Sun.COM for (ring = 0; ring < adapter->max_rds_rings; ring++) {
22387956Sxiuyan.wang@Sun.COM if (unm_post_rx_buffers(adapter, ring) != DDI_SUCCESS) {
22397956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22409436SJing.Xiong@Sun.COM goto free_hw_res;
22417956Sxiuyan.wang@Sun.COM }
22427956Sxiuyan.wang@Sun.COM }
22437956Sxiuyan.wang@Sun.COM
22447956Sxiuyan.wang@Sun.COM if (unm_nic_macaddr_set(adapter, adapter->mac_addr) != 0) {
22457956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22467956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Could not set mac address\n",
22477956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22489436SJing.Xiong@Sun.COM goto free_hw_res;
22497956Sxiuyan.wang@Sun.COM }
22507956Sxiuyan.wang@Sun.COM
22517956Sxiuyan.wang@Sun.COM if (unm_nic_init_port(adapter) != 0) {
22527956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22537956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Could not initialize port\n",
22547956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22559436SJing.Xiong@Sun.COM goto free_hw_res;
22567956Sxiuyan.wang@Sun.COM }
22577956Sxiuyan.wang@Sun.COM
22587956Sxiuyan.wang@Sun.COM unm_nic_set_link_parameters(adapter);
22597956Sxiuyan.wang@Sun.COM
22607956Sxiuyan.wang@Sun.COM /*
22617956Sxiuyan.wang@Sun.COM * P2 and P3 should be handled similarly.
22627956Sxiuyan.wang@Sun.COM */
22637956Sxiuyan.wang@Sun.COM if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
22647956Sxiuyan.wang@Sun.COM if (unm_nic_set_promisc_mode(adapter) != 0) {
22657956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22667956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Could not set promisc mode\n",
22677956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22689436SJing.Xiong@Sun.COM goto stop_and_free;
22697956Sxiuyan.wang@Sun.COM }
22707956Sxiuyan.wang@Sun.COM } else {
22717956Sxiuyan.wang@Sun.COM nx_p3_nic_set_multi(adapter);
22727956Sxiuyan.wang@Sun.COM }
22737956Sxiuyan.wang@Sun.COM adapter->stats.promiscmode = 1;
22747956Sxiuyan.wang@Sun.COM
22757956Sxiuyan.wang@Sun.COM if (unm_nic_set_mtu(adapter, adapter->mtu) != 0) {
22767956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22777956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "%s%d: Could not set mtu\n",
22787956Sxiuyan.wang@Sun.COM adapter->name, adapter->instance);
22799436SJing.Xiong@Sun.COM goto stop_and_free;
22807956Sxiuyan.wang@Sun.COM }
22817956Sxiuyan.wang@Sun.COM
22827956Sxiuyan.wang@Sun.COM adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
22837956Sxiuyan.wang@Sun.COM (void *)adapter, 0);
22847956Sxiuyan.wang@Sun.COM
22857956Sxiuyan.wang@Sun.COM adapter->is_up = UNM_ADAPTER_UP_MAGIC;
22867956Sxiuyan.wang@Sun.COM
22877956Sxiuyan.wang@Sun.COM if (adapter->intr_type == DDI_INTR_TYPE_MSI)
22887956Sxiuyan.wang@Sun.COM (void) ddi_intr_block_enable(&adapter->intr_handle, 1);
22897956Sxiuyan.wang@Sun.COM else
22907956Sxiuyan.wang@Sun.COM (void) ddi_intr_enable(adapter->intr_handle);
22917956Sxiuyan.wang@Sun.COM unm_nic_enable_int(adapter);
22927956Sxiuyan.wang@Sun.COM
22937956Sxiuyan.wang@Sun.COM UNM_SPIN_UNLOCK(&adapter->lock);
22947956Sxiuyan.wang@Sun.COM return (GLD_SUCCESS);
22959436SJing.Xiong@Sun.COM
22969436SJing.Xiong@Sun.COM stop_and_free:
22979436SJing.Xiong@Sun.COM unm_nic_stop_port(adapter);
22989436SJing.Xiong@Sun.COM free_hw_res:
22999436SJing.Xiong@Sun.COM unm_free_hw_resources(adapter);
23009436SJing.Xiong@Sun.COM dest_rings:
23019436SJing.Xiong@Sun.COM destroy_rxtx_rings(adapter);
23029436SJing.Xiong@Sun.COM return (DDI_FAILURE);
23037956Sxiuyan.wang@Sun.COM }
23047956Sxiuyan.wang@Sun.COM
23057956Sxiuyan.wang@Sun.COM
23067956Sxiuyan.wang@Sun.COM /*
23077956Sxiuyan.wang@Sun.COM * This code is kept here for reference so as to
23087956Sxiuyan.wang@Sun.COM * see if something different is required to be done
23097956Sxiuyan.wang@Sun.COM * in GLDV3. This will be deleted later.
23107956Sxiuyan.wang@Sun.COM */
23117956Sxiuyan.wang@Sun.COM /* ARGSUSED */
23127956Sxiuyan.wang@Sun.COM static void
ntxn_m_stop(void * arg)23137956Sxiuyan.wang@Sun.COM ntxn_m_stop(void *arg)
23147956Sxiuyan.wang@Sun.COM {
23157956Sxiuyan.wang@Sun.COM }
23167956Sxiuyan.wang@Sun.COM
23177956Sxiuyan.wang@Sun.COM /*ARGSUSED*/
23187956Sxiuyan.wang@Sun.COM static int
ntxn_m_multicst(void * arg,boolean_t add,const uint8_t * ep)23197956Sxiuyan.wang@Sun.COM ntxn_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
23207956Sxiuyan.wang@Sun.COM {
23217956Sxiuyan.wang@Sun.COM /*
23227956Sxiuyan.wang@Sun.COM * When we correctly implement this, invoke nx_p3_nic_set_multi()
23237956Sxiuyan.wang@Sun.COM * or nx_p2_nic_set_multi() here.
23247956Sxiuyan.wang@Sun.COM */
23257956Sxiuyan.wang@Sun.COM return (GLD_SUCCESS);
23267956Sxiuyan.wang@Sun.COM }
23277956Sxiuyan.wang@Sun.COM
23287956Sxiuyan.wang@Sun.COM /*ARGSUSED*/
23297956Sxiuyan.wang@Sun.COM static int
ntxn_m_promisc(void * arg,boolean_t on)23307956Sxiuyan.wang@Sun.COM ntxn_m_promisc(void *arg, boolean_t on)
23317956Sxiuyan.wang@Sun.COM {
23327956Sxiuyan.wang@Sun.COM #if 0
23337956Sxiuyan.wang@Sun.COM int err = 0;
23347956Sxiuyan.wang@Sun.COM struct unm_adapter_s *adapter = arg;
23357956Sxiuyan.wang@Sun.COM
23367956Sxiuyan.wang@Sun.COM err = on ? unm_nic_set_promisc_mode(adapter) :
23377956Sxiuyan.wang@Sun.COM unm_nic_unset_promisc_mode(adapter);
23387956Sxiuyan.wang@Sun.COM
23397956Sxiuyan.wang@Sun.COM if (err)
23407956Sxiuyan.wang@Sun.COM return (GLD_FAILURE);
23417956Sxiuyan.wang@Sun.COM #endif
23427956Sxiuyan.wang@Sun.COM
23437956Sxiuyan.wang@Sun.COM return (GLD_SUCCESS);
23447956Sxiuyan.wang@Sun.COM }
23457956Sxiuyan.wang@Sun.COM
23467956Sxiuyan.wang@Sun.COM static int
ntxn_m_stat(void * arg,uint_t stat,uint64_t * val)23477956Sxiuyan.wang@Sun.COM ntxn_m_stat(void *arg, uint_t stat, uint64_t *val)
23487956Sxiuyan.wang@Sun.COM {
23497956Sxiuyan.wang@Sun.COM struct unm_adapter_s *adapter = arg;
23507956Sxiuyan.wang@Sun.COM struct unm_adapter_stats *portstat = &adapter->stats;
23517956Sxiuyan.wang@Sun.COM
23527956Sxiuyan.wang@Sun.COM switch (stat) {
23537956Sxiuyan.wang@Sun.COM case MAC_STAT_IFSPEED:
23547956Sxiuyan.wang@Sun.COM if (adapter->ahw.board_type == UNM_NIC_XGBE) {
23557956Sxiuyan.wang@Sun.COM /* 10 Gigs */
23567956Sxiuyan.wang@Sun.COM *val = 10000000000ULL;
23577956Sxiuyan.wang@Sun.COM } else {
23587956Sxiuyan.wang@Sun.COM /* 1 Gig */
23597956Sxiuyan.wang@Sun.COM *val = 1000000000;
23607956Sxiuyan.wang@Sun.COM }
23617956Sxiuyan.wang@Sun.COM break;
23627956Sxiuyan.wang@Sun.COM
23637956Sxiuyan.wang@Sun.COM case MAC_STAT_MULTIRCV:
23647956Sxiuyan.wang@Sun.COM *val = 0;
23657956Sxiuyan.wang@Sun.COM break;
23667956Sxiuyan.wang@Sun.COM
23677956Sxiuyan.wang@Sun.COM case MAC_STAT_BRDCSTRCV:
23687956Sxiuyan.wang@Sun.COM case MAC_STAT_BRDCSTXMT:
23697956Sxiuyan.wang@Sun.COM *val = 0;
23707956Sxiuyan.wang@Sun.COM break;
23717956Sxiuyan.wang@Sun.COM
23727956Sxiuyan.wang@Sun.COM case MAC_STAT_NORCVBUF:
23737956Sxiuyan.wang@Sun.COM *val = portstat->updropped;
23747956Sxiuyan.wang@Sun.COM break;
23757956Sxiuyan.wang@Sun.COM
23767956Sxiuyan.wang@Sun.COM case MAC_STAT_NOXMTBUF:
23777956Sxiuyan.wang@Sun.COM *val = portstat->txdropped;
23787956Sxiuyan.wang@Sun.COM break;
23797956Sxiuyan.wang@Sun.COM
23807956Sxiuyan.wang@Sun.COM case MAC_STAT_RBYTES:
23817956Sxiuyan.wang@Sun.COM *val = portstat->rxbytes;
23827956Sxiuyan.wang@Sun.COM break;
23837956Sxiuyan.wang@Sun.COM
23847956Sxiuyan.wang@Sun.COM case MAC_STAT_OBYTES:
23857956Sxiuyan.wang@Sun.COM *val = portstat->txbytes;
23867956Sxiuyan.wang@Sun.COM break;
23877956Sxiuyan.wang@Sun.COM
23887956Sxiuyan.wang@Sun.COM case MAC_STAT_OPACKETS:
23897956Sxiuyan.wang@Sun.COM *val = portstat->xmitedframes;
23907956Sxiuyan.wang@Sun.COM break;
23917956Sxiuyan.wang@Sun.COM
23927956Sxiuyan.wang@Sun.COM case MAC_STAT_IPACKETS:
23937956Sxiuyan.wang@Sun.COM *val = portstat->uphappy;
23947956Sxiuyan.wang@Sun.COM break;
23957956Sxiuyan.wang@Sun.COM
23967956Sxiuyan.wang@Sun.COM case MAC_STAT_OERRORS:
23977956Sxiuyan.wang@Sun.COM *val = portstat->xmitcalled - portstat->xmitedframes;
23987956Sxiuyan.wang@Sun.COM break;
23997956Sxiuyan.wang@Sun.COM
24007956Sxiuyan.wang@Sun.COM case ETHER_STAT_LINK_DUPLEX:
24017956Sxiuyan.wang@Sun.COM *val = LINK_DUPLEX_FULL;
24027956Sxiuyan.wang@Sun.COM break;
24037956Sxiuyan.wang@Sun.COM
24047956Sxiuyan.wang@Sun.COM default:
24057956Sxiuyan.wang@Sun.COM /*
24067956Sxiuyan.wang@Sun.COM * Shouldn't reach here...
24077956Sxiuyan.wang@Sun.COM */
24087956Sxiuyan.wang@Sun.COM *val = 0;
24097956Sxiuyan.wang@Sun.COM DPRINTF(0, (CE_WARN, ": unrecognized parameter = %d, value "
24107956Sxiuyan.wang@Sun.COM "returned 1\n", stat));
24117956Sxiuyan.wang@Sun.COM
24127956Sxiuyan.wang@Sun.COM }
24137956Sxiuyan.wang@Sun.COM
24147956Sxiuyan.wang@Sun.COM return (0);
24157956Sxiuyan.wang@Sun.COM }
24167956Sxiuyan.wang@Sun.COM
24177956Sxiuyan.wang@Sun.COM static int
ntxn_m_unicst(void * arg,const uint8_t * mac)24187956Sxiuyan.wang@Sun.COM ntxn_m_unicst(void *arg, const uint8_t *mac)
24197956Sxiuyan.wang@Sun.COM {
24207956Sxiuyan.wang@Sun.COM struct unm_adapter_s *adapter = arg;
24217956Sxiuyan.wang@Sun.COM
24227956Sxiuyan.wang@Sun.COM DPRINTF(-1, (CE_CONT, "%s: called\n", __func__));
24237956Sxiuyan.wang@Sun.COM
24247956Sxiuyan.wang@Sun.COM if (unm_nic_macaddr_set(adapter, (uint8_t *)mac))
24257956Sxiuyan.wang@Sun.COM return (EAGAIN);
24267956Sxiuyan.wang@Sun.COM bcopy(mac, adapter->mac_addr, ETHERADDRL);
24277956Sxiuyan.wang@Sun.COM
24287956Sxiuyan.wang@Sun.COM return (0);
24297956Sxiuyan.wang@Sun.COM }
24307956Sxiuyan.wang@Sun.COM
24317956Sxiuyan.wang@Sun.COM static mblk_t *
ntxn_m_tx(void * arg,mblk_t * mp)24327956Sxiuyan.wang@Sun.COM ntxn_m_tx(void *arg, mblk_t *mp)
24337956Sxiuyan.wang@Sun.COM {
24347956Sxiuyan.wang@Sun.COM unm_adapter *adapter = arg;
24357956Sxiuyan.wang@Sun.COM mblk_t *next;
24367956Sxiuyan.wang@Sun.COM
24377956Sxiuyan.wang@Sun.COM while (mp != NULL) {
24387956Sxiuyan.wang@Sun.COM next = mp->b_next;
24397956Sxiuyan.wang@Sun.COM mp->b_next = NULL;
24407956Sxiuyan.wang@Sun.COM
24417956Sxiuyan.wang@Sun.COM if (unm_nic_xmit_frame(adapter, mp) != B_TRUE) {
24427956Sxiuyan.wang@Sun.COM mp->b_next = next;
24437956Sxiuyan.wang@Sun.COM break;
24447956Sxiuyan.wang@Sun.COM }
24457956Sxiuyan.wang@Sun.COM mp = next;
24467956Sxiuyan.wang@Sun.COM adapter->stats.xmitedframes++;
24477956Sxiuyan.wang@Sun.COM }
24487956Sxiuyan.wang@Sun.COM
24497956Sxiuyan.wang@Sun.COM return (mp);
24507956Sxiuyan.wang@Sun.COM }
24517956Sxiuyan.wang@Sun.COM
24527956Sxiuyan.wang@Sun.COM static void
ntxn_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)24537956Sxiuyan.wang@Sun.COM ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
24547956Sxiuyan.wang@Sun.COM {
24557956Sxiuyan.wang@Sun.COM int cmd;
24567956Sxiuyan.wang@Sun.COM struct iocblk *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
24577956Sxiuyan.wang@Sun.COM struct unm_adapter_s *adapter = (struct unm_adapter_s *)arg;
24587956Sxiuyan.wang@Sun.COM enum ioc_reply status = IOC_DONE;
24597956Sxiuyan.wang@Sun.COM
24607956Sxiuyan.wang@Sun.COM iocp->ioc_error = 0;
24617956Sxiuyan.wang@Sun.COM cmd = iocp->ioc_cmd;
24627956Sxiuyan.wang@Sun.COM
24637956Sxiuyan.wang@Sun.COM if (cmd == ND_GET || cmd == ND_SET) {
24647956Sxiuyan.wang@Sun.COM status = unm_nd_ioctl(adapter, wq, mp, iocp);
24657956Sxiuyan.wang@Sun.COM switch (status) {
24667956Sxiuyan.wang@Sun.COM default:
24677956Sxiuyan.wang@Sun.COM case IOC_INVAL:
24687956Sxiuyan.wang@Sun.COM miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
24697956Sxiuyan.wang@Sun.COM EINVAL : iocp->ioc_error);
24707956Sxiuyan.wang@Sun.COM break;
24717956Sxiuyan.wang@Sun.COM
24727956Sxiuyan.wang@Sun.COM case IOC_DONE:
24737956Sxiuyan.wang@Sun.COM break;
24747956Sxiuyan.wang@Sun.COM
24757956Sxiuyan.wang@Sun.COM case IOC_RESTART_ACK:
24767956Sxiuyan.wang@Sun.COM case IOC_ACK:
24777956Sxiuyan.wang@Sun.COM miocack(wq, mp, 0, 0);
24787956Sxiuyan.wang@Sun.COM break;
24797956Sxiuyan.wang@Sun.COM
24807956Sxiuyan.wang@Sun.COM case IOC_RESTART_REPLY:
24817956Sxiuyan.wang@Sun.COM case IOC_REPLY:
24827956Sxiuyan.wang@Sun.COM mp->b_datap->db_type = iocp->ioc_error == 0 ?
24837956Sxiuyan.wang@Sun.COM M_IOCACK : M_IOCNAK;
24847956Sxiuyan.wang@Sun.COM qreply(wq, mp);
24857956Sxiuyan.wang@Sun.COM break;
24867956Sxiuyan.wang@Sun.COM }
24877956Sxiuyan.wang@Sun.COM } else if (cmd <= UNM_NIC_NAME && cmd >= UNM_CMD_START) {
24887956Sxiuyan.wang@Sun.COM unm_nic_ioctl(adapter, cmd, wq, mp);
24897956Sxiuyan.wang@Sun.COM return;
24907956Sxiuyan.wang@Sun.COM } else {
24917956Sxiuyan.wang@Sun.COM miocnak(wq, mp, 0, EINVAL);
24927956Sxiuyan.wang@Sun.COM return;
24937956Sxiuyan.wang@Sun.COM }
24947956Sxiuyan.wang@Sun.COM }
24957956Sxiuyan.wang@Sun.COM
24967956Sxiuyan.wang@Sun.COM /* ARGSUSED */
24977956Sxiuyan.wang@Sun.COM static boolean_t
ntxn_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)24987956Sxiuyan.wang@Sun.COM ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
24997956Sxiuyan.wang@Sun.COM {
25007956Sxiuyan.wang@Sun.COM switch (cap) {
25017956Sxiuyan.wang@Sun.COM case MAC_CAPAB_HCKSUM:
25027956Sxiuyan.wang@Sun.COM {
25037956Sxiuyan.wang@Sun.COM uint32_t *txflags = cap_data;
25047956Sxiuyan.wang@Sun.COM
25057956Sxiuyan.wang@Sun.COM *txflags = (HCKSUM_ENABLE |
25067956Sxiuyan.wang@Sun.COM HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM);
25077956Sxiuyan.wang@Sun.COM }
25087956Sxiuyan.wang@Sun.COM break;
25099436SJing.Xiong@Sun.COM
25109436SJing.Xiong@Sun.COM #ifdef SOLARIS11
25119436SJing.Xiong@Sun.COM case MAC_CAPAB_ANCHOR_VNIC:
25129436SJing.Xiong@Sun.COM case MAC_CAPAB_MULTIFACTADDR:
25139436SJing.Xiong@Sun.COM #else
25149436SJing.Xiong@Sun.COM case MAC_CAPAB_POLL:
25159436SJing.Xiong@Sun.COM case MAC_CAPAB_MULTIADDRESS:
25169436SJing.Xiong@Sun.COM #endif
25177956Sxiuyan.wang@Sun.COM default:
25187956Sxiuyan.wang@Sun.COM return (B_FALSE);
25197956Sxiuyan.wang@Sun.COM }
25207956Sxiuyan.wang@Sun.COM
25217956Sxiuyan.wang@Sun.COM return (B_TRUE);
25227956Sxiuyan.wang@Sun.COM }
25237956Sxiuyan.wang@Sun.COM
25247956Sxiuyan.wang@Sun.COM #define NETXEN_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
25257956Sxiuyan.wang@Sun.COM
25267956Sxiuyan.wang@Sun.COM static mac_callbacks_t ntxn_m_callbacks = {
25277956Sxiuyan.wang@Sun.COM NETXEN_M_CALLBACK_FLAGS,
25287956Sxiuyan.wang@Sun.COM ntxn_m_stat,
25297956Sxiuyan.wang@Sun.COM ntxn_m_start,
25307956Sxiuyan.wang@Sun.COM ntxn_m_stop,
25317956Sxiuyan.wang@Sun.COM ntxn_m_promisc,
25327956Sxiuyan.wang@Sun.COM ntxn_m_multicst,
25337956Sxiuyan.wang@Sun.COM ntxn_m_unicst,
25347956Sxiuyan.wang@Sun.COM ntxn_m_tx,
2535*11878SVenu.Iyer@Sun.COM NULL, /* mc_reserved */
25367956Sxiuyan.wang@Sun.COM ntxn_m_ioctl,
25377956Sxiuyan.wang@Sun.COM ntxn_m_getcapab,
25387956Sxiuyan.wang@Sun.COM NULL, /* mc_open */
25397956Sxiuyan.wang@Sun.COM NULL, /* mc_close */
25407956Sxiuyan.wang@Sun.COM NULL, /* mc_setprop */
25417956Sxiuyan.wang@Sun.COM NULL /* mc_getprop */
25427956Sxiuyan.wang@Sun.COM };
25437956Sxiuyan.wang@Sun.COM
25447956Sxiuyan.wang@Sun.COM int
unm_register_mac(unm_adapter * adapter)25457956Sxiuyan.wang@Sun.COM unm_register_mac(unm_adapter *adapter)
25467956Sxiuyan.wang@Sun.COM {
25477956Sxiuyan.wang@Sun.COM int ret;
25487956Sxiuyan.wang@Sun.COM mac_register_t *macp;
25497956Sxiuyan.wang@Sun.COM unm_pauseparam_t pause;
25507956Sxiuyan.wang@Sun.COM
25517956Sxiuyan.wang@Sun.COM dev_info_t *dip = adapter->dip;
25527956Sxiuyan.wang@Sun.COM
25537956Sxiuyan.wang@Sun.COM if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
25547956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "Memory not available\n");
25557956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
25567956Sxiuyan.wang@Sun.COM }
25577956Sxiuyan.wang@Sun.COM
25587956Sxiuyan.wang@Sun.COM macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25597956Sxiuyan.wang@Sun.COM macp->m_driver = adapter;
25607956Sxiuyan.wang@Sun.COM macp->m_dip = dip;
25617956Sxiuyan.wang@Sun.COM macp->m_instance = adapter->instance;
25627956Sxiuyan.wang@Sun.COM macp->m_src_addr = adapter->mac_addr;
25637956Sxiuyan.wang@Sun.COM macp->m_callbacks = &ntxn_m_callbacks;
25647956Sxiuyan.wang@Sun.COM macp->m_min_sdu = 0;
25657956Sxiuyan.wang@Sun.COM macp->m_max_sdu = adapter->mtu;
25667956Sxiuyan.wang@Sun.COM #ifdef SOLARIS11
25677956Sxiuyan.wang@Sun.COM macp->m_margin = VLAN_TAGSZ;
25687956Sxiuyan.wang@Sun.COM #endif /* SOLARIS11 */
25697956Sxiuyan.wang@Sun.COM
25707956Sxiuyan.wang@Sun.COM ret = mac_register(macp, &adapter->mach);
25717956Sxiuyan.wang@Sun.COM mac_free(macp);
25727956Sxiuyan.wang@Sun.COM if (ret != 0) {
25737956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "mac_register failed for port %d\n",
25747956Sxiuyan.wang@Sun.COM adapter->portnum);
25757956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
25767956Sxiuyan.wang@Sun.COM }
25777956Sxiuyan.wang@Sun.COM
25787956Sxiuyan.wang@Sun.COM unm_init_kstats(adapter, adapter->instance);
25797956Sxiuyan.wang@Sun.COM
25807956Sxiuyan.wang@Sun.COM /* Register NDD-tweakable parameters */
25817956Sxiuyan.wang@Sun.COM if (unm_nd_init(adapter)) {
25827956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "unm_nd_init() failed");
25837956Sxiuyan.wang@Sun.COM return (DDI_FAILURE);
25847956Sxiuyan.wang@Sun.COM }
25857956Sxiuyan.wang@Sun.COM
25867956Sxiuyan.wang@Sun.COM pause.rx_pause = adapter->nd_params[PARAM_ADV_PAUSE_CAP].ndp_val;
25877956Sxiuyan.wang@Sun.COM pause.tx_pause = adapter->nd_params[PARAM_ADV_ASYM_PAUSE_CAP].ndp_val;
25887956Sxiuyan.wang@Sun.COM
25897956Sxiuyan.wang@Sun.COM if (unm_nic_set_pauseparam(adapter, &pause)) {
25907956Sxiuyan.wang@Sun.COM cmn_err(CE_WARN, "\nBad Pause settings RX %d, Tx %d",
25917956Sxiuyan.wang@Sun.COM pause.rx_pause, pause.tx_pause);
25927956Sxiuyan.wang@Sun.COM }
25937956Sxiuyan.wang@Sun.COM adapter->nd_params[PARAM_PAUSE_CAP].ndp_val = pause.rx_pause;
25947956Sxiuyan.wang@Sun.COM adapter->nd_params[PARAM_ASYM_PAUSE_CAP].ndp_val = pause.tx_pause;
25957956Sxiuyan.wang@Sun.COM
25967956Sxiuyan.wang@Sun.COM return (DDI_SUCCESS);
25977956Sxiuyan.wang@Sun.COM }
2598