xref: /onnv-gate/usr/src/uts/common/io/hxge/hxge_main.c (revision 7918:6740213a4e67)
16349Sqs148142 /*
26349Sqs148142  * CDDL HEADER START
36349Sqs148142  *
46349Sqs148142  * The contents of this file are subject to the terms of the
56349Sqs148142  * Common Development and Distribution License (the "License").
66349Sqs148142  * You may not use this file except in compliance with the License.
76349Sqs148142  *
86349Sqs148142  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96349Sqs148142  * or http://www.opensolaris.org/os/licensing.
106349Sqs148142  * See the License for the specific language governing permissions
116349Sqs148142  * and limitations under the License.
126349Sqs148142  *
136349Sqs148142  * When distributing Covered Code, include this CDDL HEADER in each
146349Sqs148142  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156349Sqs148142  * If applicable, add the following below this CDDL HEADER, with the
166349Sqs148142  * fields enclosed by brackets "[]" replaced with your own identifying
176349Sqs148142  * information: Portions Copyright [yyyy] [name of copyright owner]
186349Sqs148142  *
196349Sqs148142  * CDDL HEADER END
206349Sqs148142  */
216349Sqs148142 /*
226349Sqs148142  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
236349Sqs148142  * Use is subject to license terms.
246349Sqs148142  */
256349Sqs148142 
266349Sqs148142 /*
276349Sqs148142  * SunOs MT STREAMS Hydra 10Gb Ethernet Device Driver.
286349Sqs148142  */
296349Sqs148142 #include <hxge_impl.h>
306349Sqs148142 #include <hxge_pfc.h>
316349Sqs148142 
326349Sqs148142 /*
336349Sqs148142  * PSARC/2007/453 MSI-X interrupt limit override
346349Sqs148142  * (This PSARC case is limited to MSI-X vectors
356349Sqs148142  *  and SPARC platforms only).
366349Sqs148142  */
376349Sqs148142 #if defined(_BIG_ENDIAN)
386349Sqs148142 uint32_t hxge_msi_enable = 2;
396349Sqs148142 #else
406349Sqs148142 uint32_t hxge_msi_enable = 1;
416349Sqs148142 #endif
426349Sqs148142 
436349Sqs148142 /*
446349Sqs148142  * Globals: tunable parameters (/etc/system or adb)
456349Sqs148142  *
466349Sqs148142  */
476349Sqs148142 uint32_t hxge_rbr_size = HXGE_RBR_RBB_DEFAULT;
486349Sqs148142 uint32_t hxge_rbr_spare_size = 0;
496349Sqs148142 uint32_t hxge_rcr_size = HXGE_RCR_DEFAULT;
506349Sqs148142 uint32_t hxge_tx_ring_size = HXGE_TX_RING_DEFAULT;
516349Sqs148142 uint32_t hxge_bcopy_thresh = TX_BCOPY_MAX;
526349Sqs148142 uint32_t hxge_dvma_thresh = TX_FASTDVMA_MIN;
536349Sqs148142 uint32_t hxge_dma_stream_thresh = TX_STREAM_MIN;
547584SQiyan.Sun@Sun.COM uint32_t hxge_jumbo_frame_size = MAX_FRAME_SIZE;
556349Sqs148142 
566349Sqs148142 static hxge_os_mutex_t hxgedebuglock;
576349Sqs148142 static int hxge_debug_init = 0;
586349Sqs148142 
596349Sqs148142 /*
606349Sqs148142  * Debugging flags:
616349Sqs148142  *		hxge_no_tx_lb : transmit load balancing
626349Sqs148142  *		hxge_tx_lb_policy: 0 - TCP/UDP port (default)
636349Sqs148142  *				   1 - From the Stack
646349Sqs148142  *				   2 - Destination IP Address
656349Sqs148142  */
666349Sqs148142 uint32_t hxge_no_tx_lb = 0;
676349Sqs148142 uint32_t hxge_tx_lb_policy = HXGE_TX_LB_TCPUDP;
686349Sqs148142 
696349Sqs148142 /*
706349Sqs148142  * Add tunable to reduce the amount of time spent in the
716349Sqs148142  * ISR doing Rx Processing.
726349Sqs148142  */
736349Sqs148142 uint32_t hxge_max_rx_pkts = 1024;
746349Sqs148142 
756349Sqs148142 /*
766349Sqs148142  * Tunables to manage the receive buffer blocks.
776349Sqs148142  *
786349Sqs148142  * hxge_rx_threshold_hi: copy all buffers.
796349Sqs148142  * hxge_rx_bcopy_size_type: receive buffer block size type.
806349Sqs148142  * hxge_rx_threshold_lo: copy only up to tunable block size type.
816349Sqs148142  */
826349Sqs148142 hxge_rxbuf_threshold_t hxge_rx_threshold_hi = HXGE_RX_COPY_6;
836349Sqs148142 hxge_rxbuf_type_t hxge_rx_buf_size_type = RCR_PKTBUFSZ_0;
846349Sqs148142 hxge_rxbuf_threshold_t hxge_rx_threshold_lo = HXGE_RX_COPY_3;
856349Sqs148142 
866349Sqs148142 rtrace_t hpi_rtracebuf;
876349Sqs148142 
886349Sqs148142 /*
896349Sqs148142  * Function Prototypes
906349Sqs148142  */
916349Sqs148142 static int hxge_attach(dev_info_t *, ddi_attach_cmd_t);
926349Sqs148142 static int hxge_detach(dev_info_t *, ddi_detach_cmd_t);
936349Sqs148142 static void hxge_unattach(p_hxge_t);
946349Sqs148142 
956349Sqs148142 static hxge_status_t hxge_setup_system_dma_pages(p_hxge_t);
966349Sqs148142 
976349Sqs148142 static hxge_status_t hxge_setup_mutexes(p_hxge_t);
986349Sqs148142 static void hxge_destroy_mutexes(p_hxge_t);
996349Sqs148142 
1006349Sqs148142 static hxge_status_t hxge_map_regs(p_hxge_t hxgep);
1016349Sqs148142 static void hxge_unmap_regs(p_hxge_t hxgep);
1026349Sqs148142 
1036349Sqs148142 hxge_status_t hxge_add_intrs(p_hxge_t hxgep);
1046349Sqs148142 static hxge_status_t hxge_add_soft_intrs(p_hxge_t hxgep);
1056349Sqs148142 static void hxge_remove_intrs(p_hxge_t hxgep);
1066349Sqs148142 static void hxge_remove_soft_intrs(p_hxge_t hxgep);
1076349Sqs148142 static hxge_status_t hxge_add_intrs_adv(p_hxge_t hxgep);
1086349Sqs148142 static hxge_status_t hxge_add_intrs_adv_type(p_hxge_t, uint32_t);
1096349Sqs148142 static hxge_status_t hxge_add_intrs_adv_type_fix(p_hxge_t, uint32_t);
1106349Sqs148142 void hxge_intrs_enable(p_hxge_t hxgep);
1116349Sqs148142 static void hxge_intrs_disable(p_hxge_t hxgep);
1126349Sqs148142 static void hxge_suspend(p_hxge_t);
1136349Sqs148142 static hxge_status_t hxge_resume(p_hxge_t);
1146349Sqs148142 hxge_status_t hxge_setup_dev(p_hxge_t);
1156349Sqs148142 static void hxge_destroy_dev(p_hxge_t);
1166349Sqs148142 hxge_status_t hxge_alloc_mem_pool(p_hxge_t);
1176349Sqs148142 static void hxge_free_mem_pool(p_hxge_t);
1186349Sqs148142 static hxge_status_t hxge_alloc_rx_mem_pool(p_hxge_t);
1196349Sqs148142 static void hxge_free_rx_mem_pool(p_hxge_t);
1206349Sqs148142 static hxge_status_t hxge_alloc_tx_mem_pool(p_hxge_t);
1216349Sqs148142 static void hxge_free_tx_mem_pool(p_hxge_t);
1226349Sqs148142 static hxge_status_t hxge_dma_mem_alloc(p_hxge_t, dma_method_t,
1236349Sqs148142     struct ddi_dma_attr *, size_t, ddi_device_acc_attr_t *, uint_t,
1246349Sqs148142     p_hxge_dma_common_t);
1256349Sqs148142 static void hxge_dma_mem_free(p_hxge_dma_common_t);
1266349Sqs148142 static hxge_status_t hxge_alloc_rx_buf_dma(p_hxge_t, uint16_t,
1276349Sqs148142     p_hxge_dma_common_t *, size_t, size_t, uint32_t *);
1286349Sqs148142 static void hxge_free_rx_buf_dma(p_hxge_t, p_hxge_dma_common_t, uint32_t);
1296349Sqs148142 static hxge_status_t hxge_alloc_rx_cntl_dma(p_hxge_t, uint16_t,
1307618SMichael.Speer@Sun.COM     p_hxge_dma_common_t *, struct ddi_dma_attr *, size_t);
1316349Sqs148142 static void hxge_free_rx_cntl_dma(p_hxge_t, p_hxge_dma_common_t);
1326349Sqs148142 static hxge_status_t hxge_alloc_tx_buf_dma(p_hxge_t, uint16_t,
1336349Sqs148142     p_hxge_dma_common_t *, size_t, size_t, uint32_t *);
1346349Sqs148142 static void hxge_free_tx_buf_dma(p_hxge_t, p_hxge_dma_common_t, uint32_t);
1356349Sqs148142 static hxge_status_t hxge_alloc_tx_cntl_dma(p_hxge_t, uint16_t,
1366349Sqs148142     p_hxge_dma_common_t *, size_t);
1376349Sqs148142 static void hxge_free_tx_cntl_dma(p_hxge_t, p_hxge_dma_common_t);
1386349Sqs148142 static int hxge_init_common_dev(p_hxge_t);
1396349Sqs148142 static void hxge_uninit_common_dev(p_hxge_t);
1406349Sqs148142 
1416349Sqs148142 /*
1426349Sqs148142  * The next declarations are for the GLDv3 interface.
1436349Sqs148142  */
1446349Sqs148142 static int hxge_m_start(void *);
1456349Sqs148142 static void hxge_m_stop(void *);
1466349Sqs148142 static int hxge_m_unicst(void *, const uint8_t *);
1476349Sqs148142 static int hxge_m_multicst(void *, boolean_t, const uint8_t *);
1486349Sqs148142 static int hxge_m_promisc(void *, boolean_t);
1496349Sqs148142 static void hxge_m_ioctl(void *, queue_t *, mblk_t *);
1506349Sqs148142 static void hxge_m_resources(void *);
1516349Sqs148142 static hxge_status_t hxge_mac_register(p_hxge_t hxgep);
1526349Sqs148142 
1536349Sqs148142 static int hxge_m_mmac_add(void *arg, mac_multi_addr_t *maddr);
1546349Sqs148142 static int hxge_m_mmac_remove(void *arg, mac_addr_slot_t slot);
1556349Sqs148142 static int hxge_m_mmac_modify(void *arg, mac_multi_addr_t *maddr);
1566349Sqs148142 static int hxge_m_mmac_get(void *arg, mac_multi_addr_t *maddr);
1576349Sqs148142 static boolean_t hxge_m_getcapab(void *, mac_capab_t, void *);
1587584SQiyan.Sun@Sun.COM static boolean_t hxge_param_locked(mac_prop_id_t pr_num);
1597584SQiyan.Sun@Sun.COM static int hxge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1607584SQiyan.Sun@Sun.COM     uint_t pr_valsize, const void *pr_val);
1617584SQiyan.Sun@Sun.COM static int hxge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1627584SQiyan.Sun@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val);
1637584SQiyan.Sun@Sun.COM static int hxge_get_def_val(hxge_t *hxgep, mac_prop_id_t pr_num,
1647584SQiyan.Sun@Sun.COM     uint_t pr_valsize, void *pr_val);
1657584SQiyan.Sun@Sun.COM static int hxge_set_priv_prop(p_hxge_t hxgep, const char *pr_name,
1667584SQiyan.Sun@Sun.COM     uint_t pr_valsize, const void *pr_val);
1677584SQiyan.Sun@Sun.COM static int hxge_get_priv_prop(p_hxge_t hxgep, const char *pr_name,
1687584SQiyan.Sun@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val);
1697584SQiyan.Sun@Sun.COM static void hxge_link_poll(void *arg);
1707584SQiyan.Sun@Sun.COM 
1717584SQiyan.Sun@Sun.COM mac_priv_prop_t hxge_priv_props[] = {
1727584SQiyan.Sun@Sun.COM 	{"_rxdma_intr_time", MAC_PROP_PERM_RW},
1737584SQiyan.Sun@Sun.COM 	{"_rxdma_intr_pkts", MAC_PROP_PERM_RW},
1747584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv4_tcp", MAC_PROP_PERM_RW},
1757584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv4_udp", MAC_PROP_PERM_RW},
1767584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv4_ah", MAC_PROP_PERM_RW},
1777584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv4_sctp", MAC_PROP_PERM_RW},
1787584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv6_tcp", MAC_PROP_PERM_RW},
1797584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv6_udp", MAC_PROP_PERM_RW},
1807584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv6_ah", MAC_PROP_PERM_RW},
1817584SQiyan.Sun@Sun.COM 	{"_class_opt_ipv6_sctp", MAC_PROP_PERM_RW}
1827584SQiyan.Sun@Sun.COM };
1837584SQiyan.Sun@Sun.COM 
1847584SQiyan.Sun@Sun.COM #define	HXGE_MAX_PRIV_PROPS	\
1857584SQiyan.Sun@Sun.COM 	(sizeof (hxge_priv_props)/sizeof (mac_priv_prop_t))
1866349Sqs148142 
1876349Sqs148142 #define	HXGE_MAGIC	0x4E584745UL
1886349Sqs148142 #define	MAX_DUMP_SZ 256
1896349Sqs148142 
1907584SQiyan.Sun@Sun.COM #define	HXGE_M_CALLBACK_FLAGS	\
1917584SQiyan.Sun@Sun.COM 	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
1926349Sqs148142 
1936349Sqs148142 extern mblk_t *hxge_m_tx(void *arg, mblk_t *mp);
1946349Sqs148142 extern hxge_status_t hxge_pfc_set_default_mac_addr(p_hxge_t hxgep);
1956349Sqs148142 
1966349Sqs148142 static mac_callbacks_t hxge_m_callbacks = {
1976349Sqs148142 	HXGE_M_CALLBACK_FLAGS,
1986349Sqs148142 	hxge_m_stat,
1996349Sqs148142 	hxge_m_start,
2006349Sqs148142 	hxge_m_stop,
2016349Sqs148142 	hxge_m_promisc,
2026349Sqs148142 	hxge_m_multicst,
2036349Sqs148142 	hxge_m_unicst,
2046349Sqs148142 	hxge_m_tx,
2056349Sqs148142 	hxge_m_resources,
2066349Sqs148142 	hxge_m_ioctl,
2077584SQiyan.Sun@Sun.COM 	hxge_m_getcapab,
2087584SQiyan.Sun@Sun.COM 	NULL,
2097584SQiyan.Sun@Sun.COM 	NULL,
2107584SQiyan.Sun@Sun.COM 	hxge_m_setprop,
2117584SQiyan.Sun@Sun.COM 	hxge_m_getprop
2126349Sqs148142 };
2136349Sqs148142 
2146349Sqs148142 /* Enable debug messages as necessary. */
2157584SQiyan.Sun@Sun.COM uint64_t hxge_debug_level = 0;
2166349Sqs148142 
2176349Sqs148142 /*
2186349Sqs148142  * This list contains the instance structures for the Hydra
2196349Sqs148142  * devices present in the system. The lock exists to guarantee
2206349Sqs148142  * mutually exclusive access to the list.
2216349Sqs148142  */
2226349Sqs148142 void *hxge_list = NULL;
2236349Sqs148142 void *hxge_hw_list = NULL;
2246349Sqs148142 hxge_os_mutex_t hxge_common_lock;
2256349Sqs148142 
2266349Sqs148142 extern uint64_t hpi_debug_level;
2276349Sqs148142 
2286349Sqs148142 extern hxge_status_t hxge_ldgv_init();
2296349Sqs148142 extern hxge_status_t hxge_ldgv_uninit();
2306349Sqs148142 extern hxge_status_t hxge_intr_ldgv_init();
2316349Sqs148142 extern void hxge_fm_init(p_hxge_t hxgep, ddi_device_acc_attr_t *reg_attr,
2326349Sqs148142     ddi_device_acc_attr_t *desc_attr, ddi_dma_attr_t *dma_attr);
2336349Sqs148142 extern void hxge_fm_fini(p_hxge_t hxgep);
2346349Sqs148142 
2356349Sqs148142 /*
2366349Sqs148142  * Count used to maintain the number of buffers being used
2376349Sqs148142  * by Hydra instances and loaned up to the upper layers.
2386349Sqs148142  */
2396349Sqs148142 uint32_t hxge_mblks_pending = 0;
2406349Sqs148142 
2416349Sqs148142 /*
2426349Sqs148142  * Device register access attributes for PIO.
2436349Sqs148142  */
2446349Sqs148142 static ddi_device_acc_attr_t hxge_dev_reg_acc_attr = {
2456349Sqs148142 	DDI_DEVICE_ATTR_V0,
2466349Sqs148142 	DDI_STRUCTURE_LE_ACC,
2476349Sqs148142 	DDI_STRICTORDER_ACC,
2486349Sqs148142 };
2496349Sqs148142 
2506349Sqs148142 /*
2516349Sqs148142  * Device descriptor access attributes for DMA.
2526349Sqs148142  */
2536349Sqs148142 static ddi_device_acc_attr_t hxge_dev_desc_dma_acc_attr = {
2546349Sqs148142 	DDI_DEVICE_ATTR_V0,
2556349Sqs148142 	DDI_STRUCTURE_LE_ACC,
2566349Sqs148142 	DDI_STRICTORDER_ACC
2576349Sqs148142 };
2586349Sqs148142 
2596349Sqs148142 /*
2606349Sqs148142  * Device buffer access attributes for DMA.
2616349Sqs148142  */
2626349Sqs148142 static ddi_device_acc_attr_t hxge_dev_buf_dma_acc_attr = {
2636349Sqs148142 	DDI_DEVICE_ATTR_V0,
2646349Sqs148142 	DDI_STRUCTURE_BE_ACC,
2656349Sqs148142 	DDI_STRICTORDER_ACC
2666349Sqs148142 };
2676349Sqs148142 
2687618SMichael.Speer@Sun.COM ddi_dma_attr_t hxge_rx_rcr_desc_dma_attr = {
2697618SMichael.Speer@Sun.COM 	DMA_ATTR_V0,		/* version number. */
2707618SMichael.Speer@Sun.COM 	0,			/* low address */
2717618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* high address */
2727618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* address counter max */
2737618SMichael.Speer@Sun.COM 	0x80000,		/* alignment */
2747618SMichael.Speer@Sun.COM 	0xfc00fc,		/* dlim_burstsizes */
2757618SMichael.Speer@Sun.COM 	0x1,			/* minimum transfer size */
2767618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum transfer size */
2777618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum segment size */
2787618SMichael.Speer@Sun.COM 	1,			/* scatter/gather list length */
2797618SMichael.Speer@Sun.COM 	(unsigned int)1,	/* granularity */
2807618SMichael.Speer@Sun.COM 	0			/* attribute flags */
2817618SMichael.Speer@Sun.COM };
2827618SMichael.Speer@Sun.COM 
2837618SMichael.Speer@Sun.COM ddi_dma_attr_t hxge_tx_desc_dma_attr = {
2846349Sqs148142 	DMA_ATTR_V0,		/* version number. */
2856349Sqs148142 	0,			/* low address */
2866349Sqs148142 	0xffffffffffffffff,	/* high address */
2876349Sqs148142 	0xffffffffffffffff,	/* address counter max */
2886349Sqs148142 	0x100000,		/* alignment */
2896349Sqs148142 	0xfc00fc,		/* dlim_burstsizes */
2906349Sqs148142 	0x1,			/* minimum transfer size */
2916349Sqs148142 	0xffffffffffffffff,	/* maximum transfer size */
2926349Sqs148142 	0xffffffffffffffff,	/* maximum segment size */
2936349Sqs148142 	1,			/* scatter/gather list length */
2946349Sqs148142 	(unsigned int)1,	/* granularity */
2956349Sqs148142 	0			/* attribute flags */
2966349Sqs148142 };
2976349Sqs148142 
2987618SMichael.Speer@Sun.COM ddi_dma_attr_t hxge_rx_rbr_desc_dma_attr = {
2997618SMichael.Speer@Sun.COM 	DMA_ATTR_V0,		/* version number. */
3007618SMichael.Speer@Sun.COM 	0,			/* low address */
3017618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* high address */
3027618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* address counter max */
3037618SMichael.Speer@Sun.COM 	0x40000,		/* alignment */
3047618SMichael.Speer@Sun.COM 	0xfc00fc,		/* dlim_burstsizes */
3057618SMichael.Speer@Sun.COM 	0x1,			/* minimum transfer size */
3067618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum transfer size */
3077618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum segment size */
3087618SMichael.Speer@Sun.COM 	1,			/* scatter/gather list length */
3097618SMichael.Speer@Sun.COM 	(unsigned int)1,	/* granularity */
3107618SMichael.Speer@Sun.COM 	0			/* attribute flags */
3117618SMichael.Speer@Sun.COM };
3127618SMichael.Speer@Sun.COM 
3137618SMichael.Speer@Sun.COM ddi_dma_attr_t hxge_rx_mbox_dma_attr = {
3147618SMichael.Speer@Sun.COM 	DMA_ATTR_V0,		/* version number. */
3157618SMichael.Speer@Sun.COM 	0,			/* low address */
3167618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* high address */
3177618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* address counter max */
3187618SMichael.Speer@Sun.COM #if defined(_BIG_ENDIAN)
3197618SMichael.Speer@Sun.COM 	0x2000,			/* alignment */
3207618SMichael.Speer@Sun.COM #else
3217618SMichael.Speer@Sun.COM 	0x1000,			/* alignment */
3227618SMichael.Speer@Sun.COM #endif
3237618SMichael.Speer@Sun.COM 	0xfc00fc,		/* dlim_burstsizes */
3247618SMichael.Speer@Sun.COM 	0x1,			/* minimum transfer size */
3257618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum transfer size */
3267618SMichael.Speer@Sun.COM 	0xffffffffffffffff,	/* maximum segment size */
3277618SMichael.Speer@Sun.COM 	5,			/* scatter/gather list length */
3287618SMichael.Speer@Sun.COM 	(unsigned int)1,	/* granularity */
3297618SMichael.Speer@Sun.COM 	0			/* attribute flags */
3307618SMichael.Speer@Sun.COM };
3317618SMichael.Speer@Sun.COM 
3326349Sqs148142 ddi_dma_attr_t hxge_tx_dma_attr = {
3336349Sqs148142 	DMA_ATTR_V0,		/* version number. */
3346349Sqs148142 	0,			/* low address */
3356349Sqs148142 	0xffffffffffffffff,	/* high address */
3366349Sqs148142 	0xffffffffffffffff,	/* address counter max */
3376349Sqs148142 #if defined(_BIG_ENDIAN)
3386349Sqs148142 	0x2000,			/* alignment */
3396349Sqs148142 #else
3406349Sqs148142 	0x1000,			/* alignment */
3416349Sqs148142 #endif
3426349Sqs148142 	0xfc00fc,		/* dlim_burstsizes */
3436349Sqs148142 	0x1,			/* minimum transfer size */
3446349Sqs148142 	0xffffffffffffffff,	/* maximum transfer size */
3456349Sqs148142 	0xffffffffffffffff,	/* maximum segment size */
3466349Sqs148142 	5,			/* scatter/gather list length */
3476349Sqs148142 	(unsigned int)1,	/* granularity */
3486349Sqs148142 	0			/* attribute flags */
3496349Sqs148142 };
3506349Sqs148142 
3516349Sqs148142 ddi_dma_attr_t hxge_rx_dma_attr = {
3526349Sqs148142 	DMA_ATTR_V0,		/* version number. */
3536349Sqs148142 	0,			/* low address */
3546349Sqs148142 	0xffffffffffffffff,	/* high address */
3556349Sqs148142 	0xffffffffffffffff,	/* address counter max */
3566349Sqs148142 	0x10000,		/* alignment */
3576349Sqs148142 	0xfc00fc,		/* dlim_burstsizes */
3586349Sqs148142 	0x1,			/* minimum transfer size */
3596349Sqs148142 	0xffffffffffffffff,	/* maximum transfer size */
3606349Sqs148142 	0xffffffffffffffff,	/* maximum segment size */
3616349Sqs148142 	1,			/* scatter/gather list length */
3626349Sqs148142 	(unsigned int)1,	/* granularity */
3636349Sqs148142 	DDI_DMA_RELAXED_ORDERING /* attribute flags */
3646349Sqs148142 };
3656349Sqs148142 
3666349Sqs148142 ddi_dma_lim_t hxge_dma_limits = {
3676349Sqs148142 	(uint_t)0,		/* dlim_addr_lo */
3686349Sqs148142 	(uint_t)0xffffffff,	/* dlim_addr_hi */
3696349Sqs148142 	(uint_t)0xffffffff,	/* dlim_cntr_max */
3706349Sqs148142 	(uint_t)0xfc00fc,	/* dlim_burstsizes for 32 and 64 bit xfers */
3716349Sqs148142 	0x1,			/* dlim_minxfer */
3726349Sqs148142 	1024			/* dlim_speed */
3736349Sqs148142 };
3746349Sqs148142 
3756349Sqs148142 dma_method_t hxge_force_dma = DVMA;
3766349Sqs148142 
3776349Sqs148142 /*
3786349Sqs148142  * dma chunk sizes.
3796349Sqs148142  *
3806349Sqs148142  * Try to allocate the largest possible size
3816349Sqs148142  * so that fewer number of dma chunks would be managed
3826349Sqs148142  */
3836349Sqs148142 size_t alloc_sizes[] = {
3846349Sqs148142     0x1000, 0x2000, 0x4000, 0x8000,
3856349Sqs148142     0x10000, 0x20000, 0x40000, 0x80000,
3866349Sqs148142     0x100000, 0x200000, 0x400000, 0x800000, 0x1000000
3876349Sqs148142 };
3886349Sqs148142 
3896349Sqs148142 /*
3906349Sqs148142  * Translate "dev_t" to a pointer to the associated "dev_info_t".
3916349Sqs148142  */
3926349Sqs148142 static int
3936349Sqs148142 hxge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3946349Sqs148142 {
3956349Sqs148142 	p_hxge_t	hxgep = NULL;
3966349Sqs148142 	int		instance;
3976349Sqs148142 	int		status = DDI_SUCCESS;
3986349Sqs148142 
3996349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_attach"));
4006349Sqs148142 
4016349Sqs148142 	/*
4026349Sqs148142 	 * Get the device instance since we'll need to setup or retrieve a soft
4036349Sqs148142 	 * state for this instance.
4046349Sqs148142 	 */
4056349Sqs148142 	instance = ddi_get_instance(dip);
4066349Sqs148142 
4076349Sqs148142 	switch (cmd) {
4086349Sqs148142 	case DDI_ATTACH:
4096349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_ATTACH"));
4106349Sqs148142 		break;
4116349Sqs148142 
4126349Sqs148142 	case DDI_RESUME:
4136349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_RESUME"));
4146349Sqs148142 		hxgep = (p_hxge_t)ddi_get_soft_state(hxge_list, instance);
4156349Sqs148142 		if (hxgep == NULL) {
4166349Sqs148142 			status = DDI_FAILURE;
4176349Sqs148142 			break;
4186349Sqs148142 		}
4196349Sqs148142 		if (hxgep->dip != dip) {
4206349Sqs148142 			status = DDI_FAILURE;
4216349Sqs148142 			break;
4226349Sqs148142 		}
4236349Sqs148142 		if (hxgep->suspended == DDI_PM_SUSPEND) {
4246349Sqs148142 			status = ddi_dev_is_needed(hxgep->dip, 0, 1);
4256349Sqs148142 		} else {
4266349Sqs148142 			(void) hxge_resume(hxgep);
4276349Sqs148142 		}
4286349Sqs148142 		goto hxge_attach_exit;
4296349Sqs148142 
4306349Sqs148142 	case DDI_PM_RESUME:
4316349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_PM_RESUME"));
4326349Sqs148142 		hxgep = (p_hxge_t)ddi_get_soft_state(hxge_list, instance);
4336349Sqs148142 		if (hxgep == NULL) {
4346349Sqs148142 			status = DDI_FAILURE;
4356349Sqs148142 			break;
4366349Sqs148142 		}
4376349Sqs148142 		if (hxgep->dip != dip) {
4386349Sqs148142 			status = DDI_FAILURE;
4396349Sqs148142 			break;
4406349Sqs148142 		}
4416349Sqs148142 		(void) hxge_resume(hxgep);
4426349Sqs148142 		goto hxge_attach_exit;
4436349Sqs148142 
4446349Sqs148142 	default:
4456349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing unknown"));
4466349Sqs148142 		status = DDI_FAILURE;
4476349Sqs148142 		goto hxge_attach_exit;
4486349Sqs148142 	}
4496349Sqs148142 
4506349Sqs148142 	if (ddi_soft_state_zalloc(hxge_list, instance) == DDI_FAILURE) {
4516349Sqs148142 		status = DDI_FAILURE;
4526349Sqs148142 		HXGE_ERROR_MSG((hxgep, DDI_CTL,
4536349Sqs148142 		    "ddi_soft_state_zalloc failed"));
4546349Sqs148142 		goto hxge_attach_exit;
4556349Sqs148142 	}
4566349Sqs148142 
4576349Sqs148142 	hxgep = ddi_get_soft_state(hxge_list, instance);
4586349Sqs148142 	if (hxgep == NULL) {
4596349Sqs148142 		status = HXGE_ERROR;
4606349Sqs148142 		HXGE_ERROR_MSG((hxgep, DDI_CTL,
4616349Sqs148142 		    "ddi_get_soft_state failed"));
4626349Sqs148142 		goto hxge_attach_fail2;
4636349Sqs148142 	}
4646349Sqs148142 
4656349Sqs148142 	hxgep->drv_state = 0;
4666349Sqs148142 	hxgep->dip = dip;
4676349Sqs148142 	hxgep->instance = instance;
4686349Sqs148142 	hxgep->p_dip = ddi_get_parent(dip);
4696349Sqs148142 	hxgep->hxge_debug_level = hxge_debug_level;
4706349Sqs148142 	hpi_debug_level = hxge_debug_level;
4716349Sqs148142 
4726349Sqs148142 	hxge_fm_init(hxgep, &hxge_dev_reg_acc_attr, &hxge_dev_desc_dma_acc_attr,
4736349Sqs148142 	    &hxge_rx_dma_attr);
4746349Sqs148142 
4756349Sqs148142 	status = hxge_map_regs(hxgep);
4766349Sqs148142 	if (status != HXGE_OK) {
4776349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "hxge_map_regs failed"));
4786349Sqs148142 		goto hxge_attach_fail3;
4796349Sqs148142 	}
4806349Sqs148142 
4816349Sqs148142 	status = hxge_init_common_dev(hxgep);
4826349Sqs148142 	if (status != HXGE_OK) {
4836349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
4846349Sqs148142 		    "hxge_init_common_dev failed"));
4856349Sqs148142 		goto hxge_attach_fail4;
4866349Sqs148142 	}
4876349Sqs148142 
4886349Sqs148142 	/*
4896349Sqs148142 	 * Setup the Ndd parameters for this instance.
4906349Sqs148142 	 */
4916349Sqs148142 	hxge_init_param(hxgep);
4926349Sqs148142 
4936349Sqs148142 	/*
4946349Sqs148142 	 * Setup Register Tracing Buffer.
4956349Sqs148142 	 */
4966349Sqs148142 	hpi_rtrace_buf_init((rtrace_t *)&hpi_rtracebuf);
4976349Sqs148142 
4986349Sqs148142 	/* init stats ptr */
4996349Sqs148142 	hxge_init_statsp(hxgep);
5006349Sqs148142 
5017584SQiyan.Sun@Sun.COM 	status = hxge_setup_mutexes(hxgep);
5027584SQiyan.Sun@Sun.COM 	if (status != HXGE_OK) {
5037584SQiyan.Sun@Sun.COM 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "set mutex failed"));
5047584SQiyan.Sun@Sun.COM 		goto hxge_attach_fail;
5057584SQiyan.Sun@Sun.COM 	}
5067584SQiyan.Sun@Sun.COM 
5076349Sqs148142 	status = hxge_get_config_properties(hxgep);
5086349Sqs148142 	if (status != HXGE_OK) {
5096349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "get_hw create failed"));
5106349Sqs148142 		goto hxge_attach_fail;
5116349Sqs148142 	}
5126349Sqs148142 
5136349Sqs148142 	/*
5146349Sqs148142 	 * Setup the Kstats for the driver.
5156349Sqs148142 	 */
5166349Sqs148142 	hxge_setup_kstats(hxgep);
5176349Sqs148142 	hxge_setup_param(hxgep);
5186349Sqs148142 
5196349Sqs148142 	status = hxge_setup_system_dma_pages(hxgep);
5206349Sqs148142 	if (status != HXGE_OK) {
5216349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "set dma page failed"));
5226349Sqs148142 		goto hxge_attach_fail;
5236349Sqs148142 	}
5246349Sqs148142 
5256349Sqs148142 	hxge_hw_id_init(hxgep);
5266349Sqs148142 	hxge_hw_init_niu_common(hxgep);
5276349Sqs148142 
5286349Sqs148142 	status = hxge_setup_dev(hxgep);
5296349Sqs148142 	if (status != DDI_SUCCESS) {
5306349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "set dev failed"));
5316349Sqs148142 		goto hxge_attach_fail;
5326349Sqs148142 	}
5336349Sqs148142 
5346349Sqs148142 	status = hxge_add_intrs(hxgep);
5356349Sqs148142 	if (status != DDI_SUCCESS) {
5366349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "add_intr failed"));
5376349Sqs148142 		goto hxge_attach_fail;
5386349Sqs148142 	}
5396349Sqs148142 
5406349Sqs148142 	status = hxge_add_soft_intrs(hxgep);
5416349Sqs148142 	if (status != DDI_SUCCESS) {
5426349Sqs148142 		HXGE_DEBUG_MSG((hxgep, HXGE_ERR_CTL, "add_soft_intr failed"));
5436349Sqs148142 		goto hxge_attach_fail;
5446349Sqs148142 	}
5456349Sqs148142 
5466349Sqs148142 	/*
5476349Sqs148142 	 * Enable interrupts.
5486349Sqs148142 	 */
5496349Sqs148142 	hxge_intrs_enable(hxgep);
5506349Sqs148142 
5516349Sqs148142 	if ((status = hxge_mac_register(hxgep)) != HXGE_OK) {
5526349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL,
5536349Sqs148142 		    "unable to register to mac layer (%d)", status));
5546349Sqs148142 		goto hxge_attach_fail;
5556349Sqs148142 	}
5567584SQiyan.Sun@Sun.COM 	mac_link_update(hxgep->mach, LINK_STATE_UNKNOWN);
5577584SQiyan.Sun@Sun.COM 	hxgep->timeout.link_status = 0;
5587584SQiyan.Sun@Sun.COM 	hxgep->timeout.ticks = drv_usectohz(2 * 1000000);
5597584SQiyan.Sun@Sun.COM 
5607584SQiyan.Sun@Sun.COM 	/* Start the link status timer to check the link status */
5617584SQiyan.Sun@Sun.COM 	MUTEX_ENTER(&hxgep->timeout.lock);
5627584SQiyan.Sun@Sun.COM 	hxgep->timeout.id = timeout(hxge_link_poll, (void *)hxgep,
5637584SQiyan.Sun@Sun.COM 	    hxgep->timeout.ticks);
5647584SQiyan.Sun@Sun.COM 	MUTEX_EXIT(&hxgep->timeout.lock);
5656349Sqs148142 
5666349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "registered to mac (instance %d)",
5676349Sqs148142 	    instance));
5686349Sqs148142 
5696349Sqs148142 	goto hxge_attach_exit;
5706349Sqs148142 
5716349Sqs148142 hxge_attach_fail:
5726349Sqs148142 	hxge_unattach(hxgep);
5736349Sqs148142 	goto hxge_attach_fail1;
5746349Sqs148142 
5756349Sqs148142 hxge_attach_fail5:
5766349Sqs148142 	/*
5776349Sqs148142 	 * Tear down the ndd parameters setup.
5786349Sqs148142 	 */
5796349Sqs148142 	hxge_destroy_param(hxgep);
5806349Sqs148142 
5816349Sqs148142 	/*
5826349Sqs148142 	 * Tear down the kstat setup.
5836349Sqs148142 	 */
5846349Sqs148142 	hxge_destroy_kstats(hxgep);
5856349Sqs148142 
5866349Sqs148142 hxge_attach_fail4:
5876349Sqs148142 	if (hxgep->hxge_hw_p) {
5886349Sqs148142 		hxge_uninit_common_dev(hxgep);
5896349Sqs148142 		hxgep->hxge_hw_p = NULL;
5906349Sqs148142 	}
5916349Sqs148142 hxge_attach_fail3:
5926349Sqs148142 	/*
5936349Sqs148142 	 * Unmap the register setup.
5946349Sqs148142 	 */
5956349Sqs148142 	hxge_unmap_regs(hxgep);
5966349Sqs148142 
5976349Sqs148142 	hxge_fm_fini(hxgep);
5986349Sqs148142 
5996349Sqs148142 hxge_attach_fail2:
6006349Sqs148142 	ddi_soft_state_free(hxge_list, hxgep->instance);
6016349Sqs148142 
6026349Sqs148142 hxge_attach_fail1:
6036349Sqs148142 	if (status != HXGE_OK)
6046349Sqs148142 		status = (HXGE_ERROR | HXGE_DDI_FAILED);
6056349Sqs148142 	hxgep = NULL;
6066349Sqs148142 
6076349Sqs148142 hxge_attach_exit:
6086349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_attach status = 0x%08x",
6096349Sqs148142 	    status));
6106349Sqs148142 
6116349Sqs148142 	return (status);
6126349Sqs148142 }
6136349Sqs148142 
6146349Sqs148142 static int
6156349Sqs148142 hxge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
6166349Sqs148142 {
6176349Sqs148142 	int		status = DDI_SUCCESS;
6186349Sqs148142 	int		instance;
6196349Sqs148142 	p_hxge_t	hxgep = NULL;
6206349Sqs148142 
6216349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_detach"));
6226349Sqs148142 	instance = ddi_get_instance(dip);
6236349Sqs148142 	hxgep = ddi_get_soft_state(hxge_list, instance);
6246349Sqs148142 	if (hxgep == NULL) {
6256349Sqs148142 		status = DDI_FAILURE;
6266349Sqs148142 		goto hxge_detach_exit;
6276349Sqs148142 	}
6286349Sqs148142 
6296349Sqs148142 	switch (cmd) {
6306349Sqs148142 	case DDI_DETACH:
6316349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_DETACH"));
6326349Sqs148142 		break;
6336349Sqs148142 
6346349Sqs148142 	case DDI_PM_SUSPEND:
6356349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_PM_SUSPEND"));
6366349Sqs148142 		hxgep->suspended = DDI_PM_SUSPEND;
6376349Sqs148142 		hxge_suspend(hxgep);
6386349Sqs148142 		break;
6396349Sqs148142 
6406349Sqs148142 	case DDI_SUSPEND:
6416349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "doing DDI_SUSPEND"));
6426349Sqs148142 		if (hxgep->suspended != DDI_PM_SUSPEND) {
6436349Sqs148142 			hxgep->suspended = DDI_SUSPEND;
6446349Sqs148142 			hxge_suspend(hxgep);
6456349Sqs148142 		}
6466349Sqs148142 		break;
6476349Sqs148142 
6486349Sqs148142 	default:
6496349Sqs148142 		status = DDI_FAILURE;
6506349Sqs148142 		break;
6516349Sqs148142 	}
6526349Sqs148142 
6536349Sqs148142 	if (cmd != DDI_DETACH)
6546349Sqs148142 		goto hxge_detach_exit;
6556349Sqs148142 
6566349Sqs148142 	/*
6576349Sqs148142 	 * Stop the xcvr polling.
6586349Sqs148142 	 */
6596349Sqs148142 	hxgep->suspended = cmd;
6606349Sqs148142 
6617584SQiyan.Sun@Sun.COM 	/* Stop the link status timer before unregistering */
6627584SQiyan.Sun@Sun.COM 	MUTEX_ENTER(&hxgep->timeout.lock);
6637584SQiyan.Sun@Sun.COM 	if (hxgep->timeout.id)
6647584SQiyan.Sun@Sun.COM 		(void) untimeout(hxgep->timeout.id);
6657584SQiyan.Sun@Sun.COM 	MUTEX_EXIT(&hxgep->timeout.lock);
6667584SQiyan.Sun@Sun.COM 
6676349Sqs148142 	if (hxgep->mach && (status = mac_unregister(hxgep->mach)) != 0) {
6686349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
6696349Sqs148142 		    "<== hxge_detach status = 0x%08X", status));
6706349Sqs148142 		return (DDI_FAILURE);
6716349Sqs148142 	}
6726349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
6736349Sqs148142 	    "<== hxge_detach (mac_unregister) status = 0x%08X", status));
6746349Sqs148142 
6756349Sqs148142 	hxge_unattach(hxgep);
6766349Sqs148142 	hxgep = NULL;
6776349Sqs148142 
6786349Sqs148142 hxge_detach_exit:
6796349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_detach status = 0x%08X",
6806349Sqs148142 	    status));
6816349Sqs148142 
6826349Sqs148142 	return (status);
6836349Sqs148142 }
6846349Sqs148142 
6856349Sqs148142 static void
6866349Sqs148142 hxge_unattach(p_hxge_t hxgep)
6876349Sqs148142 {
6886349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_unattach"));
6896349Sqs148142 
6906349Sqs148142 	if (hxgep == NULL || hxgep->dev_regs == NULL) {
6916349Sqs148142 		return;
6926349Sqs148142 	}
6936349Sqs148142 
6946349Sqs148142 	if (hxgep->hxge_hw_p) {
6956349Sqs148142 		hxge_uninit_common_dev(hxgep);
6966349Sqs148142 		hxgep->hxge_hw_p = NULL;
6976349Sqs148142 	}
6986349Sqs148142 
6996349Sqs148142 	if (hxgep->hxge_timerid) {
7006349Sqs148142 		hxge_stop_timer(hxgep, hxgep->hxge_timerid);
7016349Sqs148142 		hxgep->hxge_timerid = 0;
7026349Sqs148142 	}
7036349Sqs148142 
7046349Sqs148142 	/* Stop any further interrupts. */
7056349Sqs148142 	hxge_remove_intrs(hxgep);
7066349Sqs148142 
7076349Sqs148142 	/* Remove soft interrups */
7086349Sqs148142 	hxge_remove_soft_intrs(hxgep);
7096349Sqs148142 
7106349Sqs148142 	/* Stop the device and free resources. */
7116349Sqs148142 	hxge_destroy_dev(hxgep);
7126349Sqs148142 
7136349Sqs148142 	/* Tear down the ndd parameters setup. */
7146349Sqs148142 	hxge_destroy_param(hxgep);
7156349Sqs148142 
7166349Sqs148142 	/* Tear down the kstat setup. */
7176349Sqs148142 	hxge_destroy_kstats(hxgep);
7186349Sqs148142 
7196349Sqs148142 	/*
7206349Sqs148142 	 * Remove the list of ndd parameters which were setup during attach.
7216349Sqs148142 	 */
7226349Sqs148142 	if (hxgep->dip) {
7236349Sqs148142 		HXGE_DEBUG_MSG((hxgep, OBP_CTL,
7246349Sqs148142 		    " hxge_unattach: remove all properties"));
7256349Sqs148142 		(void) ddi_prop_remove_all(hxgep->dip);
7266349Sqs148142 	}
7276349Sqs148142 
7286349Sqs148142 	/*
7296864Sqs148142 	 * Reset RDC, TDC, PFC, and VMAC blocks from PEU to clear any
7306864Sqs148142 	 * previous state before unmapping the registers.
7316864Sqs148142 	 */
7326864Sqs148142 	HXGE_REG_WR32(hxgep->hpi_handle, BLOCK_RESET, 0x0000001E);
7336864Sqs148142 	HXGE_DELAY(1000);
7346864Sqs148142 
7356864Sqs148142 	/*
7366349Sqs148142 	 * Unmap the register setup.
7376349Sqs148142 	 */
7386349Sqs148142 	hxge_unmap_regs(hxgep);
7396349Sqs148142 
7406349Sqs148142 	hxge_fm_fini(hxgep);
7416349Sqs148142 
7427584SQiyan.Sun@Sun.COM 	/* Destroy all mutexes.  */
7437584SQiyan.Sun@Sun.COM 	hxge_destroy_mutexes(hxgep);
7447584SQiyan.Sun@Sun.COM 
7456349Sqs148142 	/*
7466349Sqs148142 	 * Free the soft state data structures allocated with this instance.
7476349Sqs148142 	 */
7486349Sqs148142 	ddi_soft_state_free(hxge_list, hxgep->instance);
7496349Sqs148142 
7506349Sqs148142 	HXGE_DEBUG_MSG((NULL, DDI_CTL, "<== hxge_unattach"));
7516349Sqs148142 }
7526349Sqs148142 
7536349Sqs148142 static hxge_status_t
7546349Sqs148142 hxge_map_regs(p_hxge_t hxgep)
7556349Sqs148142 {
7566349Sqs148142 	int		ddi_status = DDI_SUCCESS;
7576349Sqs148142 	p_dev_regs_t	dev_regs;
7586349Sqs148142 
7596349Sqs148142 #ifdef	HXGE_DEBUG
7606349Sqs148142 	char		*sysname;
7616349Sqs148142 #endif
7626349Sqs148142 
7636349Sqs148142 	off_t		regsize;
7646349Sqs148142 	hxge_status_t	status = HXGE_OK;
7656349Sqs148142 	int		nregs;
7666349Sqs148142 
7676349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_map_regs"));
7686349Sqs148142 
7696349Sqs148142 	if (ddi_dev_nregs(hxgep->dip, &nregs) != DDI_SUCCESS)
7706349Sqs148142 		return (HXGE_ERROR);
7716349Sqs148142 
7726349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "hxge_map_regs: nregs: %d", nregs));
7736349Sqs148142 
7746349Sqs148142 	hxgep->dev_regs = NULL;
7756349Sqs148142 	dev_regs = KMEM_ZALLOC(sizeof (dev_regs_t), KM_SLEEP);
7766349Sqs148142 	dev_regs->hxge_regh = NULL;
7776349Sqs148142 	dev_regs->hxge_pciregh = NULL;
7786349Sqs148142 	dev_regs->hxge_msix_regh = NULL;
7796349Sqs148142 
7806349Sqs148142 	(void) ddi_dev_regsize(hxgep->dip, 0, &regsize);
7816349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
7826349Sqs148142 	    "hxge_map_regs: pci config size 0x%x", regsize));
7836349Sqs148142 
7846349Sqs148142 	ddi_status = ddi_regs_map_setup(hxgep->dip, 0,
7856349Sqs148142 	    (caddr_t *)&(dev_regs->hxge_pciregp), 0, 0,
7866349Sqs148142 	    &hxge_dev_reg_acc_attr, &dev_regs->hxge_pciregh);
7876349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
7886349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
7896349Sqs148142 		    "ddi_map_regs, hxge bus config regs failed"));
7906349Sqs148142 		goto hxge_map_regs_fail0;
7916349Sqs148142 	}
7926349Sqs148142 
7936349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
7946349Sqs148142 	    "hxge_map_reg: PCI config addr 0x%0llx handle 0x%0llx",
7956349Sqs148142 	    dev_regs->hxge_pciregp,
7966349Sqs148142 	    dev_regs->hxge_pciregh));
7976349Sqs148142 
7986349Sqs148142 	(void) ddi_dev_regsize(hxgep->dip, 1, &regsize);
7996349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
8006349Sqs148142 	    "hxge_map_regs: pio size 0x%x", regsize));
8016349Sqs148142 
8026349Sqs148142 	/* set up the device mapped register */
8036349Sqs148142 	ddi_status = ddi_regs_map_setup(hxgep->dip, 1,
8046349Sqs148142 	    (caddr_t *)&(dev_regs->hxge_regp), 0, 0,
8056349Sqs148142 	    &hxge_dev_reg_acc_attr, &dev_regs->hxge_regh);
8066349Sqs148142 
8076349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
8086349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8096349Sqs148142 		    "ddi_map_regs for Hydra global reg failed"));
8106349Sqs148142 		goto hxge_map_regs_fail1;
8116349Sqs148142 	}
8126349Sqs148142 
8136349Sqs148142 	/* set up the msi/msi-x mapped register */
8146349Sqs148142 	(void) ddi_dev_regsize(hxgep->dip, 2, &regsize);
8156349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
8166349Sqs148142 	    "hxge_map_regs: msix size 0x%x", regsize));
8176349Sqs148142 
8186349Sqs148142 	ddi_status = ddi_regs_map_setup(hxgep->dip, 2,
8196349Sqs148142 	    (caddr_t *)&(dev_regs->hxge_msix_regp), 0, 0,
8206349Sqs148142 	    &hxge_dev_reg_acc_attr, &dev_regs->hxge_msix_regh);
8216349Sqs148142 
8226349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
8236349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8246349Sqs148142 		    "ddi_map_regs for msi reg failed"));
8256349Sqs148142 		goto hxge_map_regs_fail2;
8266349Sqs148142 	}
8276349Sqs148142 
8286349Sqs148142 	hxgep->dev_regs = dev_regs;
8296349Sqs148142 
8306349Sqs148142 	HPI_PCI_ACC_HANDLE_SET(hxgep, dev_regs->hxge_pciregh);
8316349Sqs148142 	HPI_PCI_ADD_HANDLE_SET(hxgep, (hpi_reg_ptr_t)dev_regs->hxge_pciregp);
8326349Sqs148142 	HPI_MSI_ACC_HANDLE_SET(hxgep, dev_regs->hxge_msix_regh);
8336349Sqs148142 	HPI_MSI_ADD_HANDLE_SET(hxgep, (hpi_reg_ptr_t)dev_regs->hxge_msix_regp);
8346349Sqs148142 
8356349Sqs148142 	HPI_ACC_HANDLE_SET(hxgep, dev_regs->hxge_regh);
8366349Sqs148142 	HPI_ADD_HANDLE_SET(hxgep, (hpi_reg_ptr_t)dev_regs->hxge_regp);
8376349Sqs148142 
8386349Sqs148142 	HPI_REG_ACC_HANDLE_SET(hxgep, dev_regs->hxge_regh);
8396349Sqs148142 	HPI_REG_ADD_HANDLE_SET(hxgep, (hpi_reg_ptr_t)dev_regs->hxge_regp);
8406349Sqs148142 
8416349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "hxge_map_reg: hardware addr 0x%0llx "
8426349Sqs148142 	    " handle 0x%0llx", dev_regs->hxge_regp, dev_regs->hxge_regh));
8436349Sqs148142 
8446349Sqs148142 	goto hxge_map_regs_exit;
8456349Sqs148142 
8466349Sqs148142 hxge_map_regs_fail3:
8476349Sqs148142 	if (dev_regs->hxge_msix_regh) {
8486349Sqs148142 		ddi_regs_map_free(&dev_regs->hxge_msix_regh);
8496349Sqs148142 	}
8506349Sqs148142 
8516349Sqs148142 hxge_map_regs_fail2:
8526349Sqs148142 	if (dev_regs->hxge_regh) {
8536349Sqs148142 		ddi_regs_map_free(&dev_regs->hxge_regh);
8546349Sqs148142 	}
8556349Sqs148142 
8566349Sqs148142 hxge_map_regs_fail1:
8576349Sqs148142 	if (dev_regs->hxge_pciregh) {
8586349Sqs148142 		ddi_regs_map_free(&dev_regs->hxge_pciregh);
8596349Sqs148142 	}
8606349Sqs148142 
8616349Sqs148142 hxge_map_regs_fail0:
8626349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "Freeing register set memory"));
8636349Sqs148142 	kmem_free(dev_regs, sizeof (dev_regs_t));
8646349Sqs148142 
8656349Sqs148142 hxge_map_regs_exit:
8666349Sqs148142 	if (ddi_status != DDI_SUCCESS)
8676349Sqs148142 		status |= (HXGE_ERROR | HXGE_DDI_FAILED);
8686349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_map_regs"));
8696349Sqs148142 	return (status);
8706349Sqs148142 }
8716349Sqs148142 
8726349Sqs148142 static void
8736349Sqs148142 hxge_unmap_regs(p_hxge_t hxgep)
8746349Sqs148142 {
8756349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_unmap_regs"));
8766349Sqs148142 	if (hxgep->dev_regs) {
8776349Sqs148142 		if (hxgep->dev_regs->hxge_pciregh) {
8786349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL,
8796349Sqs148142 			    "==> hxge_unmap_regs: bus"));
8806349Sqs148142 			ddi_regs_map_free(&hxgep->dev_regs->hxge_pciregh);
8816349Sqs148142 			hxgep->dev_regs->hxge_pciregh = NULL;
8826349Sqs148142 		}
8836349Sqs148142 
8846349Sqs148142 		if (hxgep->dev_regs->hxge_regh) {
8856349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL,
8866349Sqs148142 			    "==> hxge_unmap_regs: device registers"));
8876349Sqs148142 			ddi_regs_map_free(&hxgep->dev_regs->hxge_regh);
8886349Sqs148142 			hxgep->dev_regs->hxge_regh = NULL;
8896349Sqs148142 		}
8906349Sqs148142 
8916349Sqs148142 		if (hxgep->dev_regs->hxge_msix_regh) {
8926349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL,
8936349Sqs148142 			    "==> hxge_unmap_regs: device interrupts"));
8946349Sqs148142 			ddi_regs_map_free(&hxgep->dev_regs->hxge_msix_regh);
8956349Sqs148142 			hxgep->dev_regs->hxge_msix_regh = NULL;
8966349Sqs148142 		}
8976349Sqs148142 		kmem_free(hxgep->dev_regs, sizeof (dev_regs_t));
8986349Sqs148142 		hxgep->dev_regs = NULL;
8996349Sqs148142 	}
9006349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_unmap_regs"));
9016349Sqs148142 }
9026349Sqs148142 
9036349Sqs148142 static hxge_status_t
9046349Sqs148142 hxge_setup_mutexes(p_hxge_t hxgep)
9056349Sqs148142 {
9066349Sqs148142 	int		ddi_status = DDI_SUCCESS;
9076349Sqs148142 	hxge_status_t	status = HXGE_OK;
9086349Sqs148142 
9096349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_setup_mutexes"));
9106349Sqs148142 
9116349Sqs148142 	/*
9126349Sqs148142 	 * Get the interrupt cookie so the mutexes can be Initialised.
9136349Sqs148142 	 */
9146349Sqs148142 	ddi_status = ddi_get_iblock_cookie(hxgep->dip, 0,
9156349Sqs148142 	    &hxgep->interrupt_cookie);
9166349Sqs148142 
9176349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
9186349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
9196349Sqs148142 		    "<== hxge_setup_mutexes: failed 0x%x", ddi_status));
9206349Sqs148142 		goto hxge_setup_mutexes_exit;
9216349Sqs148142 	}
9226349Sqs148142 
9236349Sqs148142 	/*
9246349Sqs148142 	 * Initialize mutex's for this device.
9256349Sqs148142 	 */
9266349Sqs148142 	MUTEX_INIT(hxgep->genlock, NULL,
9276349Sqs148142 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
9286349Sqs148142 	MUTEX_INIT(&hxgep->ouraddr_lock, NULL,
9296349Sqs148142 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
9306349Sqs148142 	RW_INIT(&hxgep->filter_lock, NULL,
9316349Sqs148142 	    RW_DRIVER, (void *) hxgep->interrupt_cookie);
9326864Sqs148142 	MUTEX_INIT(&hxgep->pio_lock, NULL,
9336864Sqs148142 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
9347584SQiyan.Sun@Sun.COM 	MUTEX_INIT(&hxgep->timeout.lock, NULL,
9357584SQiyan.Sun@Sun.COM 	    MUTEX_DRIVER, (void *) hxgep->interrupt_cookie);
9366349Sqs148142 
9376349Sqs148142 hxge_setup_mutexes_exit:
9386349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
9396349Sqs148142 	    "<== hxge_setup_mutexes status = %x", status));
9406349Sqs148142 
9416349Sqs148142 	if (ddi_status != DDI_SUCCESS)
9426349Sqs148142 		status |= (HXGE_ERROR | HXGE_DDI_FAILED);
9436349Sqs148142 
9446349Sqs148142 	return (status);
9456349Sqs148142 }
9466349Sqs148142 
9476349Sqs148142 static void
9486349Sqs148142 hxge_destroy_mutexes(p_hxge_t hxgep)
9496349Sqs148142 {
9506349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_destroy_mutexes"));
9516349Sqs148142 	RW_DESTROY(&hxgep->filter_lock);
9526349Sqs148142 	MUTEX_DESTROY(&hxgep->ouraddr_lock);
9536349Sqs148142 	MUTEX_DESTROY(hxgep->genlock);
9546864Sqs148142 	MUTEX_DESTROY(&hxgep->pio_lock);
9557584SQiyan.Sun@Sun.COM 	MUTEX_DESTROY(&hxgep->timeout.lock);
9566349Sqs148142 
9576349Sqs148142 	if (hxge_debug_init == 1) {
9586349Sqs148142 		MUTEX_DESTROY(&hxgedebuglock);
9596349Sqs148142 		hxge_debug_init = 0;
9606349Sqs148142 	}
9616349Sqs148142 
9626349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_destroy_mutexes"));
9636349Sqs148142 }
9646349Sqs148142 
9656349Sqs148142 hxge_status_t
9666349Sqs148142 hxge_init(p_hxge_t hxgep)
9676349Sqs148142 {
9686349Sqs148142 	hxge_status_t status = HXGE_OK;
9696349Sqs148142 
9706349Sqs148142 	HXGE_DEBUG_MSG((hxgep, STR_CTL, "==> hxge_init"));
9716349Sqs148142 
9726349Sqs148142 	if (hxgep->drv_state & STATE_HW_INITIALIZED) {
9736349Sqs148142 		return (status);
9746349Sqs148142 	}
9756349Sqs148142 
9766349Sqs148142 	/*
9776349Sqs148142 	 * Allocate system memory for the receive/transmit buffer blocks and
9786349Sqs148142 	 * receive/transmit descriptor rings.
9796349Sqs148142 	 */
9806349Sqs148142 	status = hxge_alloc_mem_pool(hxgep);
9816349Sqs148142 	if (status != HXGE_OK) {
9826349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "alloc mem failed\n"));
9836349Sqs148142 		goto hxge_init_fail1;
9846349Sqs148142 	}
9856349Sqs148142 
9866349Sqs148142 	/*
9876349Sqs148142 	 * Initialize and enable TXDMA channels.
9886349Sqs148142 	 */
9896349Sqs148142 	status = hxge_init_txdma_channels(hxgep);
9906349Sqs148142 	if (status != HXGE_OK) {
9916349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "init txdma failed\n"));
9926349Sqs148142 		goto hxge_init_fail3;
9936349Sqs148142 	}
9946349Sqs148142 
9956349Sqs148142 	/*
9966349Sqs148142 	 * Initialize and enable RXDMA channels.
9976349Sqs148142 	 */
9986349Sqs148142 	status = hxge_init_rxdma_channels(hxgep);
9996349Sqs148142 	if (status != HXGE_OK) {
10006349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "init rxdma failed\n"));
10016349Sqs148142 		goto hxge_init_fail4;
10026349Sqs148142 	}
10036349Sqs148142 
10046349Sqs148142 	/*
10056349Sqs148142 	 * Initialize TCAM
10066349Sqs148142 	 */
10076349Sqs148142 	status = hxge_classify_init(hxgep);
10086349Sqs148142 	if (status != HXGE_OK) {
10096349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "init classify failed\n"));
10106349Sqs148142 		goto hxge_init_fail5;
10116349Sqs148142 	}
10126349Sqs148142 
10136349Sqs148142 	/*
10146349Sqs148142 	 * Initialize the VMAC block.
10156349Sqs148142 	 */
10166349Sqs148142 	status = hxge_vmac_init(hxgep);
10176349Sqs148142 	if (status != HXGE_OK) {
10186349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "init MAC failed\n"));
10196349Sqs148142 		goto hxge_init_fail5;
10206349Sqs148142 	}
10216349Sqs148142 
10226349Sqs148142 	/* Bringup - this may be unnecessary when PXE and FCODE available */
10236349Sqs148142 	status = hxge_pfc_set_default_mac_addr(hxgep);
10246349Sqs148142 	if (status != HXGE_OK) {
10256349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
10266349Sqs148142 		    "Default Address Failure\n"));
10276349Sqs148142 		goto hxge_init_fail5;
10286349Sqs148142 	}
10296349Sqs148142 
10306349Sqs148142 	hxge_intrs_enable(hxgep);
10316349Sqs148142 
10326349Sqs148142 	/*
10336349Sqs148142 	 * Enable hardware interrupts.
10346349Sqs148142 	 */
10356349Sqs148142 	hxge_intr_hw_enable(hxgep);
10366349Sqs148142 	hxgep->drv_state |= STATE_HW_INITIALIZED;
10376349Sqs148142 
10386349Sqs148142 	goto hxge_init_exit;
10396349Sqs148142 
10406349Sqs148142 hxge_init_fail5:
10416349Sqs148142 	hxge_uninit_rxdma_channels(hxgep);
10426349Sqs148142 hxge_init_fail4:
10436349Sqs148142 	hxge_uninit_txdma_channels(hxgep);
10446349Sqs148142 hxge_init_fail3:
10456349Sqs148142 	hxge_free_mem_pool(hxgep);
10466349Sqs148142 hxge_init_fail1:
10476349Sqs148142 	HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
10486349Sqs148142 	    "<== hxge_init status (failed) = 0x%08x", status));
10496349Sqs148142 	return (status);
10506349Sqs148142 
10516349Sqs148142 hxge_init_exit:
10526349Sqs148142 
10536349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_init status = 0x%08x",
10546349Sqs148142 	    status));
10556349Sqs148142 
10566349Sqs148142 	return (status);
10576349Sqs148142 }
10586349Sqs148142 
10596349Sqs148142 timeout_id_t
10606349Sqs148142 hxge_start_timer(p_hxge_t hxgep, fptrv_t func, int msec)
10616349Sqs148142 {
10626349Sqs148142 	if ((hxgep->suspended == 0) || (hxgep->suspended == DDI_RESUME)) {
10636349Sqs148142 		return (timeout(func, (caddr_t)hxgep,
10646349Sqs148142 		    drv_usectohz(1000 * msec)));
10656349Sqs148142 	}
10666349Sqs148142 	return (NULL);
10676349Sqs148142 }
10686349Sqs148142 
10696349Sqs148142 /*ARGSUSED*/
10706349Sqs148142 void
10716349Sqs148142 hxge_stop_timer(p_hxge_t hxgep, timeout_id_t timerid)
10726349Sqs148142 {
10736349Sqs148142 	if (timerid) {
10746349Sqs148142 		(void) untimeout(timerid);
10756349Sqs148142 	}
10766349Sqs148142 }
10776349Sqs148142 
10786349Sqs148142 void
10796349Sqs148142 hxge_uninit(p_hxge_t hxgep)
10806349Sqs148142 {
10816349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_uninit"));
10826349Sqs148142 
10836349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
10846349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL,
10856349Sqs148142 		    "==> hxge_uninit: not initialized"));
10866349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_uninit"));
10876349Sqs148142 		return;
10886349Sqs148142 	}
10896349Sqs148142 
10906349Sqs148142 	/* Stop timer */
10916349Sqs148142 	if (hxgep->hxge_timerid) {
10926349Sqs148142 		hxge_stop_timer(hxgep, hxgep->hxge_timerid);
10936349Sqs148142 		hxgep->hxge_timerid = 0;
10946349Sqs148142 	}
10956349Sqs148142 
10966349Sqs148142 	(void) hxge_intr_hw_disable(hxgep);
10976349Sqs148142 
10986349Sqs148142 	/* Reset the receive VMAC side.  */
10996349Sqs148142 	(void) hxge_rx_vmac_disable(hxgep);
11006349Sqs148142 
11016349Sqs148142 	/* Free classification resources */
11026349Sqs148142 	(void) hxge_classify_uninit(hxgep);
11036349Sqs148142 
11046349Sqs148142 	/* Reset the transmit/receive DMA side.  */
11056349Sqs148142 	(void) hxge_txdma_hw_mode(hxgep, HXGE_DMA_STOP);
11066349Sqs148142 	(void) hxge_rxdma_hw_mode(hxgep, HXGE_DMA_STOP);
11076349Sqs148142 
11086349Sqs148142 	hxge_uninit_txdma_channels(hxgep);
11096349Sqs148142 	hxge_uninit_rxdma_channels(hxgep);
11106349Sqs148142 
11116349Sqs148142 	/* Reset the transmit VMAC side.  */
11126349Sqs148142 	(void) hxge_tx_vmac_disable(hxgep);
11136349Sqs148142 
11146349Sqs148142 	hxge_free_mem_pool(hxgep);
11156349Sqs148142 
11166349Sqs148142 	hxgep->drv_state &= ~STATE_HW_INITIALIZED;
11176349Sqs148142 
11186349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_uninit"));
11196349Sqs148142 }
11206349Sqs148142 
11216349Sqs148142 void
11226349Sqs148142 hxge_get64(p_hxge_t hxgep, p_mblk_t mp)
11236349Sqs148142 {
11246349Sqs148142 #if defined(__i386)
11256349Sqs148142 	size_t		reg;
11266349Sqs148142 #else
11276349Sqs148142 	uint64_t	reg;
11286349Sqs148142 #endif
11296349Sqs148142 	uint64_t	regdata;
11306349Sqs148142 	int		i, retry;
11316349Sqs148142 
11326349Sqs148142 	bcopy((char *)mp->b_rptr, (char *)&reg, sizeof (uint64_t));
11336349Sqs148142 	regdata = 0;
11346349Sqs148142 	retry = 1;
11356349Sqs148142 
11366349Sqs148142 	for (i = 0; i < retry; i++) {
11376349Sqs148142 		HXGE_REG_RD64(hxgep->hpi_handle, reg, &regdata);
11386349Sqs148142 	}
11396349Sqs148142 	bcopy((char *)&regdata, (char *)mp->b_rptr, sizeof (uint64_t));
11406349Sqs148142 }
11416349Sqs148142 
11426349Sqs148142 void
11436349Sqs148142 hxge_put64(p_hxge_t hxgep, p_mblk_t mp)
11446349Sqs148142 {
11456349Sqs148142 #if defined(__i386)
11466349Sqs148142 	size_t		reg;
11476349Sqs148142 #else
11486349Sqs148142 	uint64_t	reg;
11496349Sqs148142 #endif
11506349Sqs148142 	uint64_t	buf[2];
11516349Sqs148142 
11526349Sqs148142 	bcopy((char *)mp->b_rptr, (char *)&buf[0], 2 * sizeof (uint64_t));
11536349Sqs148142 #if defined(__i386)
11546349Sqs148142 	reg = (size_t)buf[0];
11556349Sqs148142 #else
11566349Sqs148142 	reg = buf[0];
11576349Sqs148142 #endif
11586349Sqs148142 
11596349Sqs148142 	HXGE_HPI_PIO_WRITE64(hxgep->hpi_handle, reg, buf[1]);
11606349Sqs148142 }
11616349Sqs148142 
11626349Sqs148142 /*ARGSUSED*/
11636349Sqs148142 /*VARARGS*/
11646349Sqs148142 void
11656349Sqs148142 hxge_debug_msg(p_hxge_t hxgep, uint64_t level, char *fmt, ...)
11666349Sqs148142 {
11676349Sqs148142 	char		msg_buffer[1048];
11686349Sqs148142 	char		prefix_buffer[32];
11696349Sqs148142 	int		instance;
11706349Sqs148142 	uint64_t	debug_level;
11716349Sqs148142 	int		cmn_level = CE_CONT;
11726349Sqs148142 	va_list		ap;
11736349Sqs148142 
11746349Sqs148142 	debug_level = (hxgep == NULL) ? hxge_debug_level :
11756349Sqs148142 	    hxgep->hxge_debug_level;
11766349Sqs148142 
11776349Sqs148142 	if ((level & debug_level) || (level == HXGE_NOTE) ||
11786349Sqs148142 	    (level == HXGE_ERR_CTL)) {
11796349Sqs148142 		/* do the msg processing */
11806349Sqs148142 		if (hxge_debug_init == 0) {
11816349Sqs148142 			MUTEX_INIT(&hxgedebuglock, NULL, MUTEX_DRIVER, NULL);
11826349Sqs148142 			hxge_debug_init = 1;
11836349Sqs148142 		}
11846349Sqs148142 
11856349Sqs148142 		MUTEX_ENTER(&hxgedebuglock);
11866349Sqs148142 
11876349Sqs148142 		if ((level & HXGE_NOTE)) {
11886349Sqs148142 			cmn_level = CE_NOTE;
11896349Sqs148142 		}
11906349Sqs148142 
11916349Sqs148142 		if (level & HXGE_ERR_CTL) {
11926349Sqs148142 			cmn_level = CE_WARN;
11936349Sqs148142 		}
11946349Sqs148142 
11956349Sqs148142 		va_start(ap, fmt);
11966349Sqs148142 		(void) vsprintf(msg_buffer, fmt, ap);
11976349Sqs148142 		va_end(ap);
11986349Sqs148142 
11996349Sqs148142 		if (hxgep == NULL) {
12006349Sqs148142 			instance = -1;
12016349Sqs148142 			(void) sprintf(prefix_buffer, "%s :", "hxge");
12026349Sqs148142 		} else {
12036349Sqs148142 			instance = hxgep->instance;
12046349Sqs148142 			(void) sprintf(prefix_buffer,
12056349Sqs148142 			    "%s%d :", "hxge", instance);
12066349Sqs148142 		}
12076349Sqs148142 
12086349Sqs148142 		MUTEX_EXIT(&hxgedebuglock);
12096349Sqs148142 		cmn_err(cmn_level, "%s %s\n", prefix_buffer, msg_buffer);
12106349Sqs148142 	}
12116349Sqs148142 }
12126349Sqs148142 
12136349Sqs148142 char *
12146349Sqs148142 hxge_dump_packet(char *addr, int size)
12156349Sqs148142 {
12166349Sqs148142 	uchar_t		*ap = (uchar_t *)addr;
12176349Sqs148142 	int		i;
12186349Sqs148142 	static char	etherbuf[1024];
12196349Sqs148142 	char		*cp = etherbuf;
12206349Sqs148142 	char		digits[] = "0123456789abcdef";
12216349Sqs148142 
12226349Sqs148142 	if (!size)
12236349Sqs148142 		size = 60;
12246349Sqs148142 
12256349Sqs148142 	if (size > MAX_DUMP_SZ) {
12266349Sqs148142 		/* Dump the leading bytes */
12276349Sqs148142 		for (i = 0; i < MAX_DUMP_SZ / 2; i++) {
12286349Sqs148142 			if (*ap > 0x0f)
12296349Sqs148142 				*cp++ = digits[*ap >> 4];
12306349Sqs148142 			*cp++ = digits[*ap++ & 0xf];
12316349Sqs148142 			*cp++ = ':';
12326349Sqs148142 		}
12336349Sqs148142 		for (i = 0; i < 20; i++)
12346349Sqs148142 			*cp++ = '.';
12356349Sqs148142 		/* Dump the last MAX_DUMP_SZ/2 bytes */
12366349Sqs148142 		ap = (uchar_t *)(addr + (size - MAX_DUMP_SZ / 2));
12376349Sqs148142 		for (i = 0; i < MAX_DUMP_SZ / 2; i++) {
12386349Sqs148142 			if (*ap > 0x0f)
12396349Sqs148142 				*cp++ = digits[*ap >> 4];
12406349Sqs148142 			*cp++ = digits[*ap++ & 0xf];
12416349Sqs148142 			*cp++ = ':';
12426349Sqs148142 		}
12436349Sqs148142 	} else {
12446349Sqs148142 		for (i = 0; i < size; i++) {
12456349Sqs148142 			if (*ap > 0x0f)
12466349Sqs148142 				*cp++ = digits[*ap >> 4];
12476349Sqs148142 			*cp++ = digits[*ap++ & 0xf];
12486349Sqs148142 			*cp++ = ':';
12496349Sqs148142 		}
12506349Sqs148142 	}
12516349Sqs148142 	*--cp = 0;
12526349Sqs148142 	return (etherbuf);
12536349Sqs148142 }
12546349Sqs148142 
12556349Sqs148142 static void
12566349Sqs148142 hxge_suspend(p_hxge_t hxgep)
12576349Sqs148142 {
12586349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_suspend"));
12596349Sqs148142 
12606349Sqs148142 	hxge_intrs_disable(hxgep);
12616349Sqs148142 	hxge_destroy_dev(hxgep);
12626349Sqs148142 
12637584SQiyan.Sun@Sun.COM 	/* Stop the link status timer */
12647584SQiyan.Sun@Sun.COM 	MUTEX_ENTER(&hxgep->timeout.lock);
12657584SQiyan.Sun@Sun.COM 	if (hxgep->timeout.id)
12667584SQiyan.Sun@Sun.COM 		(void) untimeout(hxgep->timeout.id);
12677584SQiyan.Sun@Sun.COM 	MUTEX_EXIT(&hxgep->timeout.lock);
12687584SQiyan.Sun@Sun.COM 
12696349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_suspend"));
12706349Sqs148142 }
12716349Sqs148142 
12726349Sqs148142 static hxge_status_t
12736349Sqs148142 hxge_resume(p_hxge_t hxgep)
12746349Sqs148142 {
12756349Sqs148142 	hxge_status_t status = HXGE_OK;
12766349Sqs148142 
12776349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_resume"));
12786349Sqs148142 	hxgep->suspended = DDI_RESUME;
12796349Sqs148142 
12806349Sqs148142 	(void) hxge_rxdma_hw_mode(hxgep, HXGE_DMA_START);
12816349Sqs148142 	(void) hxge_txdma_hw_mode(hxgep, HXGE_DMA_START);
12826349Sqs148142 
12836349Sqs148142 	(void) hxge_rx_vmac_enable(hxgep);
12846349Sqs148142 	(void) hxge_tx_vmac_enable(hxgep);
12856349Sqs148142 
12866349Sqs148142 	hxge_intrs_enable(hxgep);
12876349Sqs148142 
12886349Sqs148142 	hxgep->suspended = 0;
12896349Sqs148142 
12907584SQiyan.Sun@Sun.COM 	/* Resume the link status timer */
12917584SQiyan.Sun@Sun.COM 	MUTEX_ENTER(&hxgep->timeout.lock);
12927584SQiyan.Sun@Sun.COM 	hxgep->timeout.id = timeout(hxge_link_poll, (void *)hxgep,
12937584SQiyan.Sun@Sun.COM 	    hxgep->timeout.ticks);
12947584SQiyan.Sun@Sun.COM 	MUTEX_EXIT(&hxgep->timeout.lock);
12957584SQiyan.Sun@Sun.COM 
12966349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
12976349Sqs148142 	    "<== hxge_resume status = 0x%x", status));
12986349Sqs148142 
12996349Sqs148142 	return (status);
13006349Sqs148142 }
13016349Sqs148142 
13026349Sqs148142 hxge_status_t
13036349Sqs148142 hxge_setup_dev(p_hxge_t hxgep)
13046349Sqs148142 {
13056349Sqs148142 	hxge_status_t status = HXGE_OK;
13066349Sqs148142 
13076349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_setup_dev"));
13086349Sqs148142 
13096349Sqs148142 	status = hxge_link_init(hxgep);
13106349Sqs148142 	if (fm_check_acc_handle(hxgep->dev_regs->hxge_regh) != DDI_FM_OK) {
13116349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
13126349Sqs148142 		    "Bad register acc handle"));
13136349Sqs148142 		status = HXGE_ERROR;
13146349Sqs148142 	}
13156349Sqs148142 
13166349Sqs148142 	if (status != HXGE_OK) {
13176349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MAC_CTL,
13186349Sqs148142 		    " hxge_setup_dev status (link init 0x%08x)", status));
13196349Sqs148142 		goto hxge_setup_dev_exit;
13206349Sqs148142 	}
13216349Sqs148142 
13226349Sqs148142 hxge_setup_dev_exit:
13236349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
13246349Sqs148142 	    "<== hxge_setup_dev status = 0x%08x", status));
13256349Sqs148142 
13266349Sqs148142 	return (status);
13276349Sqs148142 }
13286349Sqs148142 
13296349Sqs148142 static void
13306349Sqs148142 hxge_destroy_dev(p_hxge_t hxgep)
13316349Sqs148142 {
13326349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_destroy_dev"));
13336349Sqs148142 
13346349Sqs148142 	(void) hxge_hw_stop(hxgep);
13356349Sqs148142 
13366349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_destroy_dev"));
13376349Sqs148142 }
13386349Sqs148142 
13396349Sqs148142 static hxge_status_t
13406349Sqs148142 hxge_setup_system_dma_pages(p_hxge_t hxgep)
13416349Sqs148142 {
13426349Sqs148142 	int			ddi_status = DDI_SUCCESS;
13436349Sqs148142 	uint_t			count;
13446349Sqs148142 	ddi_dma_cookie_t	cookie;
13456349Sqs148142 	uint_t			iommu_pagesize;
13466349Sqs148142 	hxge_status_t		status = HXGE_OK;
13476349Sqs148142 
13486349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_setup_system_dma_pages"));
13496349Sqs148142 
13506349Sqs148142 	hxgep->sys_page_sz = ddi_ptob(hxgep->dip, (ulong_t)1);
13516349Sqs148142 	iommu_pagesize = dvma_pagesize(hxgep->dip);
13526349Sqs148142 
13536349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
13546349Sqs148142 	    " hxge_setup_system_dma_pages: page %d (ddi_ptob %d) "
13556349Sqs148142 	    " default_block_size %d iommu_pagesize %d",
13566349Sqs148142 	    hxgep->sys_page_sz, ddi_ptob(hxgep->dip, (ulong_t)1),
13576349Sqs148142 	    hxgep->rx_default_block_size, iommu_pagesize));
13586349Sqs148142 
13596349Sqs148142 	if (iommu_pagesize != 0) {
13606349Sqs148142 		if (hxgep->sys_page_sz == iommu_pagesize) {
13616349Sqs148142 			/* Hydra support up to 8K pages */
13626349Sqs148142 			if (iommu_pagesize > 0x2000)
13636349Sqs148142 				hxgep->sys_page_sz = 0x2000;
13646349Sqs148142 		} else {
13656349Sqs148142 			if (hxgep->sys_page_sz > iommu_pagesize)
13666349Sqs148142 				hxgep->sys_page_sz = iommu_pagesize;
13676349Sqs148142 		}
13686349Sqs148142 	}
13696349Sqs148142 
13706349Sqs148142 	hxgep->sys_page_mask = ~(hxgep->sys_page_sz - 1);
13716349Sqs148142 
13726349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
13736349Sqs148142 	    "==> hxge_setup_system_dma_pages: page %d (ddi_ptob %d) "
13746349Sqs148142 	    "default_block_size %d page mask %d",
13756349Sqs148142 	    hxgep->sys_page_sz, ddi_ptob(hxgep->dip, (ulong_t)1),
13766349Sqs148142 	    hxgep->rx_default_block_size, hxgep->sys_page_mask));
13776349Sqs148142 
13786349Sqs148142 	switch (hxgep->sys_page_sz) {
13796349Sqs148142 	default:
13806349Sqs148142 		hxgep->sys_page_sz = 0x1000;
13816349Sqs148142 		hxgep->sys_page_mask = ~(hxgep->sys_page_sz - 1);
13826349Sqs148142 		hxgep->rx_default_block_size = 0x1000;
13836349Sqs148142 		hxgep->rx_bksize_code = RBR_BKSIZE_4K;
13846349Sqs148142 		break;
13856349Sqs148142 	case 0x1000:
13866349Sqs148142 		hxgep->rx_default_block_size = 0x1000;
13876349Sqs148142 		hxgep->rx_bksize_code = RBR_BKSIZE_4K;
13886349Sqs148142 		break;
13896349Sqs148142 	case 0x2000:
13906349Sqs148142 		hxgep->rx_default_block_size = 0x2000;
13916349Sqs148142 		hxgep->rx_bksize_code = RBR_BKSIZE_8K;
13926349Sqs148142 		break;
13936349Sqs148142 	}
13946349Sqs148142 
13956349Sqs148142 	hxge_rx_dma_attr.dma_attr_align = hxgep->sys_page_sz;
13966349Sqs148142 	hxge_tx_dma_attr.dma_attr_align = hxgep->sys_page_sz;
13976349Sqs148142 
13986349Sqs148142 	/*
13996349Sqs148142 	 * Get the system DMA burst size.
14006349Sqs148142 	 */
14016349Sqs148142 	ddi_status = ddi_dma_alloc_handle(hxgep->dip, &hxge_tx_dma_attr,
14026349Sqs148142 	    DDI_DMA_DONTWAIT, 0, &hxgep->dmasparehandle);
14036349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
14046349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
14056349Sqs148142 		    "ddi_dma_alloc_handle: failed status 0x%x", ddi_status));
14066349Sqs148142 		goto hxge_get_soft_properties_exit;
14076349Sqs148142 	}
14086349Sqs148142 
14096349Sqs148142 	ddi_status = ddi_dma_addr_bind_handle(hxgep->dmasparehandle, NULL,
14106349Sqs148142 	    (caddr_t)hxgep->dmasparehandle, sizeof (hxgep->dmasparehandle),
14116349Sqs148142 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
14126349Sqs148142 	    &cookie, &count);
14136349Sqs148142 	if (ddi_status != DDI_DMA_MAPPED) {
14146349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
14156349Sqs148142 		    "Binding spare handle to find system burstsize failed."));
14166349Sqs148142 		ddi_status = DDI_FAILURE;
14176349Sqs148142 		goto hxge_get_soft_properties_fail1;
14186349Sqs148142 	}
14196349Sqs148142 
14206349Sqs148142 	hxgep->sys_burst_sz = ddi_dma_burstsizes(hxgep->dmasparehandle);
14216349Sqs148142 	(void) ddi_dma_unbind_handle(hxgep->dmasparehandle);
14226349Sqs148142 
14236349Sqs148142 hxge_get_soft_properties_fail1:
14246349Sqs148142 	ddi_dma_free_handle(&hxgep->dmasparehandle);
14256349Sqs148142 
14266349Sqs148142 hxge_get_soft_properties_exit:
14276349Sqs148142 
14286349Sqs148142 	if (ddi_status != DDI_SUCCESS)
14296349Sqs148142 		status |= (HXGE_ERROR | HXGE_DDI_FAILED);
14306349Sqs148142 
14316349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
14326349Sqs148142 	    "<== hxge_setup_system_dma_pages status = 0x%08x", status));
14336349Sqs148142 
14346349Sqs148142 	return (status);
14356349Sqs148142 }
14366349Sqs148142 
14376349Sqs148142 hxge_status_t
14386349Sqs148142 hxge_alloc_mem_pool(p_hxge_t hxgep)
14396349Sqs148142 {
14406349Sqs148142 	hxge_status_t status = HXGE_OK;
14416349Sqs148142 
14426349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_alloc_mem_pool"));
14436349Sqs148142 
14446349Sqs148142 	status = hxge_alloc_rx_mem_pool(hxgep);
14456349Sqs148142 	if (status != HXGE_OK) {
14466349Sqs148142 		return (HXGE_ERROR);
14476349Sqs148142 	}
14486349Sqs148142 
14496349Sqs148142 	status = hxge_alloc_tx_mem_pool(hxgep);
14506349Sqs148142 	if (status != HXGE_OK) {
14516349Sqs148142 		hxge_free_rx_mem_pool(hxgep);
14526349Sqs148142 		return (HXGE_ERROR);
14536349Sqs148142 	}
14546349Sqs148142 
14556349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_alloc_mem_pool"));
14566349Sqs148142 	return (HXGE_OK);
14576349Sqs148142 }
14586349Sqs148142 
14596349Sqs148142 static void
14606349Sqs148142 hxge_free_mem_pool(p_hxge_t hxgep)
14616349Sqs148142 {
14626349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "==> hxge_free_mem_pool"));
14636349Sqs148142 
14646349Sqs148142 	hxge_free_rx_mem_pool(hxgep);
14656349Sqs148142 	hxge_free_tx_mem_pool(hxgep);
14666349Sqs148142 
14676349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "<== hxge_free_mem_pool"));
14686349Sqs148142 }
14696349Sqs148142 
14706349Sqs148142 static hxge_status_t
14716349Sqs148142 hxge_alloc_rx_mem_pool(p_hxge_t hxgep)
14726349Sqs148142 {
14736349Sqs148142 	int			i, j;
14746349Sqs148142 	uint32_t		ndmas, st_rdc;
14756349Sqs148142 	p_hxge_dma_pt_cfg_t	p_all_cfgp;
14766349Sqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
14776349Sqs148142 	p_hxge_dma_pool_t	dma_poolp;
14786349Sqs148142 	p_hxge_dma_common_t	*dma_buf_p;
14797618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_rbr_cntl_poolp;
14807618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_rbr_cntl_p;
14817618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_rcr_cntl_poolp;
14827618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_rcr_cntl_p;
14837618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_mbox_cntl_poolp;
14847618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_mbox_cntl_p;
14856349Sqs148142 	size_t			rx_buf_alloc_size;
14867618SMichael.Speer@Sun.COM 	size_t			rx_rbr_cntl_alloc_size;
14877618SMichael.Speer@Sun.COM 	size_t			rx_rcr_cntl_alloc_size;
14887618SMichael.Speer@Sun.COM 	size_t			rx_mbox_cntl_alloc_size;
14896349Sqs148142 	uint32_t		*num_chunks;	/* per dma */
14906349Sqs148142 	hxge_status_t		status = HXGE_OK;
14916349Sqs148142 
14926349Sqs148142 	uint32_t		hxge_port_rbr_size;
14936349Sqs148142 	uint32_t		hxge_port_rbr_spare_size;
14946349Sqs148142 	uint32_t		hxge_port_rcr_size;
14956349Sqs148142 
14966349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_alloc_rx_mem_pool"));
14976349Sqs148142 
14986349Sqs148142 	p_all_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
14996349Sqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_all_cfgp->hw_config;
15006349Sqs148142 	st_rdc = p_cfgp->start_rdc;
15016349Sqs148142 	ndmas = p_cfgp->max_rdcs;
15026349Sqs148142 
15036349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
15046349Sqs148142 	    " hxge_alloc_rx_mem_pool st_rdc %d ndmas %d", st_rdc, ndmas));
15056349Sqs148142 
15066349Sqs148142 	/*
15076349Sqs148142 	 * Allocate memory for each receive DMA channel.
15086349Sqs148142 	 */
15096349Sqs148142 	dma_poolp = (p_hxge_dma_pool_t)KMEM_ZALLOC(sizeof (hxge_dma_pool_t),
15106349Sqs148142 	    KM_SLEEP);
15116349Sqs148142 	dma_buf_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
15126349Sqs148142 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
15136349Sqs148142 
15147618SMichael.Speer@Sun.COM 	dma_rbr_cntl_poolp = (p_hxge_dma_pool_t)
15157618SMichael.Speer@Sun.COM 	    KMEM_ZALLOC(sizeof (hxge_dma_pool_t), KM_SLEEP);
15167618SMichael.Speer@Sun.COM 	dma_rbr_cntl_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
15177618SMichael.Speer@Sun.COM 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
15187618SMichael.Speer@Sun.COM 	dma_rcr_cntl_poolp = (p_hxge_dma_pool_t)
15196349Sqs148142 	    KMEM_ZALLOC(sizeof (hxge_dma_pool_t), KM_SLEEP);
15207618SMichael.Speer@Sun.COM 	dma_rcr_cntl_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
15217618SMichael.Speer@Sun.COM 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
15227618SMichael.Speer@Sun.COM 	dma_mbox_cntl_poolp = (p_hxge_dma_pool_t)
15237618SMichael.Speer@Sun.COM 	    KMEM_ZALLOC(sizeof (hxge_dma_pool_t), KM_SLEEP);
15247618SMichael.Speer@Sun.COM 	dma_mbox_cntl_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
15256349Sqs148142 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
15266349Sqs148142 
15276349Sqs148142 	num_chunks = (uint32_t *)KMEM_ZALLOC(sizeof (uint32_t) * ndmas,
15286349Sqs148142 	    KM_SLEEP);
15296349Sqs148142 
15306349Sqs148142 	/*
15316349Sqs148142 	 * Assume that each DMA channel will be configured with default block
15326349Sqs148142 	 * size. rbr block counts are mod of batch count (16).
15336349Sqs148142 	 */
15346349Sqs148142 	hxge_port_rbr_size = p_all_cfgp->rbr_size;
15356349Sqs148142 	hxge_port_rcr_size = p_all_cfgp->rcr_size;
15366349Sqs148142 
15376349Sqs148142 	if (!hxge_port_rbr_size) {
15386349Sqs148142 		hxge_port_rbr_size = HXGE_RBR_RBB_DEFAULT;
15396349Sqs148142 	}
15406349Sqs148142 
15416349Sqs148142 	if (hxge_port_rbr_size % HXGE_RXDMA_POST_BATCH) {
15426349Sqs148142 		hxge_port_rbr_size = (HXGE_RXDMA_POST_BATCH *
15436349Sqs148142 		    (hxge_port_rbr_size / HXGE_RXDMA_POST_BATCH + 1));
15446349Sqs148142 	}
15456349Sqs148142 
15466349Sqs148142 	p_all_cfgp->rbr_size = hxge_port_rbr_size;
15476349Sqs148142 	hxge_port_rbr_spare_size = hxge_rbr_spare_size;
15486349Sqs148142 
15496349Sqs148142 	if (hxge_port_rbr_spare_size % HXGE_RXDMA_POST_BATCH) {
15506349Sqs148142 		hxge_port_rbr_spare_size = (HXGE_RXDMA_POST_BATCH *
15516349Sqs148142 		    (hxge_port_rbr_spare_size / HXGE_RXDMA_POST_BATCH + 1));
15526349Sqs148142 	}
15536349Sqs148142 
15546349Sqs148142 	rx_buf_alloc_size = (hxgep->rx_default_block_size *
15556349Sqs148142 	    (hxge_port_rbr_size + hxge_port_rbr_spare_size));
15566349Sqs148142 
15576349Sqs148142 	/*
15586349Sqs148142 	 * Addresses of receive block ring, receive completion ring and the
15596349Sqs148142 	 * mailbox must be all cache-aligned (64 bytes).
15606349Sqs148142 	 */
15617618SMichael.Speer@Sun.COM 	rx_rbr_cntl_alloc_size = hxge_port_rbr_size + hxge_port_rbr_spare_size;
15627618SMichael.Speer@Sun.COM 	rx_rbr_cntl_alloc_size *= sizeof (rx_desc_t);
15637618SMichael.Speer@Sun.COM 	rx_rcr_cntl_alloc_size = sizeof (rcr_entry_t) * hxge_port_rcr_size;
15647618SMichael.Speer@Sun.COM 	rx_mbox_cntl_alloc_size = sizeof (rxdma_mailbox_t);
15656349Sqs148142 
15666349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "==> hxge_alloc_rx_mem_pool: "
15676349Sqs148142 	    "hxge_port_rbr_size = %d hxge_port_rbr_spare_size = %d "
15686349Sqs148142 	    "hxge_port_rcr_size = %d rx_cntl_alloc_size = %d",
15696349Sqs148142 	    hxge_port_rbr_size, hxge_port_rbr_spare_size,
15706349Sqs148142 	    hxge_port_rcr_size, rx_cntl_alloc_size));
15716349Sqs148142 
15726349Sqs148142 	hxgep->hxge_port_rbr_size = hxge_port_rbr_size;
15736349Sqs148142 	hxgep->hxge_port_rcr_size = hxge_port_rcr_size;
15746349Sqs148142 
15756349Sqs148142 	/*
15766349Sqs148142 	 * Allocate memory for receive buffers and descriptor rings. Replace
15776349Sqs148142 	 * allocation functions with interface functions provided by the
15786349Sqs148142 	 * partition manager when it is available.
15796349Sqs148142 	 */
15806349Sqs148142 	/*
15816349Sqs148142 	 * Allocate memory for the receive buffer blocks.
15826349Sqs148142 	 */
15836349Sqs148142 	for (i = 0; i < ndmas; i++) {
15846349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
15856349Sqs148142 		    " hxge_alloc_rx_mem_pool to alloc mem: "
15866349Sqs148142 		    " dma %d dma_buf_p %llx &dma_buf_p %llx",
15876349Sqs148142 		    i, dma_buf_p[i], &dma_buf_p[i]));
15886349Sqs148142 
15896349Sqs148142 		num_chunks[i] = 0;
15906349Sqs148142 
15916349Sqs148142 		status = hxge_alloc_rx_buf_dma(hxgep, st_rdc, &dma_buf_p[i],
15926349Sqs148142 		    rx_buf_alloc_size, hxgep->rx_default_block_size,
15936349Sqs148142 		    &num_chunks[i]);
15946349Sqs148142 		if (status != HXGE_OK) {
15956349Sqs148142 			break;
15966349Sqs148142 		}
15976349Sqs148142 
15986349Sqs148142 		st_rdc++;
15996349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
16006349Sqs148142 		    " hxge_alloc_rx_mem_pool DONE  alloc mem: "
16016349Sqs148142 		    "dma %d dma_buf_p %llx &dma_buf_p %llx", i,
16026349Sqs148142 		    dma_buf_p[i], &dma_buf_p[i]));
16036349Sqs148142 	}
16046349Sqs148142 
16056349Sqs148142 	if (i < ndmas) {
16066349Sqs148142 		goto hxge_alloc_rx_mem_fail1;
16076349Sqs148142 	}
16086349Sqs148142 
16096349Sqs148142 	/*
16106349Sqs148142 	 * Allocate memory for descriptor rings and mailbox.
16116349Sqs148142 	 */
16126349Sqs148142 	st_rdc = p_cfgp->start_rdc;
16136349Sqs148142 	for (j = 0; j < ndmas; j++) {
16147618SMichael.Speer@Sun.COM 		if ((status = hxge_alloc_rx_cntl_dma(hxgep, st_rdc,
16157618SMichael.Speer@Sun.COM 		    &dma_rbr_cntl_p[j], &hxge_rx_rbr_desc_dma_attr,
16167618SMichael.Speer@Sun.COM 		    rx_rbr_cntl_alloc_size)) != HXGE_OK) {
16177618SMichael.Speer@Sun.COM 			break;
16187618SMichael.Speer@Sun.COM 		}
16197618SMichael.Speer@Sun.COM 
16207618SMichael.Speer@Sun.COM 		if ((status = hxge_alloc_rx_cntl_dma(hxgep, st_rdc,
16217618SMichael.Speer@Sun.COM 		    &dma_rcr_cntl_p[j], &hxge_rx_rcr_desc_dma_attr,
16227618SMichael.Speer@Sun.COM 		    rx_rcr_cntl_alloc_size)) != HXGE_OK) {
16237618SMichael.Speer@Sun.COM 			break;
16247618SMichael.Speer@Sun.COM 		}
16257618SMichael.Speer@Sun.COM 
16267618SMichael.Speer@Sun.COM 		if ((status = hxge_alloc_rx_cntl_dma(hxgep, st_rdc,
16277618SMichael.Speer@Sun.COM 		    &dma_mbox_cntl_p[j], &hxge_rx_mbox_dma_attr,
16287618SMichael.Speer@Sun.COM 		    rx_mbox_cntl_alloc_size)) != HXGE_OK) {
16296349Sqs148142 			break;
16306349Sqs148142 		}
16316349Sqs148142 		st_rdc++;
16326349Sqs148142 	}
16336349Sqs148142 
16346349Sqs148142 	if (j < ndmas) {
16356349Sqs148142 		goto hxge_alloc_rx_mem_fail2;
16366349Sqs148142 	}
16376349Sqs148142 
16386349Sqs148142 	dma_poolp->ndmas = ndmas;
16396349Sqs148142 	dma_poolp->num_chunks = num_chunks;
16406349Sqs148142 	dma_poolp->buf_allocated = B_TRUE;
16416349Sqs148142 	hxgep->rx_buf_pool_p = dma_poolp;
16426349Sqs148142 	dma_poolp->dma_buf_pool_p = dma_buf_p;
16436349Sqs148142 
16447618SMichael.Speer@Sun.COM 	dma_rbr_cntl_poolp->ndmas = ndmas;
16457618SMichael.Speer@Sun.COM 	dma_rbr_cntl_poolp->buf_allocated = B_TRUE;
16467618SMichael.Speer@Sun.COM 	hxgep->rx_rbr_cntl_pool_p = dma_rbr_cntl_poolp;
16477618SMichael.Speer@Sun.COM 	dma_rbr_cntl_poolp->dma_buf_pool_p = dma_rbr_cntl_p;
16487618SMichael.Speer@Sun.COM 
16497618SMichael.Speer@Sun.COM 	dma_rcr_cntl_poolp->ndmas = ndmas;
16507618SMichael.Speer@Sun.COM 	dma_rcr_cntl_poolp->buf_allocated = B_TRUE;
16517618SMichael.Speer@Sun.COM 	hxgep->rx_rcr_cntl_pool_p = dma_rcr_cntl_poolp;
16527618SMichael.Speer@Sun.COM 	dma_rcr_cntl_poolp->dma_buf_pool_p = dma_rcr_cntl_p;
16537618SMichael.Speer@Sun.COM 
16547618SMichael.Speer@Sun.COM 	dma_mbox_cntl_poolp->ndmas = ndmas;
16557618SMichael.Speer@Sun.COM 	dma_mbox_cntl_poolp->buf_allocated = B_TRUE;
16567618SMichael.Speer@Sun.COM 	hxgep->rx_mbox_cntl_pool_p = dma_mbox_cntl_poolp;
16577618SMichael.Speer@Sun.COM 	dma_mbox_cntl_poolp->dma_buf_pool_p = dma_mbox_cntl_p;
16586349Sqs148142 
16596349Sqs148142 	goto hxge_alloc_rx_mem_pool_exit;
16606349Sqs148142 
16616349Sqs148142 hxge_alloc_rx_mem_fail2:
16626349Sqs148142 	/* Free control buffers */
16636349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
16646349Sqs148142 	    "==> hxge_alloc_rx_mem_pool: freeing control bufs (%d)", j));
16656349Sqs148142 	for (; j >= 0; j--) {
16666349Sqs148142 		hxge_free_rx_cntl_dma(hxgep,
16677618SMichael.Speer@Sun.COM 		    (p_hxge_dma_common_t)dma_rbr_cntl_p[j]);
16687618SMichael.Speer@Sun.COM 		hxge_free_rx_cntl_dma(hxgep,
16697618SMichael.Speer@Sun.COM 		    (p_hxge_dma_common_t)dma_rcr_cntl_p[j]);
16707618SMichael.Speer@Sun.COM 		hxge_free_rx_cntl_dma(hxgep,
16717618SMichael.Speer@Sun.COM 		    (p_hxge_dma_common_t)dma_mbox_cntl_p[j]);
16726349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DMA_CTL,
16736349Sqs148142 		    "==> hxge_alloc_rx_mem_pool: control bufs freed (%d)", j));
16746349Sqs148142 	}
16756349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
16766349Sqs148142 	    "==> hxge_alloc_rx_mem_pool: control bufs freed (%d)", j));
16776349Sqs148142 
16786349Sqs148142 hxge_alloc_rx_mem_fail1:
16796349Sqs148142 	/* Free data buffers */
16806349Sqs148142 	i--;
16816349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
16826349Sqs148142 	    "==> hxge_alloc_rx_mem_pool: freeing data bufs (%d)", i));
16836349Sqs148142 	for (; i >= 0; i--) {
16846349Sqs148142 		hxge_free_rx_buf_dma(hxgep, (p_hxge_dma_common_t)dma_buf_p[i],
16856349Sqs148142 		    num_chunks[i]);
16866349Sqs148142 	}
16876349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
16886349Sqs148142 	    "==> hxge_alloc_rx_mem_pool: data bufs freed (%d)", i));
16896349Sqs148142 
16906349Sqs148142 	KMEM_FREE(num_chunks, sizeof (uint32_t) * ndmas);
16916349Sqs148142 	KMEM_FREE(dma_poolp, sizeof (hxge_dma_pool_t));
16926349Sqs148142 	KMEM_FREE(dma_buf_p, ndmas * sizeof (p_hxge_dma_common_t));
16937618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rbr_cntl_poolp, sizeof (hxge_dma_pool_t));
16947618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rbr_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
16957618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rcr_cntl_poolp, sizeof (hxge_dma_pool_t));
16967618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rcr_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
16977618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_mbox_cntl_poolp, sizeof (hxge_dma_pool_t));
16987618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_mbox_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
16996349Sqs148142 
17006349Sqs148142 hxge_alloc_rx_mem_pool_exit:
17016349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
17026349Sqs148142 	    "<== hxge_alloc_rx_mem_pool:status 0x%08x", status));
17036349Sqs148142 
17046349Sqs148142 	return (status);
17056349Sqs148142 }
17066349Sqs148142 
17076349Sqs148142 static void
17086349Sqs148142 hxge_free_rx_mem_pool(p_hxge_t hxgep)
17096349Sqs148142 {
17106349Sqs148142 	uint32_t		i, ndmas;
17116349Sqs148142 	p_hxge_dma_pool_t	dma_poolp;
17126349Sqs148142 	p_hxge_dma_common_t	*dma_buf_p;
17137618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_rbr_cntl_poolp;
17147618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_rbr_cntl_p;
17157618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_rcr_cntl_poolp;
17167618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_rcr_cntl_p;
17177618SMichael.Speer@Sun.COM 	p_hxge_dma_pool_t	dma_mbox_cntl_poolp;
17187618SMichael.Speer@Sun.COM 	p_hxge_dma_common_t	*dma_mbox_cntl_p;
17196349Sqs148142 	uint32_t		*num_chunks;
17206349Sqs148142 
17216349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "==> hxge_free_rx_mem_pool"));
17226349Sqs148142 
17236349Sqs148142 	dma_poolp = hxgep->rx_buf_pool_p;
17246349Sqs148142 	if (dma_poolp == NULL || (!dma_poolp->buf_allocated)) {
17256349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "<== hxge_free_rx_mem_pool "
17266349Sqs148142 		    "(null rx buf pool or buf not allocated"));
17276349Sqs148142 		return;
17286349Sqs148142 	}
17296349Sqs148142 
17307618SMichael.Speer@Sun.COM 	dma_rbr_cntl_poolp = hxgep->rx_rbr_cntl_pool_p;
17317618SMichael.Speer@Sun.COM 	if (dma_rbr_cntl_poolp == NULL ||
17327618SMichael.Speer@Sun.COM 	    (!dma_rbr_cntl_poolp->buf_allocated)) {
17336349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
17346349Sqs148142 		    "<== hxge_free_rx_mem_pool "
17357618SMichael.Speer@Sun.COM 		    "(null rbr cntl buf pool or rbr cntl buf not allocated"));
17367618SMichael.Speer@Sun.COM 		return;
17377618SMichael.Speer@Sun.COM 	}
17387618SMichael.Speer@Sun.COM 
17397618SMichael.Speer@Sun.COM 	dma_rcr_cntl_poolp = hxgep->rx_rcr_cntl_pool_p;
17407618SMichael.Speer@Sun.COM 	if (dma_rcr_cntl_poolp == NULL ||
17417618SMichael.Speer@Sun.COM 	    (!dma_rcr_cntl_poolp->buf_allocated)) {
17427618SMichael.Speer@Sun.COM 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
17437618SMichael.Speer@Sun.COM 		    "<== hxge_free_rx_mem_pool "
17447618SMichael.Speer@Sun.COM 		    "(null rcr cntl buf pool or rcr cntl buf not allocated"));
17457618SMichael.Speer@Sun.COM 		return;
17467618SMichael.Speer@Sun.COM 	}
17477618SMichael.Speer@Sun.COM 
17487618SMichael.Speer@Sun.COM 	dma_mbox_cntl_poolp = hxgep->rx_mbox_cntl_pool_p;
17497618SMichael.Speer@Sun.COM 	if (dma_mbox_cntl_poolp == NULL ||
17507618SMichael.Speer@Sun.COM 	    (!dma_mbox_cntl_poolp->buf_allocated)) {
17517618SMichael.Speer@Sun.COM 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
17527618SMichael.Speer@Sun.COM 		    "<== hxge_free_rx_mem_pool "
17537618SMichael.Speer@Sun.COM 		    "(null mbox cntl buf pool or mbox cntl buf not allocated"));
17546349Sqs148142 		return;
17556349Sqs148142 	}
17566349Sqs148142 
17576349Sqs148142 	dma_buf_p = dma_poolp->dma_buf_pool_p;
17586349Sqs148142 	num_chunks = dma_poolp->num_chunks;
17596349Sqs148142 
17607618SMichael.Speer@Sun.COM 	dma_rbr_cntl_p = dma_rbr_cntl_poolp->dma_buf_pool_p;
17617618SMichael.Speer@Sun.COM 	dma_rcr_cntl_p = dma_rcr_cntl_poolp->dma_buf_pool_p;
17627618SMichael.Speer@Sun.COM 	dma_mbox_cntl_p = dma_mbox_cntl_poolp->dma_buf_pool_p;
17637618SMichael.Speer@Sun.COM 	ndmas = dma_rbr_cntl_poolp->ndmas;
17646349Sqs148142 
17656349Sqs148142 	for (i = 0; i < ndmas; i++) {
17666349Sqs148142 		hxge_free_rx_buf_dma(hxgep, dma_buf_p[i], num_chunks[i]);
17676349Sqs148142 	}
17686349Sqs148142 
17696349Sqs148142 	for (i = 0; i < ndmas; i++) {
17707618SMichael.Speer@Sun.COM 		hxge_free_rx_cntl_dma(hxgep, dma_rbr_cntl_p[i]);
17717618SMichael.Speer@Sun.COM 		hxge_free_rx_cntl_dma(hxgep, dma_rcr_cntl_p[i]);
17727618SMichael.Speer@Sun.COM 		hxge_free_rx_cntl_dma(hxgep, dma_mbox_cntl_p[i]);
17736349Sqs148142 	}
17746349Sqs148142 
17756349Sqs148142 	for (i = 0; i < ndmas; i++) {
17766349Sqs148142 		KMEM_FREE(dma_buf_p[i],
17776349Sqs148142 		    sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK);
17787618SMichael.Speer@Sun.COM 		KMEM_FREE(dma_rbr_cntl_p[i], sizeof (hxge_dma_common_t));
17797618SMichael.Speer@Sun.COM 		KMEM_FREE(dma_rcr_cntl_p[i], sizeof (hxge_dma_common_t));
17807618SMichael.Speer@Sun.COM 		KMEM_FREE(dma_mbox_cntl_p[i], sizeof (hxge_dma_common_t));
17816349Sqs148142 	}
17826349Sqs148142 
17836349Sqs148142 	KMEM_FREE(num_chunks, sizeof (uint32_t) * ndmas);
17847618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rbr_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
17857618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rbr_cntl_poolp, sizeof (hxge_dma_pool_t));
17867618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rcr_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
17877618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_rcr_cntl_poolp, sizeof (hxge_dma_pool_t));
17887618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_mbox_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
17897618SMichael.Speer@Sun.COM 	KMEM_FREE(dma_mbox_cntl_poolp, sizeof (hxge_dma_pool_t));
17906349Sqs148142 	KMEM_FREE(dma_buf_p, ndmas * sizeof (p_hxge_dma_common_t));
17916349Sqs148142 	KMEM_FREE(dma_poolp, sizeof (hxge_dma_pool_t));
17926349Sqs148142 
17936349Sqs148142 	hxgep->rx_buf_pool_p = NULL;
17947618SMichael.Speer@Sun.COM 	hxgep->rx_rbr_cntl_pool_p = NULL;
17957618SMichael.Speer@Sun.COM 	hxgep->rx_rcr_cntl_pool_p = NULL;
17967618SMichael.Speer@Sun.COM 	hxgep->rx_mbox_cntl_pool_p = NULL;
17976349Sqs148142 
17986349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "<== hxge_free_rx_mem_pool"));
17996349Sqs148142 }
18006349Sqs148142 
18016349Sqs148142 static hxge_status_t
18026349Sqs148142 hxge_alloc_rx_buf_dma(p_hxge_t hxgep, uint16_t dma_channel,
18036349Sqs148142     p_hxge_dma_common_t *dmap,
18046349Sqs148142     size_t alloc_size, size_t block_size, uint32_t *num_chunks)
18056349Sqs148142 {
18066349Sqs148142 	p_hxge_dma_common_t	rx_dmap;
18076349Sqs148142 	hxge_status_t		status = HXGE_OK;
18086349Sqs148142 	size_t			total_alloc_size;
18096349Sqs148142 	size_t			allocated = 0;
18106349Sqs148142 	int			i, size_index, array_size;
18116349Sqs148142 
18126349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_alloc_rx_buf_dma"));
18136349Sqs148142 
18146349Sqs148142 	rx_dmap = (p_hxge_dma_common_t)
18156349Sqs148142 	    KMEM_ZALLOC(sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK, KM_SLEEP);
18166349Sqs148142 
18176349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
18186349Sqs148142 	    " alloc_rx_buf_dma rdc %d asize %x bsize %x bbuf %llx ",
18196349Sqs148142 	    dma_channel, alloc_size, block_size, dmap));
18206349Sqs148142 
18216349Sqs148142 	total_alloc_size = alloc_size;
18226349Sqs148142 
18236349Sqs148142 	i = 0;
18246349Sqs148142 	size_index = 0;
18256349Sqs148142 	array_size = sizeof (alloc_sizes) / sizeof (size_t);
18266349Sqs148142 	while ((alloc_sizes[size_index] < alloc_size) &&
18276349Sqs148142 	    (size_index < array_size))
18286349Sqs148142 		size_index++;
18296349Sqs148142 	if (size_index >= array_size) {
18306349Sqs148142 		size_index = array_size - 1;
18316349Sqs148142 	}
18326349Sqs148142 
18336349Sqs148142 	while ((allocated < total_alloc_size) &&
18346349Sqs148142 	    (size_index >= 0) && (i < HXGE_DMA_BLOCK)) {
18356349Sqs148142 		rx_dmap[i].dma_chunk_index = i;
18366349Sqs148142 		rx_dmap[i].block_size = block_size;
18376349Sqs148142 		rx_dmap[i].alength = alloc_sizes[size_index];
18386349Sqs148142 		rx_dmap[i].orig_alength = rx_dmap[i].alength;
18396349Sqs148142 		rx_dmap[i].nblocks = alloc_sizes[size_index] / block_size;
18406349Sqs148142 		rx_dmap[i].dma_channel = dma_channel;
18416349Sqs148142 		rx_dmap[i].contig_alloc_type = B_FALSE;
18426349Sqs148142 
18436349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
18446349Sqs148142 		    "alloc_rx_buf_dma rdc %d chunk %d bufp %llx size %x "
18456349Sqs148142 		    "i %d nblocks %d alength %d",
18466349Sqs148142 		    dma_channel, i, &rx_dmap[i], block_size,
18476349Sqs148142 		    i, rx_dmap[i].nblocks, rx_dmap[i].alength));
18486349Sqs148142 		status = hxge_dma_mem_alloc(hxgep, hxge_force_dma,
18496349Sqs148142 		    &hxge_rx_dma_attr, rx_dmap[i].alength,
18506349Sqs148142 		    &hxge_dev_buf_dma_acc_attr,
18516349Sqs148142 		    DDI_DMA_READ | DDI_DMA_STREAMING,
18526349Sqs148142 		    (p_hxge_dma_common_t)(&rx_dmap[i]));
18536349Sqs148142 		if (status != HXGE_OK) {
18546349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DMA_CTL,
18556349Sqs148142 			    " hxge_alloc_rx_buf_dma: Alloc Failed: "
18566349Sqs148142 			    " for size: %d", alloc_sizes[size_index]));
18576349Sqs148142 			size_index--;
18586349Sqs148142 		} else {
18596349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DMA_CTL,
18606349Sqs148142 			    " alloc_rx_buf_dma allocated rdc %d "
18616349Sqs148142 			    "chunk %d size %x dvma %x bufp %llx ",
18626349Sqs148142 			    dma_channel, i, rx_dmap[i].alength,
18636349Sqs148142 			    rx_dmap[i].ioaddr_pp, &rx_dmap[i]));
18646349Sqs148142 			i++;
18656349Sqs148142 			allocated += alloc_sizes[size_index];
18666349Sqs148142 		}
18676349Sqs148142 	}
18686349Sqs148142 
18696349Sqs148142 	if (allocated < total_alloc_size) {
18706349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
18716349Sqs148142 		    " hxge_alloc_rx_buf_dma failed due to"
18726349Sqs148142 		    " allocated(%d) < required(%d)",
18736349Sqs148142 		    allocated, total_alloc_size));
18746349Sqs148142 		goto hxge_alloc_rx_mem_fail1;
18756349Sqs148142 	}
18766349Sqs148142 
18776349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
18786349Sqs148142 	    " alloc_rx_buf_dma rdc %d allocated %d chunks", dma_channel, i));
18796349Sqs148142 
18806349Sqs148142 	*num_chunks = i;
18816349Sqs148142 	*dmap = rx_dmap;
18826349Sqs148142 
18836349Sqs148142 	goto hxge_alloc_rx_mem_exit;
18846349Sqs148142 
18856349Sqs148142 hxge_alloc_rx_mem_fail1:
18866349Sqs148142 	KMEM_FREE(rx_dmap, sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK);
18876349Sqs148142 
18886349Sqs148142 hxge_alloc_rx_mem_exit:
18896349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
18906349Sqs148142 	    "<== hxge_alloc_rx_buf_dma status 0x%08x", status));
18916349Sqs148142 
18926349Sqs148142 	return (status);
18936349Sqs148142 }
18946349Sqs148142 
18956349Sqs148142 /*ARGSUSED*/
18966349Sqs148142 static void
18976349Sqs148142 hxge_free_rx_buf_dma(p_hxge_t hxgep, p_hxge_dma_common_t dmap,
18986349Sqs148142     uint32_t num_chunks)
18996349Sqs148142 {
19006349Sqs148142 	int i;
19016349Sqs148142 
19026349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
19036349Sqs148142 	    "==> hxge_free_rx_buf_dma: # of chunks %d", num_chunks));
19046349Sqs148142 
19056349Sqs148142 	for (i = 0; i < num_chunks; i++) {
19066349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
19076349Sqs148142 		    "==> hxge_free_rx_buf_dma: chunk %d dmap 0x%llx", i, dmap));
19086349Sqs148142 		hxge_dma_mem_free(dmap++);
19096349Sqs148142 	}
19106349Sqs148142 
19116349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM2_CTL, "<== hxge_free_rx_buf_dma"));
19126349Sqs148142 }
19136349Sqs148142 
19146349Sqs148142 /*ARGSUSED*/
19156349Sqs148142 static hxge_status_t
19166349Sqs148142 hxge_alloc_rx_cntl_dma(p_hxge_t hxgep, uint16_t dma_channel,
19177618SMichael.Speer@Sun.COM     p_hxge_dma_common_t *dmap, struct ddi_dma_attr *attr, size_t size)
19186349Sqs148142 {
19196349Sqs148142 	p_hxge_dma_common_t	rx_dmap;
19206349Sqs148142 	hxge_status_t		status = HXGE_OK;
19216349Sqs148142 
19226349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_alloc_rx_cntl_dma"));
19236349Sqs148142 
19246349Sqs148142 	rx_dmap = (p_hxge_dma_common_t)
19256349Sqs148142 	    KMEM_ZALLOC(sizeof (hxge_dma_common_t), KM_SLEEP);
19266349Sqs148142 
19276349Sqs148142 	rx_dmap->contig_alloc_type = B_FALSE;
19286349Sqs148142 
19296349Sqs148142 	status = hxge_dma_mem_alloc(hxgep, hxge_force_dma,
19307618SMichael.Speer@Sun.COM 	    attr, size, &hxge_dev_desc_dma_acc_attr,
19316349Sqs148142 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, rx_dmap);
19326349Sqs148142 	if (status != HXGE_OK) {
19336349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
19346349Sqs148142 		    " hxge_alloc_rx_cntl_dma: Alloc Failed: "
19356349Sqs148142 		    " for size: %d", size));
19366349Sqs148142 		goto hxge_alloc_rx_cntl_dma_fail1;
19376349Sqs148142 	}
19386349Sqs148142 
19396349Sqs148142 	*dmap = rx_dmap;
19406349Sqs148142 
19416349Sqs148142 	goto hxge_alloc_rx_cntl_dma_exit;
19426349Sqs148142 
19436349Sqs148142 hxge_alloc_rx_cntl_dma_fail1:
19446349Sqs148142 	KMEM_FREE(rx_dmap, sizeof (hxge_dma_common_t));
19456349Sqs148142 
19466349Sqs148142 hxge_alloc_rx_cntl_dma_exit:
19476349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
19486349Sqs148142 	    "<== hxge_alloc_rx_cntl_dma status 0x%08x", status));
19496349Sqs148142 
19506349Sqs148142 	return (status);
19516349Sqs148142 }
19526349Sqs148142 
19536349Sqs148142 /*ARGSUSED*/
19546349Sqs148142 static void
19556349Sqs148142 hxge_free_rx_cntl_dma(p_hxge_t hxgep, p_hxge_dma_common_t dmap)
19566349Sqs148142 {
19576349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_free_rx_cntl_dma"));
19586349Sqs148142 
19596349Sqs148142 	hxge_dma_mem_free(dmap);
19606349Sqs148142 
19616349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_free_rx_cntl_dma"));
19626349Sqs148142 }
19636349Sqs148142 
19646349Sqs148142 static hxge_status_t
19656349Sqs148142 hxge_alloc_tx_mem_pool(p_hxge_t hxgep)
19666349Sqs148142 {
19676349Sqs148142 	hxge_status_t		status = HXGE_OK;
19686349Sqs148142 	int			i, j;
19696349Sqs148142 	uint32_t		ndmas, st_tdc;
19706349Sqs148142 	p_hxge_dma_pt_cfg_t	p_all_cfgp;
19716349Sqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
19726349Sqs148142 	p_hxge_dma_pool_t	dma_poolp;
19736349Sqs148142 	p_hxge_dma_common_t	*dma_buf_p;
19746349Sqs148142 	p_hxge_dma_pool_t	dma_cntl_poolp;
19756349Sqs148142 	p_hxge_dma_common_t	*dma_cntl_p;
19766349Sqs148142 	size_t			tx_buf_alloc_size;
19776349Sqs148142 	size_t			tx_cntl_alloc_size;
19786349Sqs148142 	uint32_t		*num_chunks;	/* per dma */
19796349Sqs148142 
19806349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "==> hxge_alloc_tx_mem_pool"));
19816349Sqs148142 
19826349Sqs148142 	p_all_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
19836349Sqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_all_cfgp->hw_config;
19846349Sqs148142 	st_tdc = p_cfgp->start_tdc;
19856349Sqs148142 	ndmas = p_cfgp->max_tdcs;
19866349Sqs148142 
19876349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "==> hxge_alloc_tx_mem_pool: "
19886349Sqs148142 	    "p_cfgp 0x%016llx start_tdc %d ndmas %d hxgep->max_tdcs %d",
19896349Sqs148142 	    p_cfgp, p_cfgp->start_tdc, p_cfgp->max_tdcs, hxgep->max_tdcs));
19906349Sqs148142 	/*
19916349Sqs148142 	 * Allocate memory for each transmit DMA channel.
19926349Sqs148142 	 */
19936349Sqs148142 	dma_poolp = (p_hxge_dma_pool_t)KMEM_ZALLOC(sizeof (hxge_dma_pool_t),
19946349Sqs148142 	    KM_SLEEP);
19956349Sqs148142 	dma_buf_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
19966349Sqs148142 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
19976349Sqs148142 
19986349Sqs148142 	dma_cntl_poolp = (p_hxge_dma_pool_t)
19996349Sqs148142 	    KMEM_ZALLOC(sizeof (hxge_dma_pool_t), KM_SLEEP);
20006349Sqs148142 	dma_cntl_p = (p_hxge_dma_common_t *)KMEM_ZALLOC(
20016349Sqs148142 	    sizeof (p_hxge_dma_common_t) * ndmas, KM_SLEEP);
20026349Sqs148142 
20036349Sqs148142 	hxgep->hxge_port_tx_ring_size = hxge_tx_ring_size;
20046349Sqs148142 
20056349Sqs148142 	/*
20066349Sqs148142 	 * Assume that each DMA channel will be configured with default
20076349Sqs148142 	 * transmit bufer size for copying transmit data. (For packet payload
20086349Sqs148142 	 * over this limit, packets will not be copied.)
20096349Sqs148142 	 */
20106349Sqs148142 	tx_buf_alloc_size = (hxge_bcopy_thresh * hxge_tx_ring_size);
20116349Sqs148142 
20126349Sqs148142 	/*
20136349Sqs148142 	 * Addresses of transmit descriptor ring and the mailbox must be all
20146349Sqs148142 	 * cache-aligned (64 bytes).
20156349Sqs148142 	 */
20166349Sqs148142 	tx_cntl_alloc_size = hxge_tx_ring_size;
20176349Sqs148142 	tx_cntl_alloc_size *= (sizeof (tx_desc_t));
20186349Sqs148142 	tx_cntl_alloc_size += sizeof (txdma_mailbox_t);
20196349Sqs148142 
20206349Sqs148142 	num_chunks = (uint32_t *)KMEM_ZALLOC(sizeof (uint32_t) * ndmas,
20216349Sqs148142 	    KM_SLEEP);
20226349Sqs148142 
20236349Sqs148142 	/*
20246349Sqs148142 	 * Allocate memory for transmit buffers and descriptor rings. Replace
20256349Sqs148142 	 * allocation functions with interface functions provided by the
20266349Sqs148142 	 * partition manager when it is available.
20276349Sqs148142 	 *
20286349Sqs148142 	 * Allocate memory for the transmit buffer pool.
20296349Sqs148142 	 */
20306349Sqs148142 	for (i = 0; i < ndmas; i++) {
20316349Sqs148142 		num_chunks[i] = 0;
20326349Sqs148142 		status = hxge_alloc_tx_buf_dma(hxgep, st_tdc, &dma_buf_p[i],
20336349Sqs148142 		    tx_buf_alloc_size, hxge_bcopy_thresh, &num_chunks[i]);
20346349Sqs148142 		if (status != HXGE_OK) {
20356349Sqs148142 			break;
20366349Sqs148142 		}
20376349Sqs148142 		st_tdc++;
20386349Sqs148142 	}
20396349Sqs148142 
20406349Sqs148142 	if (i < ndmas) {
20416349Sqs148142 		goto hxge_alloc_tx_mem_pool_fail1;
20426349Sqs148142 	}
20436349Sqs148142 
20446349Sqs148142 	st_tdc = p_cfgp->start_tdc;
20456349Sqs148142 
20466349Sqs148142 	/*
20476349Sqs148142 	 * Allocate memory for descriptor rings and mailbox.
20486349Sqs148142 	 */
20496349Sqs148142 	for (j = 0; j < ndmas; j++) {
20506349Sqs148142 		status = hxge_alloc_tx_cntl_dma(hxgep, st_tdc, &dma_cntl_p[j],
20516349Sqs148142 		    tx_cntl_alloc_size);
20526349Sqs148142 		if (status != HXGE_OK) {
20536349Sqs148142 			break;
20546349Sqs148142 		}
20556349Sqs148142 		st_tdc++;
20566349Sqs148142 	}
20576349Sqs148142 
20586349Sqs148142 	if (j < ndmas) {
20596349Sqs148142 		goto hxge_alloc_tx_mem_pool_fail2;
20606349Sqs148142 	}
20616349Sqs148142 
20626349Sqs148142 	dma_poolp->ndmas = ndmas;
20636349Sqs148142 	dma_poolp->num_chunks = num_chunks;
20646349Sqs148142 	dma_poolp->buf_allocated = B_TRUE;
20656349Sqs148142 	dma_poolp->dma_buf_pool_p = dma_buf_p;
20666349Sqs148142 	hxgep->tx_buf_pool_p = dma_poolp;
20676349Sqs148142 
20686349Sqs148142 	dma_cntl_poolp->ndmas = ndmas;
20696349Sqs148142 	dma_cntl_poolp->buf_allocated = B_TRUE;
20706349Sqs148142 	dma_cntl_poolp->dma_buf_pool_p = dma_cntl_p;
20716349Sqs148142 	hxgep->tx_cntl_pool_p = dma_cntl_poolp;
20726349Sqs148142 
20736349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL,
20746349Sqs148142 	    "==> hxge_alloc_tx_mem_pool: start_tdc %d "
20756349Sqs148142 	    "ndmas %d poolp->ndmas %d", st_tdc, ndmas, dma_poolp->ndmas));
20766349Sqs148142 
20776349Sqs148142 	goto hxge_alloc_tx_mem_pool_exit;
20786349Sqs148142 
20796349Sqs148142 hxge_alloc_tx_mem_pool_fail2:
20806349Sqs148142 	/* Free control buffers */
20816349Sqs148142 	j--;
20826349Sqs148142 	for (; j >= 0; j--) {
20836349Sqs148142 		hxge_free_tx_cntl_dma(hxgep,
20846349Sqs148142 		    (p_hxge_dma_common_t)dma_cntl_p[j]);
20856349Sqs148142 	}
20866349Sqs148142 
20876349Sqs148142 hxge_alloc_tx_mem_pool_fail1:
20886349Sqs148142 	/* Free data buffers */
20896349Sqs148142 	i--;
20906349Sqs148142 	for (; i >= 0; i--) {
20916349Sqs148142 		hxge_free_tx_buf_dma(hxgep, (p_hxge_dma_common_t)dma_buf_p[i],
20926349Sqs148142 		    num_chunks[i]);
20936349Sqs148142 	}
20946349Sqs148142 
20956349Sqs148142 	KMEM_FREE(dma_poolp, sizeof (hxge_dma_pool_t));
20966349Sqs148142 	KMEM_FREE(dma_buf_p, ndmas * sizeof (p_hxge_dma_common_t));
20976349Sqs148142 	KMEM_FREE(dma_cntl_poolp, sizeof (hxge_dma_pool_t));
20986349Sqs148142 	KMEM_FREE(dma_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
20996349Sqs148142 	KMEM_FREE(num_chunks, sizeof (uint32_t) * ndmas);
21006349Sqs148142 
21016349Sqs148142 hxge_alloc_tx_mem_pool_exit:
21026349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL,
21036349Sqs148142 	    "<== hxge_alloc_tx_mem_pool:status 0x%08x", status));
21046349Sqs148142 
21056349Sqs148142 	return (status);
21066349Sqs148142 }
21076349Sqs148142 
21086349Sqs148142 static hxge_status_t
21096349Sqs148142 hxge_alloc_tx_buf_dma(p_hxge_t hxgep, uint16_t dma_channel,
21106349Sqs148142     p_hxge_dma_common_t *dmap, size_t alloc_size,
21116349Sqs148142     size_t block_size, uint32_t *num_chunks)
21126349Sqs148142 {
21136349Sqs148142 	p_hxge_dma_common_t	tx_dmap;
21146349Sqs148142 	hxge_status_t		status = HXGE_OK;
21156349Sqs148142 	size_t			total_alloc_size;
21166349Sqs148142 	size_t			allocated = 0;
21176349Sqs148142 	int			i, size_index, array_size;
21186349Sqs148142 
21196349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_alloc_tx_buf_dma"));
21206349Sqs148142 
21216349Sqs148142 	tx_dmap = (p_hxge_dma_common_t)
21226349Sqs148142 	    KMEM_ZALLOC(sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK, KM_SLEEP);
21236349Sqs148142 
21246349Sqs148142 	total_alloc_size = alloc_size;
21256349Sqs148142 	i = 0;
21266349Sqs148142 	size_index = 0;
21276349Sqs148142 	array_size = sizeof (alloc_sizes) / sizeof (size_t);
21286349Sqs148142 	while ((alloc_sizes[size_index] < alloc_size) &&
21296349Sqs148142 	    (size_index < array_size))
21306349Sqs148142 		size_index++;
21316349Sqs148142 	if (size_index >= array_size) {
21326349Sqs148142 		size_index = array_size - 1;
21336349Sqs148142 	}
21346349Sqs148142 
21356349Sqs148142 	while ((allocated < total_alloc_size) &&
21366349Sqs148142 	    (size_index >= 0) && (i < HXGE_DMA_BLOCK)) {
21376349Sqs148142 		tx_dmap[i].dma_chunk_index = i;
21386349Sqs148142 		tx_dmap[i].block_size = block_size;
21396349Sqs148142 		tx_dmap[i].alength = alloc_sizes[size_index];
21406349Sqs148142 		tx_dmap[i].orig_alength = tx_dmap[i].alength;
21416349Sqs148142 		tx_dmap[i].nblocks = alloc_sizes[size_index] / block_size;
21426349Sqs148142 		tx_dmap[i].dma_channel = dma_channel;
21436349Sqs148142 		tx_dmap[i].contig_alloc_type = B_FALSE;
21446349Sqs148142 
21456349Sqs148142 		status = hxge_dma_mem_alloc(hxgep, hxge_force_dma,
21466349Sqs148142 		    &hxge_tx_dma_attr, tx_dmap[i].alength,
21476349Sqs148142 		    &hxge_dev_buf_dma_acc_attr,
21486349Sqs148142 		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
21496349Sqs148142 		    (p_hxge_dma_common_t)(&tx_dmap[i]));
21506349Sqs148142 		if (status != HXGE_OK) {
21516349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DMA_CTL,
21526349Sqs148142 			    " hxge_alloc_tx_buf_dma: Alloc Failed: "
21536349Sqs148142 			    " for size: %d", alloc_sizes[size_index]));
21546349Sqs148142 			size_index--;
21556349Sqs148142 		} else {
21566349Sqs148142 			i++;
21576349Sqs148142 			allocated += alloc_sizes[size_index];
21586349Sqs148142 		}
21596349Sqs148142 	}
21606349Sqs148142 
21616349Sqs148142 	if (allocated < total_alloc_size) {
21626349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
21636349Sqs148142 		    " hxge_alloc_tx_buf_dma: failed due to"
21646349Sqs148142 		    " allocated(%d) < required(%d)",
21656349Sqs148142 		    allocated, total_alloc_size));
21666349Sqs148142 		goto hxge_alloc_tx_mem_fail1;
21676349Sqs148142 	}
21686349Sqs148142 
21696349Sqs148142 	*num_chunks = i;
21706349Sqs148142 	*dmap = tx_dmap;
21716349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
21726349Sqs148142 	    "==> hxge_alloc_tx_buf_dma dmap 0x%016llx num chunks %d",
21736349Sqs148142 	    *dmap, i));
21746349Sqs148142 	goto hxge_alloc_tx_mem_exit;
21756349Sqs148142 
21766349Sqs148142 hxge_alloc_tx_mem_fail1:
21776349Sqs148142 	KMEM_FREE(tx_dmap, sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK);
21786349Sqs148142 
21796349Sqs148142 hxge_alloc_tx_mem_exit:
21806349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
21816349Sqs148142 	    "<== hxge_alloc_tx_buf_dma status 0x%08x", status));
21826349Sqs148142 
21836349Sqs148142 	return (status);
21846349Sqs148142 }
21856349Sqs148142 
21866349Sqs148142 /*ARGSUSED*/
21876349Sqs148142 static void
21886349Sqs148142 hxge_free_tx_buf_dma(p_hxge_t hxgep, p_hxge_dma_common_t dmap,
21896349Sqs148142     uint32_t num_chunks)
21906349Sqs148142 {
21916349Sqs148142 	int i;
21926349Sqs148142 
21936349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "==> hxge_free_tx_buf_dma"));
21946349Sqs148142 
21956349Sqs148142 	for (i = 0; i < num_chunks; i++) {
21966349Sqs148142 		hxge_dma_mem_free(dmap++);
21976349Sqs148142 	}
21986349Sqs148142 
21996349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM_CTL, "<== hxge_free_tx_buf_dma"));
22006349Sqs148142 }
22016349Sqs148142 
22026349Sqs148142 /*ARGSUSED*/
22036349Sqs148142 static hxge_status_t
22046349Sqs148142 hxge_alloc_tx_cntl_dma(p_hxge_t hxgep, uint16_t dma_channel,
22056349Sqs148142     p_hxge_dma_common_t *dmap, size_t size)
22066349Sqs148142 {
22076349Sqs148142 	p_hxge_dma_common_t	tx_dmap;
22086349Sqs148142 	hxge_status_t		status = HXGE_OK;
22096349Sqs148142 
22106349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_alloc_tx_cntl_dma"));
22116349Sqs148142 
22126349Sqs148142 	tx_dmap = (p_hxge_dma_common_t)KMEM_ZALLOC(sizeof (hxge_dma_common_t),
22136349Sqs148142 	    KM_SLEEP);
22146349Sqs148142 
22156349Sqs148142 	tx_dmap->contig_alloc_type = B_FALSE;
22166349Sqs148142 
22176349Sqs148142 	status = hxge_dma_mem_alloc(hxgep, hxge_force_dma,
22187618SMichael.Speer@Sun.COM 	    &hxge_tx_desc_dma_attr, size, &hxge_dev_desc_dma_acc_attr,
22196349Sqs148142 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, tx_dmap);
22206349Sqs148142 	if (status != HXGE_OK) {
22216349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
22226349Sqs148142 		    " hxge_alloc_tx_cntl_dma: Alloc Failed: "
22236349Sqs148142 		    " for size: %d", size));
22246349Sqs148142 		goto hxge_alloc_tx_cntl_dma_fail1;
22256349Sqs148142 	}
22266349Sqs148142 
22276349Sqs148142 	*dmap = tx_dmap;
22286349Sqs148142 
22296349Sqs148142 	goto hxge_alloc_tx_cntl_dma_exit;
22306349Sqs148142 
22316349Sqs148142 hxge_alloc_tx_cntl_dma_fail1:
22326349Sqs148142 	KMEM_FREE(tx_dmap, sizeof (hxge_dma_common_t));
22336349Sqs148142 
22346349Sqs148142 hxge_alloc_tx_cntl_dma_exit:
22356349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL,
22366349Sqs148142 	    "<== hxge_alloc_tx_cntl_dma status 0x%08x", status));
22376349Sqs148142 
22386349Sqs148142 	return (status);
22396349Sqs148142 }
22406349Sqs148142 
22416349Sqs148142 /*ARGSUSED*/
22426349Sqs148142 static void
22436349Sqs148142 hxge_free_tx_cntl_dma(p_hxge_t hxgep, p_hxge_dma_common_t dmap)
22446349Sqs148142 {
22456349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "==> hxge_free_tx_cntl_dma"));
22466349Sqs148142 
22476349Sqs148142 	hxge_dma_mem_free(dmap);
22486349Sqs148142 
22496349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_free_tx_cntl_dma"));
22506349Sqs148142 }
22516349Sqs148142 
22526349Sqs148142 static void
22536349Sqs148142 hxge_free_tx_mem_pool(p_hxge_t hxgep)
22546349Sqs148142 {
22556349Sqs148142 	uint32_t		i, ndmas;
22566349Sqs148142 	p_hxge_dma_pool_t	dma_poolp;
22576349Sqs148142 	p_hxge_dma_common_t	*dma_buf_p;
22586349Sqs148142 	p_hxge_dma_pool_t	dma_cntl_poolp;
22596349Sqs148142 	p_hxge_dma_common_t	*dma_cntl_p;
22606349Sqs148142 	uint32_t		*num_chunks;
22616349Sqs148142 
22626349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM3_CTL, "==> hxge_free_tx_mem_pool"));
22636349Sqs148142 
22646349Sqs148142 	dma_poolp = hxgep->tx_buf_pool_p;
22656349Sqs148142 	if (dma_poolp == NULL || (!dma_poolp->buf_allocated)) {
22666349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM3_CTL,
22676349Sqs148142 		    "<== hxge_free_tx_mem_pool "
22686349Sqs148142 		    "(null rx buf pool or buf not allocated"));
22696349Sqs148142 		return;
22706349Sqs148142 	}
22716349Sqs148142 
22726349Sqs148142 	dma_cntl_poolp = hxgep->tx_cntl_pool_p;
22736349Sqs148142 	if (dma_cntl_poolp == NULL || (!dma_cntl_poolp->buf_allocated)) {
22746349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MEM3_CTL,
22756349Sqs148142 		    "<== hxge_free_tx_mem_pool "
22766349Sqs148142 		    "(null tx cntl buf pool or cntl buf not allocated"));
22776349Sqs148142 		return;
22786349Sqs148142 	}
22796349Sqs148142 
22806349Sqs148142 	dma_buf_p = dma_poolp->dma_buf_pool_p;
22816349Sqs148142 	num_chunks = dma_poolp->num_chunks;
22826349Sqs148142 
22836349Sqs148142 	dma_cntl_p = dma_cntl_poolp->dma_buf_pool_p;
22846349Sqs148142 	ndmas = dma_cntl_poolp->ndmas;
22856349Sqs148142 
22866349Sqs148142 	for (i = 0; i < ndmas; i++) {
22876349Sqs148142 		hxge_free_tx_buf_dma(hxgep, dma_buf_p[i], num_chunks[i]);
22886349Sqs148142 	}
22896349Sqs148142 
22906349Sqs148142 	for (i = 0; i < ndmas; i++) {
22916349Sqs148142 		hxge_free_tx_cntl_dma(hxgep, dma_cntl_p[i]);
22926349Sqs148142 	}
22936349Sqs148142 
22946349Sqs148142 	for (i = 0; i < ndmas; i++) {
22956349Sqs148142 		KMEM_FREE(dma_buf_p[i],
22966349Sqs148142 		    sizeof (hxge_dma_common_t) * HXGE_DMA_BLOCK);
22976349Sqs148142 		KMEM_FREE(dma_cntl_p[i], sizeof (hxge_dma_common_t));
22986349Sqs148142 	}
22996349Sqs148142 
23006349Sqs148142 	KMEM_FREE(num_chunks, sizeof (uint32_t) * ndmas);
23016349Sqs148142 	KMEM_FREE(dma_cntl_p, ndmas * sizeof (p_hxge_dma_common_t));
23026349Sqs148142 	KMEM_FREE(dma_cntl_poolp, sizeof (hxge_dma_pool_t));
23036349Sqs148142 	KMEM_FREE(dma_buf_p, ndmas * sizeof (p_hxge_dma_common_t));
23046349Sqs148142 	KMEM_FREE(dma_poolp, sizeof (hxge_dma_pool_t));
23056349Sqs148142 
23066349Sqs148142 	hxgep->tx_buf_pool_p = NULL;
23076349Sqs148142 	hxgep->tx_cntl_pool_p = NULL;
23086349Sqs148142 
23096349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MEM3_CTL, "<== hxge_free_tx_mem_pool"));
23106349Sqs148142 }
23116349Sqs148142 
23126349Sqs148142 /*ARGSUSED*/
23136349Sqs148142 static hxge_status_t
23146349Sqs148142 hxge_dma_mem_alloc(p_hxge_t hxgep, dma_method_t method,
23156349Sqs148142     struct ddi_dma_attr *dma_attrp,
23166349Sqs148142     size_t length, ddi_device_acc_attr_t *acc_attr_p, uint_t xfer_flags,
23176349Sqs148142     p_hxge_dma_common_t dma_p)
23186349Sqs148142 {
23196349Sqs148142 	caddr_t		kaddrp;
23206349Sqs148142 	int		ddi_status = DDI_SUCCESS;
23216349Sqs148142 
23226349Sqs148142 	dma_p->dma_handle = NULL;
23236349Sqs148142 	dma_p->acc_handle = NULL;
23246349Sqs148142 	dma_p->kaddrp = NULL;
23256349Sqs148142 
23266349Sqs148142 	ddi_status = ddi_dma_alloc_handle(hxgep->dip, dma_attrp,
23276349Sqs148142 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_handle);
23286349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
23296349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
23306349Sqs148142 		    "hxge_dma_mem_alloc:ddi_dma_alloc_handle failed."));
23316349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
23326349Sqs148142 	}
23336349Sqs148142 
23346349Sqs148142 	ddi_status = ddi_dma_mem_alloc(dma_p->dma_handle, length, acc_attr_p,
23356349Sqs148142 	    xfer_flags, DDI_DMA_DONTWAIT, 0, &kaddrp, &dma_p->alength,
23366349Sqs148142 	    &dma_p->acc_handle);
23376349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
23386349Sqs148142 		/* The caller will decide whether it is fatal */
23396349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DMA_CTL,
23406349Sqs148142 		    "hxge_dma_mem_alloc:ddi_dma_mem_alloc failed"));
23416349Sqs148142 		ddi_dma_free_handle(&dma_p->dma_handle);
23426349Sqs148142 		dma_p->dma_handle = NULL;
23436349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
23446349Sqs148142 	}
23456349Sqs148142 
23466349Sqs148142 	if (dma_p->alength < length) {
23476349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
23486349Sqs148142 		    "hxge_dma_mem_alloc:ddi_dma_mem_alloc < length."));
23496349Sqs148142 		ddi_dma_mem_free(&dma_p->acc_handle);
23506349Sqs148142 		ddi_dma_free_handle(&dma_p->dma_handle);
23516349Sqs148142 		dma_p->acc_handle = NULL;
23526349Sqs148142 		dma_p->dma_handle = NULL;
23536349Sqs148142 		return (HXGE_ERROR);
23546349Sqs148142 	}
23556349Sqs148142 
23566349Sqs148142 	ddi_status = ddi_dma_addr_bind_handle(dma_p->dma_handle, NULL,
23576349Sqs148142 	    kaddrp, dma_p->alength, xfer_flags, DDI_DMA_DONTWAIT, 0,
23586349Sqs148142 	    &dma_p->dma_cookie, &dma_p->ncookies);
23596349Sqs148142 	if (ddi_status != DDI_DMA_MAPPED) {
23606349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
23616349Sqs148142 		    "hxge_dma_mem_alloc:di_dma_addr_bind failed "
23626349Sqs148142 		    "(staus 0x%x ncookies %d.)", ddi_status, dma_p->ncookies));
23636349Sqs148142 		if (dma_p->acc_handle) {
23646349Sqs148142 			ddi_dma_mem_free(&dma_p->acc_handle);
23656349Sqs148142 			dma_p->acc_handle = NULL;
23666349Sqs148142 		}
23676349Sqs148142 		ddi_dma_free_handle(&dma_p->dma_handle);
23686349Sqs148142 		dma_p->dma_handle = NULL;
23696349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
23706349Sqs148142 	}
23716349Sqs148142 
23726349Sqs148142 	if (dma_p->ncookies != 1) {
23736349Sqs148142 		HXGE_DEBUG_MSG((hxgep, DMA_CTL,
23746349Sqs148142 		    "hxge_dma_mem_alloc:ddi_dma_addr_bind > 1 cookie"
23756349Sqs148142 		    "(staus 0x%x ncookies %d.)", ddi_status, dma_p->ncookies));
23766349Sqs148142 		if (dma_p->acc_handle) {
23776349Sqs148142 			ddi_dma_mem_free(&dma_p->acc_handle);
23786349Sqs148142 			dma_p->acc_handle = NULL;
23796349Sqs148142 		}
23806349Sqs148142 		(void) ddi_dma_unbind_handle(dma_p->dma_handle);
23816349Sqs148142 		ddi_dma_free_handle(&dma_p->dma_handle);
23826349Sqs148142 		dma_p->dma_handle = NULL;
23836349Sqs148142 		return (HXGE_ERROR);
23846349Sqs148142 	}
23856349Sqs148142 
23866349Sqs148142 	dma_p->kaddrp = kaddrp;
23876349Sqs148142 #if defined(__i386)
23886349Sqs148142 	dma_p->ioaddr_pp =
23896349Sqs148142 	    (unsigned char *)(uint32_t)dma_p->dma_cookie.dmac_laddress;
23906349Sqs148142 #else
23916349Sqs148142 	dma_p->ioaddr_pp = (unsigned char *) dma_p->dma_cookie.dmac_laddress;
23926349Sqs148142 #endif
23936349Sqs148142 
23946349Sqs148142 	HPI_DMA_ACC_HANDLE_SET(dma_p, dma_p->acc_handle);
23956349Sqs148142 
23966349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DMA_CTL, "<== hxge_dma_mem_alloc: "
23976349Sqs148142 	    "dma buffer allocated: dma_p $%p "
23986349Sqs148142 	    "return dmac_ladress from cookie $%p dmac_size %d "
23996349Sqs148142 	    "dma_p->ioaddr_p $%p "
24006349Sqs148142 	    "dma_p->orig_ioaddr_p $%p "
24016349Sqs148142 	    "orig_vatopa $%p "
24026349Sqs148142 	    "alength %d (0x%x) "
24036349Sqs148142 	    "kaddrp $%p "
24046349Sqs148142 	    "length %d (0x%x)",
24056349Sqs148142 	    dma_p,
24066349Sqs148142 	    dma_p->dma_cookie.dmac_laddress,
24076349Sqs148142 	    dma_p->dma_cookie.dmac_size,
24086349Sqs148142 	    dma_p->ioaddr_pp,
24096349Sqs148142 	    dma_p->orig_ioaddr_pp,
24106349Sqs148142 	    dma_p->orig_vatopa,
24116349Sqs148142 	    dma_p->alength, dma_p->alength,
24126349Sqs148142 	    kaddrp,
24136349Sqs148142 	    length, length));
24146349Sqs148142 
24156349Sqs148142 	return (HXGE_OK);
24166349Sqs148142 }
24176349Sqs148142 
24186349Sqs148142 static void
24196349Sqs148142 hxge_dma_mem_free(p_hxge_dma_common_t dma_p)
24206349Sqs148142 {
24217618SMichael.Speer@Sun.COM 	if (dma_p == NULL)
24227618SMichael.Speer@Sun.COM 		return;
24237618SMichael.Speer@Sun.COM 
24246349Sqs148142 	if (dma_p->dma_handle != NULL) {
24256349Sqs148142 		if (dma_p->ncookies) {
24266349Sqs148142 			(void) ddi_dma_unbind_handle(dma_p->dma_handle);
24276349Sqs148142 			dma_p->ncookies = 0;
24286349Sqs148142 		}
24296349Sqs148142 		ddi_dma_free_handle(&dma_p->dma_handle);
24306349Sqs148142 		dma_p->dma_handle = NULL;
24316349Sqs148142 	}
24327618SMichael.Speer@Sun.COM 
24336349Sqs148142 	if (dma_p->acc_handle != NULL) {
24346349Sqs148142 		ddi_dma_mem_free(&dma_p->acc_handle);
24356349Sqs148142 		dma_p->acc_handle = NULL;
24366349Sqs148142 		HPI_DMA_ACC_HANDLE_SET(dma_p, NULL);
24376349Sqs148142 	}
24387618SMichael.Speer@Sun.COM 
24396349Sqs148142 	dma_p->kaddrp = NULL;
24406349Sqs148142 	dma_p->alength = NULL;
24416349Sqs148142 }
24426349Sqs148142 
24436349Sqs148142 /*
24446349Sqs148142  *	hxge_m_start() -- start transmitting and receiving.
24456349Sqs148142  *
24466349Sqs148142  *	This function is called by the MAC layer when the first
24476349Sqs148142  *	stream is open to prepare the hardware ready for sending
24486349Sqs148142  *	and transmitting packets.
24496349Sqs148142  */
24506349Sqs148142 static int
24516349Sqs148142 hxge_m_start(void *arg)
24526349Sqs148142 {
24536349Sqs148142 	p_hxge_t hxgep = (p_hxge_t)arg;
24546349Sqs148142 
24556349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "==> hxge_m_start"));
24566349Sqs148142 
24576349Sqs148142 	MUTEX_ENTER(hxgep->genlock);
24586349Sqs148142 
24596349Sqs148142 	if (hxge_init(hxgep) != DDI_SUCCESS) {
24606349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
24616349Sqs148142 		    "<== hxge_m_start: initialization failed"));
24626349Sqs148142 		MUTEX_EXIT(hxgep->genlock);
24636349Sqs148142 		return (EIO);
24646349Sqs148142 	}
24656349Sqs148142 
24666349Sqs148142 	if (hxgep->hxge_mac_state != HXGE_MAC_STARTED) {
24676349Sqs148142 		/*
24686349Sqs148142 		 * Start timer to check the system error and tx hangs
24696349Sqs148142 		 */
24706349Sqs148142 		hxgep->hxge_timerid = hxge_start_timer(hxgep,
24716349Sqs148142 		    hxge_check_hw_state, HXGE_CHECK_TIMER);
24726349Sqs148142 
24736349Sqs148142 		hxgep->hxge_mac_state = HXGE_MAC_STARTED;
24746349Sqs148142 	}
24756349Sqs148142 
24766349Sqs148142 	MUTEX_EXIT(hxgep->genlock);
24776349Sqs148142 
24786349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "<== hxge_m_start"));
24796349Sqs148142 
24806349Sqs148142 	return (0);
24816349Sqs148142 }
24826349Sqs148142 
24836349Sqs148142 /*
24846349Sqs148142  * hxge_m_stop(): stop transmitting and receiving.
24856349Sqs148142  */
24866349Sqs148142 static void
24876349Sqs148142 hxge_m_stop(void *arg)
24886349Sqs148142 {
24896349Sqs148142 	p_hxge_t hxgep = (p_hxge_t)arg;
24906349Sqs148142 
24916349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "==> hxge_m_stop"));
24926349Sqs148142 
24936349Sqs148142 	if (hxgep->hxge_timerid) {
24946349Sqs148142 		hxge_stop_timer(hxgep, hxgep->hxge_timerid);
24956349Sqs148142 		hxgep->hxge_timerid = 0;
24966349Sqs148142 	}
24976349Sqs148142 
24986349Sqs148142 	MUTEX_ENTER(hxgep->genlock);
24996349Sqs148142 
25006349Sqs148142 	hxge_uninit(hxgep);
25016349Sqs148142 
25026349Sqs148142 	hxgep->hxge_mac_state = HXGE_MAC_STOPPED;
25036349Sqs148142 
25046349Sqs148142 	MUTEX_EXIT(hxgep->genlock);
25056349Sqs148142 
25066349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "<== hxge_m_stop"));
25076349Sqs148142 }
25086349Sqs148142 
25096349Sqs148142 static int
25106349Sqs148142 hxge_m_unicst(void *arg, const uint8_t *macaddr)
25116349Sqs148142 {
25126349Sqs148142 	p_hxge_t		hxgep = (p_hxge_t)arg;
25136349Sqs148142 	struct ether_addr	addrp;
25146349Sqs148142 	hxge_status_t		status;
25156349Sqs148142 
25166349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "==> hxge_m_unicst"));
25176349Sqs148142 
25186349Sqs148142 	bcopy(macaddr, (uint8_t *)&addrp, ETHERADDRL);
25196349Sqs148142 
25206349Sqs148142 	status = hxge_set_mac_addr(hxgep, &addrp);
25216349Sqs148142 	if (status != HXGE_OK) {
25226349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
25236349Sqs148142 		    "<== hxge_m_unicst: set unitcast failed"));
25246349Sqs148142 		return (EINVAL);
25256349Sqs148142 	}
25266349Sqs148142 
25276349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "<== hxge_m_unicst"));
25286349Sqs148142 
25296349Sqs148142 	return (0);
25306349Sqs148142 }
25316349Sqs148142 
25326349Sqs148142 static int
25336349Sqs148142 hxge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
25346349Sqs148142 {
25356349Sqs148142 	p_hxge_t		hxgep = (p_hxge_t)arg;
25366349Sqs148142 	struct ether_addr	addrp;
25376349Sqs148142 
25386349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "==> hxge_m_multicst: add %d", add));
25396349Sqs148142 
25406349Sqs148142 	bcopy(mca, (uint8_t *)&addrp, ETHERADDRL);
25416349Sqs148142 
25426349Sqs148142 	if (add) {
25436349Sqs148142 		if (hxge_add_mcast_addr(hxgep, &addrp)) {
25446349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
25456349Sqs148142 			    "<== hxge_m_multicst: add multicast failed"));
25466349Sqs148142 			return (EINVAL);
25476349Sqs148142 		}
25486349Sqs148142 	} else {
25496349Sqs148142 		if (hxge_del_mcast_addr(hxgep, &addrp)) {
25506349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
25516349Sqs148142 			    "<== hxge_m_multicst: del multicast failed"));
25526349Sqs148142 			return (EINVAL);
25536349Sqs148142 		}
25546349Sqs148142 	}
25556349Sqs148142 
25566349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "<== hxge_m_multicst"));
25576349Sqs148142 
25586349Sqs148142 	return (0);
25596349Sqs148142 }
25606349Sqs148142 
25616349Sqs148142 static int
25626349Sqs148142 hxge_m_promisc(void *arg, boolean_t on)
25636349Sqs148142 {
25646349Sqs148142 	p_hxge_t hxgep = (p_hxge_t)arg;
25656349Sqs148142 
25666349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "==> hxge_m_promisc: on %d", on));
25676349Sqs148142 
25686349Sqs148142 	if (hxge_set_promisc(hxgep, on)) {
25696349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
25706349Sqs148142 		    "<== hxge_m_promisc: set promisc failed"));
25716349Sqs148142 		return (EINVAL);
25726349Sqs148142 	}
25736349Sqs148142 
25746349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MAC_CTL, "<== hxge_m_promisc: on %d", on));
25756349Sqs148142 
25766349Sqs148142 	return (0);
25776349Sqs148142 }
25786349Sqs148142 
25796349Sqs148142 static void
25806349Sqs148142 hxge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
25816349Sqs148142 {
25826349Sqs148142 	p_hxge_t	hxgep = (p_hxge_t)arg;
25836349Sqs148142 	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
25846349Sqs148142 	boolean_t	need_privilege;
25856349Sqs148142 	int		err;
25866349Sqs148142 	int		cmd;
25876349Sqs148142 
25886349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "==> hxge_m_ioctl"));
25896349Sqs148142 
25906349Sqs148142 	iocp = (struct iocblk *)mp->b_rptr;
25916349Sqs148142 	iocp->ioc_error = 0;
25926349Sqs148142 	need_privilege = B_TRUE;
25936349Sqs148142 	cmd = iocp->ioc_cmd;
25946349Sqs148142 
25956349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "==> hxge_m_ioctl: cmd 0x%08x", cmd));
25966349Sqs148142 	switch (cmd) {
25976349Sqs148142 	default:
25986349Sqs148142 		miocnak(wq, mp, 0, EINVAL);
25996349Sqs148142 		HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "<== hxge_m_ioctl: invalid"));
26006349Sqs148142 		return;
26016349Sqs148142 
26026349Sqs148142 	case LB_GET_INFO_SIZE:
26036349Sqs148142 	case LB_GET_INFO:
26046349Sqs148142 	case LB_GET_MODE:
26056349Sqs148142 		need_privilege = B_FALSE;
26066349Sqs148142 		break;
26076349Sqs148142 
26086349Sqs148142 	case LB_SET_MODE:
26096349Sqs148142 		break;
26106349Sqs148142 
26116349Sqs148142 	case ND_GET:
26126349Sqs148142 		need_privilege = B_FALSE;
26136349Sqs148142 		break;
26146349Sqs148142 	case ND_SET:
26156349Sqs148142 		break;
26166349Sqs148142 
26176349Sqs148142 	case HXGE_GET64:
26186349Sqs148142 	case HXGE_PUT64:
26196349Sqs148142 	case HXGE_GET_TX_RING_SZ:
26206349Sqs148142 	case HXGE_GET_TX_DESC:
26216349Sqs148142 	case HXGE_TX_SIDE_RESET:
26226349Sqs148142 	case HXGE_RX_SIDE_RESET:
26236349Sqs148142 	case HXGE_GLOBAL_RESET:
26246349Sqs148142 	case HXGE_RESET_MAC:
26256349Sqs148142 	case HXGE_PUT_TCAM:
26266349Sqs148142 	case HXGE_GET_TCAM:
26276349Sqs148142 	case HXGE_RTRACE:
26286349Sqs148142 
26296349Sqs148142 		need_privilege = B_FALSE;
26306349Sqs148142 		break;
26316349Sqs148142 	}
26326349Sqs148142 
26336349Sqs148142 	if (need_privilege) {
26346349Sqs148142 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
26356349Sqs148142 		if (err != 0) {
26366349Sqs148142 			miocnak(wq, mp, 0, err);
26376349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
26386349Sqs148142 			    "<== hxge_m_ioctl: no priv"));
26396349Sqs148142 			return;
26406349Sqs148142 		}
26416349Sqs148142 	}
26426349Sqs148142 
26436349Sqs148142 	switch (cmd) {
26446349Sqs148142 	case ND_GET:
26456349Sqs148142 		HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "ND_GET command"));
26466349Sqs148142 	case ND_SET:
26476349Sqs148142 		HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "ND_SET command"));
26486349Sqs148142 		hxge_param_ioctl(hxgep, wq, mp, iocp);
26496349Sqs148142 		break;
26506349Sqs148142 
26516349Sqs148142 	case LB_GET_MODE:
26526349Sqs148142 	case LB_SET_MODE:
26536349Sqs148142 	case LB_GET_INFO_SIZE:
26546349Sqs148142 	case LB_GET_INFO:
26556349Sqs148142 		hxge_loopback_ioctl(hxgep, wq, mp, iocp);
26566349Sqs148142 		break;
26576349Sqs148142 
26586349Sqs148142 	case HXGE_PUT_TCAM:
26596349Sqs148142 	case HXGE_GET_TCAM:
26606349Sqs148142 	case HXGE_GET64:
26616349Sqs148142 	case HXGE_PUT64:
26626349Sqs148142 	case HXGE_GET_TX_RING_SZ:
26636349Sqs148142 	case HXGE_GET_TX_DESC:
26646349Sqs148142 	case HXGE_TX_SIDE_RESET:
26656349Sqs148142 	case HXGE_RX_SIDE_RESET:
26666349Sqs148142 	case HXGE_GLOBAL_RESET:
26676349Sqs148142 	case HXGE_RESET_MAC:
26686349Sqs148142 		HXGE_DEBUG_MSG((hxgep, NEMO_CTL,
26696349Sqs148142 		    "==> hxge_m_ioctl: cmd 0x%x", cmd));
26706349Sqs148142 		hxge_hw_ioctl(hxgep, wq, mp, iocp);
26716349Sqs148142 		break;
26726349Sqs148142 	}
26736349Sqs148142 
26746349Sqs148142 	HXGE_DEBUG_MSG((hxgep, NEMO_CTL, "<== hxge_m_ioctl"));
26756349Sqs148142 }
26766349Sqs148142 
26776349Sqs148142 extern void hxge_rx_hw_blank(void *arg, time_t ticks, uint_t count);
26786349Sqs148142 
26796349Sqs148142 static void
26806349Sqs148142 hxge_m_resources(void *arg)
26816349Sqs148142 {
26826349Sqs148142 	p_hxge_t hxgep = arg;
26836349Sqs148142 	mac_rx_fifo_t mrf;
26846349Sqs148142 	p_rx_rcr_rings_t rcr_rings;
26856349Sqs148142 	p_rx_rcr_ring_t *rcr_p;
26866349Sqs148142 	p_rx_rcr_ring_t rcrp;
26876349Sqs148142 	uint32_t i, ndmas;
26886349Sqs148142 	int status;
26896349Sqs148142 
26906349Sqs148142 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_m_resources"));
26916349Sqs148142 
26926349Sqs148142 	MUTEX_ENTER(hxgep->genlock);
26936349Sqs148142 
26946349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
26956349Sqs148142 		status = hxge_init(hxgep);
26966349Sqs148142 		if (status != HXGE_OK) {
26976349Sqs148142 			HXGE_DEBUG_MSG((hxgep, RX_CTL, "==> hxge_m_resources: "
26986349Sqs148142 			    "hxge_init failed"));
26996349Sqs148142 			MUTEX_EXIT(hxgep->genlock);
27006349Sqs148142 			return;
27016349Sqs148142 		}
27026349Sqs148142 	}
27036349Sqs148142 
27046349Sqs148142 	mrf.mrf_type = MAC_RX_FIFO;
27056349Sqs148142 	mrf.mrf_blank = hxge_rx_hw_blank;
27066864Sqs148142 	mrf.mrf_arg = (void *)hxgep;
27076864Sqs148142 
27086864Sqs148142 	mrf.mrf_normal_blank_time = RXDMA_RCR_TO_DEFAULT;
27096864Sqs148142 	mrf.mrf_normal_pkt_count = RXDMA_RCR_PTHRES_DEFAULT;
27106349Sqs148142 
27116349Sqs148142 	rcr_rings = hxgep->rx_rcr_rings;
27126349Sqs148142 	rcr_p = rcr_rings->rcr_rings;
27136349Sqs148142 	ndmas = rcr_rings->ndmas;
27146349Sqs148142 
27156349Sqs148142 	/*
27166349Sqs148142 	 * Export our receive resources to the MAC layer.
27176349Sqs148142 	 */
27186349Sqs148142 	for (i = 0; i < ndmas; i++) {
27196349Sqs148142 		rcrp = (void *)(p_rx_rcr_ring_t)rcr_p[i];
27206349Sqs148142 		rcrp->rcr_mac_handle =
27216349Sqs148142 		    mac_resource_add(hxgep->mach, (mac_resource_t *)&mrf);
27226349Sqs148142 
27236349Sqs148142 		HXGE_DEBUG_MSG((hxgep, RX_CTL,
27246349Sqs148142 		    "==> hxge_m_resources: vdma %d dma %d "
27256349Sqs148142 		    "rcrptr 0x%016llx mac_handle 0x%016llx",
27266349Sqs148142 		    i, rcrp->rdc, rcr_p[i], rcrp->rcr_mac_handle));
27276349Sqs148142 	}
27286349Sqs148142 
27296349Sqs148142 	MUTEX_EXIT(hxgep->genlock);
27306349Sqs148142 
27316349Sqs148142 	HXGE_DEBUG_MSG((hxgep, RX_CTL, "<== hxge_m_resources"));
27326349Sqs148142 }
27336349Sqs148142 
27346349Sqs148142 /*
27356349Sqs148142  * Set an alternate MAC address
27366349Sqs148142  */
27376349Sqs148142 static int
27386349Sqs148142 hxge_altmac_set(p_hxge_t hxgep, uint8_t *maddr, mac_addr_slot_t slot)
27396349Sqs148142 {
27406349Sqs148142 	uint64_t	address;
27416349Sqs148142 	uint64_t	tmp;
27426349Sqs148142 	hpi_status_t	status;
27436349Sqs148142 	uint8_t		addrn;
27446349Sqs148142 	int		i;
27456349Sqs148142 
27466349Sqs148142 	/*
27476349Sqs148142 	 * Convert a byte array to a 48 bit value.
27486349Sqs148142 	 * Need to check endianess if in doubt
27496349Sqs148142 	 */
27506349Sqs148142 	address = 0;
27516349Sqs148142 	for (i = 0; i < ETHERADDRL; i++) {
27526349Sqs148142 		tmp = maddr[i];
27536349Sqs148142 		address <<= 8;
27546349Sqs148142 		address |= tmp;
27556349Sqs148142 	}
27566349Sqs148142 
27576349Sqs148142 	addrn = (uint8_t)slot;
27586349Sqs148142 	status = hpi_pfc_set_mac_address(hxgep->hpi_handle, addrn, address);
27596349Sqs148142 	if (status != HPI_SUCCESS)
27606349Sqs148142 		return (EIO);
27616349Sqs148142 
27626349Sqs148142 	return (0);
27636349Sqs148142 }
27646349Sqs148142 
27656349Sqs148142 static void
27666349Sqs148142 hxge_mmac_kstat_update(p_hxge_t hxgep, mac_addr_slot_t slot)
27676349Sqs148142 {
27686349Sqs148142 	p_hxge_mmac_stats_t	mmac_stats;
27696349Sqs148142 	int			i;
27706349Sqs148142 	hxge_mmac_t		*mmac_info;
27716349Sqs148142 
27726349Sqs148142 	mmac_info = &hxgep->hxge_mmac_info;
27736349Sqs148142 	mmac_stats = &hxgep->statsp->mmac_stats;
27746349Sqs148142 	mmac_stats->mmac_max_cnt = mmac_info->num_mmac;
27756349Sqs148142 	mmac_stats->mmac_avail_cnt = mmac_info->naddrfree;
27766349Sqs148142 
27776349Sqs148142 	for (i = 0; i < ETHERADDRL; i++) {
27786349Sqs148142 		mmac_stats->mmac_avail_pool[slot].ether_addr_octet[i] =
27796349Sqs148142 		    mmac_info->mac_pool[slot].addr[(ETHERADDRL - 1) - i];
27806349Sqs148142 	}
27816349Sqs148142 }
27826349Sqs148142 
27836349Sqs148142 /*
27846349Sqs148142  * Find an unused address slot, set the address value to the one specified,
27856349Sqs148142  * enable the port to start filtering on the new MAC address.
27866349Sqs148142  * Returns: 0 on success.
27876349Sqs148142  */
27886349Sqs148142 int
27896349Sqs148142 hxge_m_mmac_add(void *arg, mac_multi_addr_t *maddr)
27906349Sqs148142 {
27916349Sqs148142 	p_hxge_t	hxgep = arg;
27926349Sqs148142 	mac_addr_slot_t	slot;
27936349Sqs148142 	hxge_mmac_t	*mmac_info;
27946349Sqs148142 	int		err;
27956349Sqs148142 	hxge_status_t	status;
27966349Sqs148142 
27976349Sqs148142 	mutex_enter(hxgep->genlock);
27986349Sqs148142 
27996349Sqs148142 	/*
28006349Sqs148142 	 * Make sure that hxge is initialized, if _start() has
28016349Sqs148142 	 * not been called.
28026349Sqs148142 	 */
28036349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
28046349Sqs148142 		status = hxge_init(hxgep);
28056349Sqs148142 		if (status != HXGE_OK) {
28066349Sqs148142 			mutex_exit(hxgep->genlock);
28076349Sqs148142 			return (ENXIO);
28086349Sqs148142 		}
28096349Sqs148142 	}
28106349Sqs148142 
28116349Sqs148142 	mmac_info = &hxgep->hxge_mmac_info;
28126349Sqs148142 	if (mmac_info->naddrfree == 0) {
28136349Sqs148142 		mutex_exit(hxgep->genlock);
28146349Sqs148142 		return (ENOSPC);
28156349Sqs148142 	}
28166349Sqs148142 
28176349Sqs148142 	if (!mac_unicst_verify(hxgep->mach, maddr->mma_addr,
28186349Sqs148142 	    maddr->mma_addrlen)) {
28196349Sqs148142 		mutex_exit(hxgep->genlock);
28206349Sqs148142 		return (EINVAL);
28216349Sqs148142 	}
28226349Sqs148142 
28236349Sqs148142 	/*
28246349Sqs148142 	 * Search for the first available slot. Because naddrfree
28256349Sqs148142 	 * is not zero, we are guaranteed to find one.
28266349Sqs148142 	 * Slot 0 is for unique (primary) MAC.  The first alternate
28276349Sqs148142 	 * MAC slot is slot 1.
28286349Sqs148142 	 */
28296349Sqs148142 	for (slot = 1; slot < mmac_info->num_mmac; slot++) {
28306349Sqs148142 		if (!(mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED))
28316349Sqs148142 			break;
28326349Sqs148142 	}
28336349Sqs148142 
28346349Sqs148142 	ASSERT(slot < mmac_info->num_mmac);
28356349Sqs148142 	if ((err = hxge_altmac_set(hxgep, maddr->mma_addr, slot)) != 0) {
28366349Sqs148142 		mutex_exit(hxgep->genlock);
28376349Sqs148142 		return (err);
28386349Sqs148142 	}
28396349Sqs148142 	bcopy(maddr->mma_addr, mmac_info->mac_pool[slot].addr, ETHERADDRL);
28406349Sqs148142 	mmac_info->mac_pool[slot].flags |= MMAC_SLOT_USED;
28416349Sqs148142 	mmac_info->naddrfree--;
28426349Sqs148142 	hxge_mmac_kstat_update(hxgep, slot);
28436349Sqs148142 
28446349Sqs148142 	maddr->mma_slot = slot;
28456349Sqs148142 
28466349Sqs148142 	mutex_exit(hxgep->genlock);
28476349Sqs148142 	return (0);
28486349Sqs148142 }
28496349Sqs148142 
28506349Sqs148142 /*
28516349Sqs148142  * Remove the specified mac address and update
28526349Sqs148142  * the h/w not to filter the mac address anymore.
28536349Sqs148142  * Returns: 0, on success.
28546349Sqs148142  */
28556349Sqs148142 int
28566349Sqs148142 hxge_m_mmac_remove(void *arg, mac_addr_slot_t slot)
28576349Sqs148142 {
28586349Sqs148142 	p_hxge_t	hxgep = arg;
28596349Sqs148142 	hxge_mmac_t	*mmac_info;
28606349Sqs148142 	int		err = 0;
28616349Sqs148142 	hxge_status_t	status;
28626349Sqs148142 
28636349Sqs148142 	mutex_enter(hxgep->genlock);
28646349Sqs148142 
28656349Sqs148142 	/*
28666349Sqs148142 	 * Make sure that hxge is initialized, if _start() has
28676349Sqs148142 	 * not been called.
28686349Sqs148142 	 */
28696349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
28706349Sqs148142 		status = hxge_init(hxgep);
28716349Sqs148142 		if (status != HXGE_OK) {
28726349Sqs148142 			mutex_exit(hxgep->genlock);
28736349Sqs148142 			return (ENXIO);
28746349Sqs148142 		}
28756349Sqs148142 	}
28766349Sqs148142 
28776349Sqs148142 	mmac_info = &hxgep->hxge_mmac_info;
28786349Sqs148142 	if (slot <= 0 || slot >= mmac_info->num_mmac) {
28796349Sqs148142 		mutex_exit(hxgep->genlock);
28806349Sqs148142 		return (EINVAL);
28816349Sqs148142 	}
28826349Sqs148142 
28836349Sqs148142 	if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) {
28846349Sqs148142 		if (hpi_pfc_mac_addr_disable(hxgep->hpi_handle, slot) ==
28856349Sqs148142 		    HPI_SUCCESS) {
28866349Sqs148142 			mmac_info->mac_pool[slot].flags &= ~MMAC_SLOT_USED;
28876349Sqs148142 			mmac_info->naddrfree++;
28886349Sqs148142 			/*
28896349Sqs148142 			 * Clear mac_pool[slot].addr so that kstat shows 0
28906349Sqs148142 			 * alternate MAC address if the slot is not used.
28916349Sqs148142 			 */
28926349Sqs148142 			bzero(mmac_info->mac_pool[slot].addr, ETHERADDRL);
28936349Sqs148142 			hxge_mmac_kstat_update(hxgep, slot);
28946349Sqs148142 		} else {
28956349Sqs148142 			err = EIO;
28966349Sqs148142 		}
28976349Sqs148142 	} else {
28986349Sqs148142 		err = EINVAL;
28996349Sqs148142 	}
29006349Sqs148142 
29016349Sqs148142 	mutex_exit(hxgep->genlock);
29026349Sqs148142 	return (err);
29036349Sqs148142 }
29046349Sqs148142 
29056349Sqs148142 /*
29066349Sqs148142  * Modify a mac address added by hxge_mmac_add().
29076349Sqs148142  * Returns: 0, on success.
29086349Sqs148142  */
29096349Sqs148142 int
29106349Sqs148142 hxge_m_mmac_modify(void *arg, mac_multi_addr_t *maddr)
29116349Sqs148142 {
29126349Sqs148142 	p_hxge_t	hxgep = arg;
29136349Sqs148142 	mac_addr_slot_t	slot;
29146349Sqs148142 	hxge_mmac_t	*mmac_info;
29156349Sqs148142 	int		err = 0;
29166349Sqs148142 	hxge_status_t	status;
29176349Sqs148142 
29186349Sqs148142 	if (!mac_unicst_verify(hxgep->mach, maddr->mma_addr,
29196349Sqs148142 	    maddr->mma_addrlen))
29206349Sqs148142 		return (EINVAL);
29216349Sqs148142 
29226349Sqs148142 	slot = maddr->mma_slot;
29236349Sqs148142 
29246349Sqs148142 	mutex_enter(hxgep->genlock);
29256349Sqs148142 
29266349Sqs148142 	/*
29276349Sqs148142 	 * Make sure that hxge is initialized, if _start() has
29286349Sqs148142 	 * not been called.
29296349Sqs148142 	 */
29306349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
29316349Sqs148142 		status = hxge_init(hxgep);
29326349Sqs148142 		if (status != HXGE_OK) {
29336349Sqs148142 			mutex_exit(hxgep->genlock);
29346349Sqs148142 			return (ENXIO);
29356349Sqs148142 		}
29366349Sqs148142 	}
29376349Sqs148142 
29386349Sqs148142 	mmac_info = &hxgep->hxge_mmac_info;
29396349Sqs148142 	if (slot <= 0 || slot >= mmac_info->num_mmac) {
29406349Sqs148142 		mutex_exit(hxgep->genlock);
29416349Sqs148142 		return (EINVAL);
29426349Sqs148142 	}
29436349Sqs148142 
29446349Sqs148142 	if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) {
29456349Sqs148142 		if ((err = hxge_altmac_set(hxgep, maddr->mma_addr,
29466349Sqs148142 		    slot)) == 0) {
29476349Sqs148142 			bcopy(maddr->mma_addr, mmac_info->mac_pool[slot].addr,
29486349Sqs148142 			    ETHERADDRL);
29496349Sqs148142 			hxge_mmac_kstat_update(hxgep, slot);
29506349Sqs148142 		}
29516349Sqs148142 	} else {
29526349Sqs148142 		err = EINVAL;
29536349Sqs148142 	}
29546349Sqs148142 
29556349Sqs148142 	mutex_exit(hxgep->genlock);
29566349Sqs148142 	return (err);
29576349Sqs148142 }
29586349Sqs148142 
29596349Sqs148142 /*
29606349Sqs148142  * static int
29616349Sqs148142  * hxge_m_mmac_get() - Get the MAC address and other information
29626349Sqs148142  *	related to the slot.  mma_flags should be set to 0 in the call.
29636349Sqs148142  *	Note: although kstat shows MAC address as zero when a slot is
29646349Sqs148142  *	not used, Crossbow expects hxge_m_mmac_get to copy factory MAC
29656349Sqs148142  *	to the caller as long as the slot is not using a user MAC address.
29666349Sqs148142  *	The following table shows the rules,
29676349Sqs148142  *
29686349Sqs148142  *     					USED    VENDOR    mma_addr
29696349Sqs148142  *	------------------------------------------------------------
29706349Sqs148142  *	(1) Slot uses a user MAC:	yes      no     user MAC
29716349Sqs148142  *	(2) Slot uses a factory MAC:    yes      yes    factory MAC
29726349Sqs148142  *	(3) Slot is not used but is
29736349Sqs148142  *	     factory MAC capable:	no       yes    factory MAC
29746349Sqs148142  *	(4) Slot is not used and is
29756349Sqs148142  *	     not factory MAC capable:   no       no	0
29766349Sqs148142  *	------------------------------------------------------------
29776349Sqs148142  */
29786349Sqs148142 int
29796349Sqs148142 hxge_m_mmac_get(void *arg, mac_multi_addr_t *maddr)
29806349Sqs148142 {
29816349Sqs148142 	hxge_t		*hxgep = arg;
29826349Sqs148142 	mac_addr_slot_t	slot;
29836349Sqs148142 	hxge_mmac_t	*mmac_info;
29846349Sqs148142 	hxge_status_t	status;
29856349Sqs148142 
29866349Sqs148142 	slot = maddr->mma_slot;
29876349Sqs148142 
29886349Sqs148142 	mutex_enter(hxgep->genlock);
29896349Sqs148142 
29906349Sqs148142 	/*
29916349Sqs148142 	 * Make sure that hxge is initialized, if _start() has
29926349Sqs148142 	 * not been called.
29936349Sqs148142 	 */
29946349Sqs148142 	if (!(hxgep->drv_state & STATE_HW_INITIALIZED)) {
29956349Sqs148142 		status = hxge_init(hxgep);
29966349Sqs148142 		if (status != HXGE_OK) {
29976349Sqs148142 			mutex_exit(hxgep->genlock);
29986349Sqs148142 			return (ENXIO);
29996349Sqs148142 		}
30006349Sqs148142 	}
30016349Sqs148142 
30026349Sqs148142 	mmac_info = &hxgep->hxge_mmac_info;
30036349Sqs148142 	if (slot <= 0 || slot >= mmac_info->num_mmac) {
30046349Sqs148142 		mutex_exit(hxgep->genlock);
30056349Sqs148142 		return (EINVAL);
30066349Sqs148142 	}
30076349Sqs148142 
30086349Sqs148142 	maddr->mma_flags = 0;
30096349Sqs148142 	if (mmac_info->mac_pool[slot].flags & MMAC_SLOT_USED) {
30106349Sqs148142 		maddr->mma_flags |= MMAC_SLOT_USED;
30116349Sqs148142 		bcopy(mmac_info->mac_pool[slot].addr,
30126349Sqs148142 		    maddr->mma_addr, ETHERADDRL);
30136349Sqs148142 		maddr->mma_addrlen = ETHERADDRL;
30146349Sqs148142 	}
30156349Sqs148142 
30166349Sqs148142 	mutex_exit(hxgep->genlock);
30176349Sqs148142 	return (0);
30186349Sqs148142 }
30196349Sqs148142 
30206349Sqs148142 /*ARGSUSED*/
30216349Sqs148142 boolean_t
30226349Sqs148142 hxge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
30236349Sqs148142 {
30246349Sqs148142 	p_hxge_t		hxgep = (p_hxge_t)arg;
30256349Sqs148142 	uint32_t		*txflags = cap_data;
30266349Sqs148142 	multiaddress_capab_t	*mmacp = cap_data;
30276349Sqs148142 
30286349Sqs148142 	switch (cap) {
30296349Sqs148142 	case MAC_CAPAB_HCKSUM:
30306349Sqs148142 		*txflags = HCKSUM_INET_PARTIAL;
30316349Sqs148142 		break;
30326349Sqs148142 
30336349Sqs148142 	case MAC_CAPAB_POLL:
30346349Sqs148142 		/*
30356349Sqs148142 		 * There's nothing for us to fill in, simply returning B_TRUE
30366349Sqs148142 		 * stating that we support polling is sufficient.
30376349Sqs148142 		 */
30386349Sqs148142 		break;
30396349Sqs148142 
30406349Sqs148142 	case MAC_CAPAB_MULTIADDRESS:
30416349Sqs148142 		/*
30426349Sqs148142 		 * The number of MAC addresses made available by
30436349Sqs148142 		 * this capability is one less than the total as
30446349Sqs148142 		 * the primary address in slot 0 is counted in
30456349Sqs148142 		 * the total.
30466349Sqs148142 		 */
30476349Sqs148142 		mmacp->maddr_naddr = PFC_N_MAC_ADDRESSES - 1;
30486349Sqs148142 		mmacp->maddr_naddrfree = hxgep->hxge_mmac_info.naddrfree;
30496349Sqs148142 		mmacp->maddr_flag = 0;	/* No multiple factory macs */
30506349Sqs148142 		mmacp->maddr_handle = hxgep;
30516349Sqs148142 		mmacp->maddr_add = hxge_m_mmac_add;
30526349Sqs148142 		mmacp->maddr_remove = hxge_m_mmac_remove;
30536349Sqs148142 		mmacp->maddr_modify = hxge_m_mmac_modify;
30546349Sqs148142 		mmacp->maddr_get = hxge_m_mmac_get;
30556349Sqs148142 		mmacp->maddr_reserve = NULL;	/* No multiple factory macs */
30566349Sqs148142 		break;
30576349Sqs148142 	default:
30586349Sqs148142 		return (B_FALSE);
30596349Sqs148142 	}
30606349Sqs148142 	return (B_TRUE);
30616349Sqs148142 }
30626349Sqs148142 
30637584SQiyan.Sun@Sun.COM static boolean_t
30647584SQiyan.Sun@Sun.COM hxge_param_locked(mac_prop_id_t pr_num)
30657584SQiyan.Sun@Sun.COM {
30667584SQiyan.Sun@Sun.COM 	/*
30677584SQiyan.Sun@Sun.COM 	 * All adv_* parameters are locked (read-only) while
30687584SQiyan.Sun@Sun.COM 	 * the device is in any sort of loopback mode ...
30697584SQiyan.Sun@Sun.COM 	 */
30707584SQiyan.Sun@Sun.COM 	switch (pr_num) {
30717584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000FDX_CAP:
30727584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000FDX_CAP:
30737584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000HDX_CAP:
30747584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
30757584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100FDX_CAP:
30767584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100FDX_CAP:
30777584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100HDX_CAP:
30787584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100HDX_CAP:
30797584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10FDX_CAP:
30807584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10FDX_CAP:
30817584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10HDX_CAP:
30827584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10HDX_CAP:
30837584SQiyan.Sun@Sun.COM 		case MAC_PROP_AUTONEG:
30847584SQiyan.Sun@Sun.COM 		case MAC_PROP_FLOWCTRL:
30857584SQiyan.Sun@Sun.COM 			return (B_TRUE);
30867584SQiyan.Sun@Sun.COM 	}
30877584SQiyan.Sun@Sun.COM 	return (B_FALSE);
30887584SQiyan.Sun@Sun.COM }
30897584SQiyan.Sun@Sun.COM 
30907584SQiyan.Sun@Sun.COM /*
30917584SQiyan.Sun@Sun.COM  * callback functions for set/get of properties
30927584SQiyan.Sun@Sun.COM  */
30937584SQiyan.Sun@Sun.COM static int
30947584SQiyan.Sun@Sun.COM hxge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
30957584SQiyan.Sun@Sun.COM     uint_t pr_valsize, const void *pr_val)
30967584SQiyan.Sun@Sun.COM {
30977584SQiyan.Sun@Sun.COM 	hxge_t		*hxgep = barg;
30987584SQiyan.Sun@Sun.COM 	p_hxge_stats_t	statsp;
30997584SQiyan.Sun@Sun.COM 	int		err = 0;
31007584SQiyan.Sun@Sun.COM 	uint32_t	new_mtu, old_framesize, new_framesize;
31017584SQiyan.Sun@Sun.COM 
31027584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL, "==> hxge_m_setprop"));
31037584SQiyan.Sun@Sun.COM 
31047584SQiyan.Sun@Sun.COM 	statsp = hxgep->statsp;
31057584SQiyan.Sun@Sun.COM 	mutex_enter(hxgep->genlock);
31067584SQiyan.Sun@Sun.COM 	if (statsp->port_stats.lb_mode != hxge_lb_normal &&
31077584SQiyan.Sun@Sun.COM 	    hxge_param_locked(pr_num)) {
31087584SQiyan.Sun@Sun.COM 		/*
31097584SQiyan.Sun@Sun.COM 		 * All adv_* parameters are locked (read-only)
31107584SQiyan.Sun@Sun.COM 		 * while the device is in any sort of loopback mode.
31117584SQiyan.Sun@Sun.COM 		 */
31127584SQiyan.Sun@Sun.COM 		HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
31137584SQiyan.Sun@Sun.COM 		    "==> hxge_m_setprop: loopback mode: read only"));
31147584SQiyan.Sun@Sun.COM 		mutex_exit(hxgep->genlock);
31157584SQiyan.Sun@Sun.COM 		return (EBUSY);
31167584SQiyan.Sun@Sun.COM 	}
31177584SQiyan.Sun@Sun.COM 
31187584SQiyan.Sun@Sun.COM 	switch (pr_num) {
31197584SQiyan.Sun@Sun.COM 		/*
31207584SQiyan.Sun@Sun.COM 		 * These properties are either not exist or read only
31217584SQiyan.Sun@Sun.COM 		 */
31227584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000FDX_CAP:
31237584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100FDX_CAP:
31247584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10FDX_CAP:
31257584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
31267584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100HDX_CAP:
31277584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10HDX_CAP:
31287584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000FDX_CAP:
31297584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000HDX_CAP:
31307584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100FDX_CAP:
31317584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100HDX_CAP:
31327584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10FDX_CAP:
31337584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10HDX_CAP:
31347584SQiyan.Sun@Sun.COM 		case MAC_PROP_STATUS:
31357584SQiyan.Sun@Sun.COM 		case MAC_PROP_SPEED:
31367584SQiyan.Sun@Sun.COM 		case MAC_PROP_DUPLEX:
31377584SQiyan.Sun@Sun.COM 		case MAC_PROP_AUTONEG:
31387584SQiyan.Sun@Sun.COM 		/*
31397584SQiyan.Sun@Sun.COM 		 * Flow control is handled in the shared domain and
31407584SQiyan.Sun@Sun.COM 		 * it is readonly here.
31417584SQiyan.Sun@Sun.COM 		 */
31427584SQiyan.Sun@Sun.COM 		case MAC_PROP_FLOWCTRL:
31437584SQiyan.Sun@Sun.COM 			err = EINVAL;
31447584SQiyan.Sun@Sun.COM 			HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
31457584SQiyan.Sun@Sun.COM 			    "==> hxge_m_setprop:  read only property %d",
31467584SQiyan.Sun@Sun.COM 			    pr_num));
31477584SQiyan.Sun@Sun.COM 			break;
31487584SQiyan.Sun@Sun.COM 
31497584SQiyan.Sun@Sun.COM 		case MAC_PROP_MTU:
31507584SQiyan.Sun@Sun.COM 			if (hxgep->hxge_mac_state == HXGE_MAC_STARTED) {
31517584SQiyan.Sun@Sun.COM 				err = EBUSY;
31527584SQiyan.Sun@Sun.COM 				break;
31537584SQiyan.Sun@Sun.COM 			}
31547584SQiyan.Sun@Sun.COM 
31557584SQiyan.Sun@Sun.COM 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
31567584SQiyan.Sun@Sun.COM 			HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
31577584SQiyan.Sun@Sun.COM 			    "==> hxge_m_setprop: set MTU: %d", new_mtu));
31587584SQiyan.Sun@Sun.COM 
31597584SQiyan.Sun@Sun.COM 			new_framesize = new_mtu + MTU_TO_FRAME_SIZE;
31607584SQiyan.Sun@Sun.COM 			if (new_framesize == hxgep->vmac.maxframesize) {
31617584SQiyan.Sun@Sun.COM 				err = 0;
31627584SQiyan.Sun@Sun.COM 				break;
31637584SQiyan.Sun@Sun.COM 			}
31647584SQiyan.Sun@Sun.COM 
31657584SQiyan.Sun@Sun.COM 			if (new_framesize < MIN_FRAME_SIZE ||
31667584SQiyan.Sun@Sun.COM 			    new_framesize > MAX_FRAME_SIZE) {
31677584SQiyan.Sun@Sun.COM 				err = EINVAL;
31687584SQiyan.Sun@Sun.COM 				break;
31697584SQiyan.Sun@Sun.COM 			}
31707584SQiyan.Sun@Sun.COM 
31717584SQiyan.Sun@Sun.COM 			old_framesize = hxgep->vmac.maxframesize;
31727584SQiyan.Sun@Sun.COM 			hxgep->vmac.maxframesize = (uint16_t)new_framesize;
31737584SQiyan.Sun@Sun.COM 
31747584SQiyan.Sun@Sun.COM 			if (hxge_vmac_set_framesize(hxgep)) {
31757584SQiyan.Sun@Sun.COM 				hxgep->vmac.maxframesize =
31767584SQiyan.Sun@Sun.COM 				    (uint16_t)old_framesize;
31777584SQiyan.Sun@Sun.COM 				err = EINVAL;
31787584SQiyan.Sun@Sun.COM 				break;
31797584SQiyan.Sun@Sun.COM 			}
31807584SQiyan.Sun@Sun.COM 
31817584SQiyan.Sun@Sun.COM 			err = mac_maxsdu_update(hxgep->mach, new_mtu);
31827584SQiyan.Sun@Sun.COM 			if (err) {
31837584SQiyan.Sun@Sun.COM 				hxgep->vmac.maxframesize =
31847584SQiyan.Sun@Sun.COM 				    (uint16_t)old_framesize;
31857584SQiyan.Sun@Sun.COM 				(void) hxge_vmac_set_framesize(hxgep);
31867584SQiyan.Sun@Sun.COM 			}
31877584SQiyan.Sun@Sun.COM 
31887584SQiyan.Sun@Sun.COM 			HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
31897584SQiyan.Sun@Sun.COM 			    "==> hxge_m_setprop: set MTU: %d maxframe %d",
31907584SQiyan.Sun@Sun.COM 			    new_mtu, hxgep->vmac.maxframesize));
31917584SQiyan.Sun@Sun.COM 			break;
31927584SQiyan.Sun@Sun.COM 
31937584SQiyan.Sun@Sun.COM 		case MAC_PROP_PRIVATE:
31947584SQiyan.Sun@Sun.COM 			HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
31957584SQiyan.Sun@Sun.COM 			    "==> hxge_m_setprop: private property"));
31967584SQiyan.Sun@Sun.COM 			err = hxge_set_priv_prop(hxgep, pr_name, pr_valsize,
31977584SQiyan.Sun@Sun.COM 			    pr_val);
31987584SQiyan.Sun@Sun.COM 			break;
31997584SQiyan.Sun@Sun.COM 
32007584SQiyan.Sun@Sun.COM 		default:
32017584SQiyan.Sun@Sun.COM 			err = ENOTSUP;
32027584SQiyan.Sun@Sun.COM 			break;
32037584SQiyan.Sun@Sun.COM 	}
32047584SQiyan.Sun@Sun.COM 
32057584SQiyan.Sun@Sun.COM 	mutex_exit(hxgep->genlock);
32067584SQiyan.Sun@Sun.COM 
32077584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
32087584SQiyan.Sun@Sun.COM 	    "<== hxge_m_setprop (return %d)", err));
32097584SQiyan.Sun@Sun.COM 
32107584SQiyan.Sun@Sun.COM 	return (err);
32117584SQiyan.Sun@Sun.COM }
32127584SQiyan.Sun@Sun.COM 
32137584SQiyan.Sun@Sun.COM /* ARGSUSED */
32147584SQiyan.Sun@Sun.COM static int
32157584SQiyan.Sun@Sun.COM hxge_get_def_val(hxge_t *hxgep, mac_prop_id_t pr_num, uint_t pr_valsize,
32167584SQiyan.Sun@Sun.COM     void *pr_val)
32177584SQiyan.Sun@Sun.COM {
32187584SQiyan.Sun@Sun.COM 	int		err = 0;
32197584SQiyan.Sun@Sun.COM 	link_flowctrl_t	fl;
32207584SQiyan.Sun@Sun.COM 
32217584SQiyan.Sun@Sun.COM 	switch (pr_num) {
32227584SQiyan.Sun@Sun.COM 	case MAC_PROP_DUPLEX:
32237584SQiyan.Sun@Sun.COM 		*(uint8_t *)pr_val = 2;
32247584SQiyan.Sun@Sun.COM 		break;
32257584SQiyan.Sun@Sun.COM 	case MAC_PROP_AUTONEG:
32267584SQiyan.Sun@Sun.COM 		*(uint8_t *)pr_val = 0;
32277584SQiyan.Sun@Sun.COM 		break;
32287584SQiyan.Sun@Sun.COM 	case MAC_PROP_FLOWCTRL:
32297584SQiyan.Sun@Sun.COM 		if (pr_valsize < sizeof (link_flowctrl_t))
32307584SQiyan.Sun@Sun.COM 			return (EINVAL);
32317584SQiyan.Sun@Sun.COM 		fl = LINK_FLOWCTRL_TX;
32327584SQiyan.Sun@Sun.COM 		bcopy(&fl, pr_val, sizeof (fl));
32337584SQiyan.Sun@Sun.COM 		break;
32347584SQiyan.Sun@Sun.COM 	default:
32357584SQiyan.Sun@Sun.COM 		err = ENOTSUP;
32367584SQiyan.Sun@Sun.COM 		break;
32377584SQiyan.Sun@Sun.COM 	}
32387584SQiyan.Sun@Sun.COM 	return (err);
32397584SQiyan.Sun@Sun.COM }
32407584SQiyan.Sun@Sun.COM 
32417584SQiyan.Sun@Sun.COM static int
32427584SQiyan.Sun@Sun.COM hxge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
32437584SQiyan.Sun@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val)
32447584SQiyan.Sun@Sun.COM {
32457584SQiyan.Sun@Sun.COM 	hxge_t 		*hxgep = barg;
32467584SQiyan.Sun@Sun.COM 	p_hxge_stats_t	statsp = hxgep->statsp;
32477584SQiyan.Sun@Sun.COM 	int		err = 0;
32487584SQiyan.Sun@Sun.COM 	link_flowctrl_t fl;
32497584SQiyan.Sun@Sun.COM 	uint64_t	tmp = 0;
32507584SQiyan.Sun@Sun.COM 	link_state_t	ls;
32517584SQiyan.Sun@Sun.COM 
32527584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
32537584SQiyan.Sun@Sun.COM 	    "==> hxge_m_getprop: pr_num %d", pr_num));
32547584SQiyan.Sun@Sun.COM 
32557584SQiyan.Sun@Sun.COM 	if (pr_valsize == 0)
32567584SQiyan.Sun@Sun.COM 		return (EINVAL);
32577584SQiyan.Sun@Sun.COM 
32587584SQiyan.Sun@Sun.COM 	if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
32597584SQiyan.Sun@Sun.COM 		err = hxge_get_def_val(hxgep, pr_num, pr_valsize, pr_val);
32607584SQiyan.Sun@Sun.COM 		return (err);
32617584SQiyan.Sun@Sun.COM 	}
32627584SQiyan.Sun@Sun.COM 
32637584SQiyan.Sun@Sun.COM 	bzero(pr_val, pr_valsize);
32647584SQiyan.Sun@Sun.COM 	switch (pr_num) {
32657584SQiyan.Sun@Sun.COM 		case MAC_PROP_DUPLEX:
32667584SQiyan.Sun@Sun.COM 			*(uint8_t *)pr_val = statsp->mac_stats.link_duplex;
32677584SQiyan.Sun@Sun.COM 			HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
32687584SQiyan.Sun@Sun.COM 			    "==> hxge_m_getprop: duplex mode %d",
32697584SQiyan.Sun@Sun.COM 			    *(uint8_t *)pr_val));
32707584SQiyan.Sun@Sun.COM 			break;
32717584SQiyan.Sun@Sun.COM 
32727584SQiyan.Sun@Sun.COM 		case MAC_PROP_SPEED:
32737584SQiyan.Sun@Sun.COM 			if (pr_valsize < sizeof (uint64_t))
32747584SQiyan.Sun@Sun.COM 				return (EINVAL);
32757584SQiyan.Sun@Sun.COM 			tmp = statsp->mac_stats.link_speed * 1000000ull;
32767584SQiyan.Sun@Sun.COM 			bcopy(&tmp, pr_val, sizeof (tmp));
32777584SQiyan.Sun@Sun.COM 			break;
32787584SQiyan.Sun@Sun.COM 
32797584SQiyan.Sun@Sun.COM 		case MAC_PROP_STATUS:
32807584SQiyan.Sun@Sun.COM 			if (pr_valsize < sizeof (link_state_t))
32817584SQiyan.Sun@Sun.COM 				return (EINVAL);
32827584SQiyan.Sun@Sun.COM 			if (!statsp->mac_stats.link_up)
32837584SQiyan.Sun@Sun.COM 				ls = LINK_STATE_DOWN;
32847584SQiyan.Sun@Sun.COM 			else
32857584SQiyan.Sun@Sun.COM 				ls = LINK_STATE_UP;
32867584SQiyan.Sun@Sun.COM 			bcopy(&ls, pr_val, sizeof (ls));
32877584SQiyan.Sun@Sun.COM 			break;
32887584SQiyan.Sun@Sun.COM 
32897584SQiyan.Sun@Sun.COM 		case MAC_PROP_FLOWCTRL:
32907584SQiyan.Sun@Sun.COM 			/*
32917584SQiyan.Sun@Sun.COM 			 * Flow control is supported by the shared domain and
32927584SQiyan.Sun@Sun.COM 			 * it is currently transmit only
32937584SQiyan.Sun@Sun.COM 			 */
32947584SQiyan.Sun@Sun.COM 			if (pr_valsize < sizeof (link_flowctrl_t))
32957584SQiyan.Sun@Sun.COM 				return (EINVAL);
32967584SQiyan.Sun@Sun.COM 			fl = LINK_FLOWCTRL_TX;
32977584SQiyan.Sun@Sun.COM 			bcopy(&fl, pr_val, sizeof (fl));
32987584SQiyan.Sun@Sun.COM 			break;
32997584SQiyan.Sun@Sun.COM 		case MAC_PROP_AUTONEG:
33007584SQiyan.Sun@Sun.COM 			/* 10G link only and it is not negotiable */
33017584SQiyan.Sun@Sun.COM 			*(uint8_t *)pr_val = 0;
33027584SQiyan.Sun@Sun.COM 			break;
33037584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000FDX_CAP:
33047584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100FDX_CAP:
33057584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10FDX_CAP:
33067584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_1000HDX_CAP:
33077584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_100HDX_CAP:
33087584SQiyan.Sun@Sun.COM 		case MAC_PROP_ADV_10HDX_CAP:
33097584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000FDX_CAP:
33107584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100FDX_CAP:
33117584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10FDX_CAP:
33127584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
33137584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_100HDX_CAP:
33147584SQiyan.Sun@Sun.COM 		case MAC_PROP_EN_10HDX_CAP:
33157584SQiyan.Sun@Sun.COM 			err = ENOTSUP;
33167584SQiyan.Sun@Sun.COM 			break;
33177584SQiyan.Sun@Sun.COM 
33187584SQiyan.Sun@Sun.COM 		case MAC_PROP_PRIVATE:
33197584SQiyan.Sun@Sun.COM 			err = hxge_get_priv_prop(hxgep, pr_name, pr_flags,
33207584SQiyan.Sun@Sun.COM 			    pr_valsize, pr_val);
33217584SQiyan.Sun@Sun.COM 			break;
33227584SQiyan.Sun@Sun.COM 		default:
33237584SQiyan.Sun@Sun.COM 			err = EINVAL;
33247584SQiyan.Sun@Sun.COM 			break;
33257584SQiyan.Sun@Sun.COM 	}
33267584SQiyan.Sun@Sun.COM 
33277584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL, "<== hxge_m_getprop"));
33287584SQiyan.Sun@Sun.COM 
33297584SQiyan.Sun@Sun.COM 	return (err);
33307584SQiyan.Sun@Sun.COM }
33317584SQiyan.Sun@Sun.COM 
33327584SQiyan.Sun@Sun.COM /* ARGSUSED */
33337584SQiyan.Sun@Sun.COM static int
33347584SQiyan.Sun@Sun.COM hxge_set_priv_prop(p_hxge_t hxgep, const char *pr_name, uint_t pr_valsize,
33357584SQiyan.Sun@Sun.COM     const void *pr_val)
33367584SQiyan.Sun@Sun.COM {
33377584SQiyan.Sun@Sun.COM 	p_hxge_param_t	param_arr = hxgep->param_arr;
33387584SQiyan.Sun@Sun.COM 	int		err = 0;
33397584SQiyan.Sun@Sun.COM 
33407584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
33417584SQiyan.Sun@Sun.COM 	    "==> hxge_set_priv_prop: name %s (value %s)", pr_name, pr_val));
33427584SQiyan.Sun@Sun.COM 
33437584SQiyan.Sun@Sun.COM 	if (pr_val == NULL) {
33447584SQiyan.Sun@Sun.COM 		return (EINVAL);
33457584SQiyan.Sun@Sun.COM 	}
33467584SQiyan.Sun@Sun.COM 
33477584SQiyan.Sun@Sun.COM 	/* Blanking */
33487584SQiyan.Sun@Sun.COM 	if (strcmp(pr_name, "_rxdma_intr_time") == 0) {
33497584SQiyan.Sun@Sun.COM 		err = hxge_param_rx_intr_time(hxgep, NULL, NULL,
33507584SQiyan.Sun@Sun.COM 		    (char *)pr_val, (caddr_t)&param_arr[param_rxdma_intr_time]);
33517584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_rxdma_intr_pkts") == 0) {
33527584SQiyan.Sun@Sun.COM 		err = hxge_param_rx_intr_pkts(hxgep, NULL, NULL,
33537584SQiyan.Sun@Sun.COM 		    (char *)pr_val, (caddr_t)&param_arr[param_rxdma_intr_pkts]);
33547584SQiyan.Sun@Sun.COM 
33557584SQiyan.Sun@Sun.COM 	/* Classification */
33567584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv4_tcp") == 0) {
33577584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33587584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv4_tcp]);
33597584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv4_udp") == 0) {
33607584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33617584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv4_udp]);
33627584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv4_ah") == 0) {
33637584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33647584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv4_ah]);
33657584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv4_sctp") == 0) {
33667584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33677584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv4_sctp]);
33687584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv6_tcp") == 0) {
33697584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33707584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv6_tcp]);
33717584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv6_udp") == 0) {
33727584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33737584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv6_udp]);
33747584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv6_ah") == 0) {
33757584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33767584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv6_ah]);
33777584SQiyan.Sun@Sun.COM 	} else if (strcmp(pr_name, "_class_opt_ipv6_sctp") == 0) {
33787584SQiyan.Sun@Sun.COM 		err = hxge_param_set_ip_opt(hxgep, NULL, NULL, (char *)pr_val,
33797584SQiyan.Sun@Sun.COM 		    (caddr_t)&param_arr[param_class_opt_ipv6_sctp]);
33807584SQiyan.Sun@Sun.COM 	} else {
33817584SQiyan.Sun@Sun.COM 		err = EINVAL;
33827584SQiyan.Sun@Sun.COM 	}
33837584SQiyan.Sun@Sun.COM 
33847584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
33857584SQiyan.Sun@Sun.COM 	    "<== hxge_set_priv_prop: err %d", err));
33867584SQiyan.Sun@Sun.COM 
33877584SQiyan.Sun@Sun.COM 	return (err);
33887584SQiyan.Sun@Sun.COM }
33897584SQiyan.Sun@Sun.COM 
33907584SQiyan.Sun@Sun.COM static int
33917584SQiyan.Sun@Sun.COM hxge_get_priv_prop(p_hxge_t hxgep, const char *pr_name, uint_t pr_flags,
33927584SQiyan.Sun@Sun.COM     uint_t pr_valsize, void *pr_val)
33937584SQiyan.Sun@Sun.COM {
33947584SQiyan.Sun@Sun.COM 	p_hxge_param_t	param_arr = hxgep->param_arr;
33957584SQiyan.Sun@Sun.COM 	char		valstr[MAXNAMELEN];
33967584SQiyan.Sun@Sun.COM 	int		err = 0;
33977584SQiyan.Sun@Sun.COM 	uint_t		strsize;
33987584SQiyan.Sun@Sun.COM 	int		value = 0;
33997584SQiyan.Sun@Sun.COM 
34007584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
34017584SQiyan.Sun@Sun.COM 	    "==> hxge_get_priv_prop: property %s", pr_name));
34027584SQiyan.Sun@Sun.COM 
34037584SQiyan.Sun@Sun.COM 	if (pr_flags & MAC_PROP_DEFAULT) {
34047584SQiyan.Sun@Sun.COM 		/* Receive Interrupt Blanking Parameters */
34057584SQiyan.Sun@Sun.COM 		if (strcmp(pr_name, "_rxdma_intr_time") == 0) {
34067584SQiyan.Sun@Sun.COM 			value = RXDMA_RCR_TO_DEFAULT;
34077584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_rxdma_intr_pkts") == 0) {
34087584SQiyan.Sun@Sun.COM 			value = RXDMA_RCR_PTHRES_DEFAULT;
34097584SQiyan.Sun@Sun.COM 
34107584SQiyan.Sun@Sun.COM 		/* Classification and Load Distribution Configuration */
34117584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv4_tcp") == 0 ||
34127584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv4_udp") == 0 ||
34137584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv4_ah") == 0 ||
34147584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv4_sctp") == 0 ||
34157584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv6_tcp") == 0 ||
34167584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv6_udp") == 0 ||
34177584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv6_ah") == 0 ||
34187584SQiyan.Sun@Sun.COM 		    strcmp(pr_name, "_class_opt_ipv6_sctp") == 0) {
34197584SQiyan.Sun@Sun.COM 			value = HXGE_CLASS_TCAM_LOOKUP;
34207584SQiyan.Sun@Sun.COM 		} else {
34217584SQiyan.Sun@Sun.COM 			err = EINVAL;
34227584SQiyan.Sun@Sun.COM 		}
34237584SQiyan.Sun@Sun.COM 	} else {
34247584SQiyan.Sun@Sun.COM 		/* Receive Interrupt Blanking Parameters */
34257584SQiyan.Sun@Sun.COM 		if (strcmp(pr_name, "_rxdma_intr_time") == 0) {
34267584SQiyan.Sun@Sun.COM 			value = hxgep->intr_timeout;
34277584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_rxdma_intr_pkts") == 0) {
34287584SQiyan.Sun@Sun.COM 			value = hxgep->intr_threshold;
34297584SQiyan.Sun@Sun.COM 
34307584SQiyan.Sun@Sun.COM 		/* Classification and Load Distribution Configuration */
34317584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv4_tcp") == 0) {
34327584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34337584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv4_tcp]);
34347584SQiyan.Sun@Sun.COM 
34357584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv4_tcp].value;
34367584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv4_udp") == 0) {
34377584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34387584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv4_udp]);
34397584SQiyan.Sun@Sun.COM 
34407584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv4_udp].value;
34417584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv4_ah") == 0) {
34427584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34437584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv4_ah]);
34447584SQiyan.Sun@Sun.COM 
34457584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv4_ah].value;
34467584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv4_sctp") == 0) {
34477584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34487584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv4_sctp]);
34497584SQiyan.Sun@Sun.COM 
34507584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv4_sctp].value;
34517584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv6_tcp") == 0) {
34527584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34537584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv6_tcp]);
34547584SQiyan.Sun@Sun.COM 
34557584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv6_tcp].value;
34567584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv6_udp") == 0) {
34577584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34587584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv6_udp]);
34597584SQiyan.Sun@Sun.COM 
34607584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv6_udp].value;
34617584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv6_ah") == 0) {
34627584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34637584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv6_ah]);
34647584SQiyan.Sun@Sun.COM 
34657584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv6_ah].value;
34667584SQiyan.Sun@Sun.COM 		} else if (strcmp(pr_name, "_class_opt_ipv6_sctp") == 0) {
34677584SQiyan.Sun@Sun.COM 			err = hxge_param_get_ip_opt(hxgep, NULL, NULL,
34687584SQiyan.Sun@Sun.COM 			    (caddr_t)&param_arr[param_class_opt_ipv6_sctp]);
34697584SQiyan.Sun@Sun.COM 
34707584SQiyan.Sun@Sun.COM 			value = (int)param_arr[param_class_opt_ipv6_sctp].value;
34717584SQiyan.Sun@Sun.COM 		} else {
34727584SQiyan.Sun@Sun.COM 			err = EINVAL;
34737584SQiyan.Sun@Sun.COM 		}
34747584SQiyan.Sun@Sun.COM 	}
34757584SQiyan.Sun@Sun.COM 
34767584SQiyan.Sun@Sun.COM 	if (err == 0) {
34777584SQiyan.Sun@Sun.COM 		(void) snprintf(valstr, sizeof (valstr), "0x%x", value);
34787584SQiyan.Sun@Sun.COM 
34797584SQiyan.Sun@Sun.COM 		strsize = (uint_t)strlen(valstr);
34807584SQiyan.Sun@Sun.COM 		if (pr_valsize < strsize) {
34817584SQiyan.Sun@Sun.COM 			err = ENOBUFS;
34827584SQiyan.Sun@Sun.COM 		} else {
34837584SQiyan.Sun@Sun.COM 			(void) strlcpy(pr_val, valstr, pr_valsize);
34847584SQiyan.Sun@Sun.COM 		}
34857584SQiyan.Sun@Sun.COM 	}
34867584SQiyan.Sun@Sun.COM 
34877584SQiyan.Sun@Sun.COM 	HXGE_DEBUG_MSG((hxgep, DLADM_CTL,
34887584SQiyan.Sun@Sun.COM 	    "<== hxge_get_priv_prop: return %d", err));
34897584SQiyan.Sun@Sun.COM 
34907584SQiyan.Sun@Sun.COM 	return (err);
34917584SQiyan.Sun@Sun.COM }
34926349Sqs148142 /*
34936349Sqs148142  * Module loading and removing entry points.
34946349Sqs148142  */
34956349Sqs148142 DDI_DEFINE_STREAM_OPS(hxge_dev_ops, nulldev, nulldev, hxge_attach, hxge_detach,
3496*7918SQiyan.Sun@Sun.COM     nodev, NULL, D_MP, NULL, NULL);
34976349Sqs148142 
34986349Sqs148142 extern struct mod_ops mod_driverops;
34996349Sqs148142 
35006349Sqs148142 #define	HXGE_DESC_VER	"HXGE 10Gb Ethernet Driver"
35016349Sqs148142 
35026349Sqs148142 /*
35036349Sqs148142  * Module linkage information for the kernel.
35046349Sqs148142  */
35056349Sqs148142 static struct modldrv hxge_modldrv = {
35066349Sqs148142 	&mod_driverops,
35076349Sqs148142 	HXGE_DESC_VER,
35086349Sqs148142 	&hxge_dev_ops
35096349Sqs148142 };
35106349Sqs148142 
35116349Sqs148142 static struct modlinkage modlinkage = {
35126349Sqs148142 	MODREV_1, (void *) &hxge_modldrv, NULL
35136349Sqs148142 };
35146349Sqs148142 
35156349Sqs148142 int
35166349Sqs148142 _init(void)
35176349Sqs148142 {
35186349Sqs148142 	int status;
35196349Sqs148142 
35206349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "==> _init"));
35216349Sqs148142 	mac_init_ops(&hxge_dev_ops, "hxge");
35226349Sqs148142 	status = ddi_soft_state_init(&hxge_list, sizeof (hxge_t), 0);
35236349Sqs148142 	if (status != 0) {
35246349Sqs148142 		HXGE_ERROR_MSG((NULL, HXGE_ERR_CTL,
35256349Sqs148142 		    "failed to init device soft state"));
35266349Sqs148142 		mac_fini_ops(&hxge_dev_ops);
35276349Sqs148142 		goto _init_exit;
35286349Sqs148142 	}
35296349Sqs148142 
35306349Sqs148142 	status = mod_install(&modlinkage);
35316349Sqs148142 	if (status != 0) {
35326349Sqs148142 		ddi_soft_state_fini(&hxge_list);
35336349Sqs148142 		HXGE_ERROR_MSG((NULL, HXGE_ERR_CTL, "Mod install failed"));
35346349Sqs148142 		goto _init_exit;
35356349Sqs148142 	}
35366349Sqs148142 
35376349Sqs148142 	MUTEX_INIT(&hxge_common_lock, NULL, MUTEX_DRIVER, NULL);
35386349Sqs148142 
35396349Sqs148142 _init_exit:
35406349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "_init status = 0x%X", status));
35416349Sqs148142 
35426349Sqs148142 	return (status);
35436349Sqs148142 }
35446349Sqs148142 
35456349Sqs148142 int
35466349Sqs148142 _fini(void)
35476349Sqs148142 {
35486349Sqs148142 	int status;
35496349Sqs148142 
35506349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "==> _fini"));
35516349Sqs148142 
35526349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "==> _fini: mod_remove"));
35536349Sqs148142 
35546349Sqs148142 	if (hxge_mblks_pending)
35556349Sqs148142 		return (EBUSY);
35566349Sqs148142 
35576349Sqs148142 	status = mod_remove(&modlinkage);
35586349Sqs148142 	if (status != DDI_SUCCESS) {
35596349Sqs148142 		HXGE_DEBUG_MSG((NULL, MOD_CTL,
35606349Sqs148142 		    "Module removal failed 0x%08x", status));
35616349Sqs148142 		goto _fini_exit;
35626349Sqs148142 	}
35636349Sqs148142 
35646349Sqs148142 	mac_fini_ops(&hxge_dev_ops);
35656349Sqs148142 
35666349Sqs148142 	ddi_soft_state_fini(&hxge_list);
35676349Sqs148142 
35686349Sqs148142 	MUTEX_DESTROY(&hxge_common_lock);
35696349Sqs148142 
35706349Sqs148142 _fini_exit:
35716349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "_fini status = 0x%08x", status));
35726349Sqs148142 
35736349Sqs148142 	return (status);
35746349Sqs148142 }
35756349Sqs148142 
35766349Sqs148142 int
35776349Sqs148142 _info(struct modinfo *modinfop)
35786349Sqs148142 {
35796349Sqs148142 	int status;
35806349Sqs148142 
35816349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, "==> _info"));
35826349Sqs148142 	status = mod_info(&modlinkage, modinfop);
35836349Sqs148142 	HXGE_DEBUG_MSG((NULL, MOD_CTL, " _info status = 0x%X", status));
35846349Sqs148142 
35856349Sqs148142 	return (status);
35866349Sqs148142 }
35876349Sqs148142 
35886349Sqs148142 /*ARGSUSED*/
35896349Sqs148142 hxge_status_t
35906349Sqs148142 hxge_add_intrs(p_hxge_t hxgep)
35916349Sqs148142 {
35926349Sqs148142 	int		intr_types;
35936349Sqs148142 	int		type = 0;
35946349Sqs148142 	int		ddi_status = DDI_SUCCESS;
35956349Sqs148142 	hxge_status_t	status = HXGE_OK;
35966349Sqs148142 
35976349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs"));
35986349Sqs148142 
35996349Sqs148142 	hxgep->hxge_intr_type.intr_registered = B_FALSE;
36006349Sqs148142 	hxgep->hxge_intr_type.intr_enabled = B_FALSE;
36016349Sqs148142 	hxgep->hxge_intr_type.msi_intx_cnt = 0;
36026349Sqs148142 	hxgep->hxge_intr_type.intr_added = 0;
36036349Sqs148142 	hxgep->hxge_intr_type.niu_msi_enable = B_FALSE;
36046349Sqs148142 	hxgep->hxge_intr_type.intr_type = 0;
36056349Sqs148142 
36066349Sqs148142 	if (hxge_msi_enable) {
36076349Sqs148142 		hxgep->hxge_intr_type.niu_msi_enable = B_TRUE;
36086349Sqs148142 	}
36096349Sqs148142 
36106349Sqs148142 	/* Get the supported interrupt types */
36116349Sqs148142 	if ((ddi_status = ddi_intr_get_supported_types(hxgep->dip, &intr_types))
36126349Sqs148142 	    != DDI_SUCCESS) {
36136349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_add_intrs: "
36146349Sqs148142 		    "ddi_intr_get_supported_types failed: status 0x%08x",
36156349Sqs148142 		    ddi_status));
36166349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
36176349Sqs148142 	}
36186349Sqs148142 
36196349Sqs148142 	hxgep->hxge_intr_type.intr_types = intr_types;
36206349Sqs148142 
36216349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs: "
36226349Sqs148142 	    "ddi_intr_get_supported_types: 0x%08x", intr_types));
36236349Sqs148142 
36246349Sqs148142 	/*
36256349Sqs148142 	 * Pick the interrupt type to use MSIX, MSI, INTX hxge_msi_enable:
36266349Sqs148142 	 *	(1): 1 - MSI
36276349Sqs148142 	 *	(2): 2 - MSI-X
36286349Sqs148142 	 *	others - FIXED
36296349Sqs148142 	 */
36306349Sqs148142 	switch (hxge_msi_enable) {
36316349Sqs148142 	default:
36326349Sqs148142 		type = DDI_INTR_TYPE_FIXED;
36336349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs: "
36346349Sqs148142 		    "use fixed (intx emulation) type %08x", type));
36356349Sqs148142 		break;
36366349Sqs148142 
36376349Sqs148142 	case 2:
36386349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs: "
36396349Sqs148142 		    "ddi_intr_get_supported_types: 0x%08x", intr_types));
36406349Sqs148142 		if (intr_types & DDI_INTR_TYPE_MSIX) {
36416349Sqs148142 			type = DDI_INTR_TYPE_MSIX;
36426349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
36436349Sqs148142 			    "==> hxge_add_intrs: "
36446349Sqs148142 			    "ddi_intr_get_supported_types: MSIX 0x%08x", type));
36456349Sqs148142 		} else if (intr_types & DDI_INTR_TYPE_MSI) {
36466349Sqs148142 			type = DDI_INTR_TYPE_MSI;
36476349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
36486349Sqs148142 			    "==> hxge_add_intrs: "
36496349Sqs148142 			    "ddi_intr_get_supported_types: MSI 0x%08x", type));
36506349Sqs148142 		} else if (intr_types & DDI_INTR_TYPE_FIXED) {
36516349Sqs148142 			type = DDI_INTR_TYPE_FIXED;
36526349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs: "
36536349Sqs148142 			    "ddi_intr_get_supported_types: MSXED0x%08x", type));
36546349Sqs148142 		}
36556349Sqs148142 		break;
36566349Sqs148142 
36576349Sqs148142 	case 1:
36586349Sqs148142 		if (intr_types & DDI_INTR_TYPE_MSI) {
36596349Sqs148142 			type = DDI_INTR_TYPE_MSI;
36606349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
36616349Sqs148142 			    "==> hxge_add_intrs: "
36626349Sqs148142 			    "ddi_intr_get_supported_types: MSI 0x%08x", type));
36636349Sqs148142 		} else if (intr_types & DDI_INTR_TYPE_MSIX) {
36646349Sqs148142 			type = DDI_INTR_TYPE_MSIX;
36656349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
36666349Sqs148142 			    "==> hxge_add_intrs: "
36676349Sqs148142 			    "ddi_intr_get_supported_types: MSIX 0x%08x", type));
36686349Sqs148142 		} else if (intr_types & DDI_INTR_TYPE_FIXED) {
36696349Sqs148142 			type = DDI_INTR_TYPE_FIXED;
36706349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
36716349Sqs148142 			    "==> hxge_add_intrs: "
36726349Sqs148142 			    "ddi_intr_get_supported_types: MSXED0x%08x", type));
36736349Sqs148142 		}
36746349Sqs148142 	}
36756349Sqs148142 
36766349Sqs148142 	hxgep->hxge_intr_type.intr_type = type;
36776349Sqs148142 	if ((type == DDI_INTR_TYPE_MSIX || type == DDI_INTR_TYPE_MSI ||
36786349Sqs148142 	    type == DDI_INTR_TYPE_FIXED) &&
36796349Sqs148142 	    hxgep->hxge_intr_type.niu_msi_enable) {
36806349Sqs148142 		if ((status = hxge_add_intrs_adv(hxgep)) != DDI_SUCCESS) {
36816349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
36826349Sqs148142 			    " hxge_add_intrs: "
36836349Sqs148142 			    " hxge_add_intrs_adv failed: status 0x%08x",
36846349Sqs148142 			    status));
36856349Sqs148142 			return (status);
36866349Sqs148142 		} else {
36876349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_add_intrs: "
36886349Sqs148142 			    "interrupts registered : type %d", type));
36896349Sqs148142 			hxgep->hxge_intr_type.intr_registered = B_TRUE;
36906349Sqs148142 
36916349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL,
36926349Sqs148142 			    "\nAdded advanced hxge add_intr_adv "
36936349Sqs148142 			    "intr type 0x%x\n", type));
36946349Sqs148142 
36956349Sqs148142 			return (status);
36966349Sqs148142 		}
36976349Sqs148142 	}
36986349Sqs148142 
36996349Sqs148142 	if (!hxgep->hxge_intr_type.intr_registered) {
37006349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
37016349Sqs148142 		    "==> hxge_add_intrs: failed to register interrupts"));
37026349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
37036349Sqs148142 	}
37046349Sqs148142 
37056349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_add_intrs"));
37066349Sqs148142 
37076349Sqs148142 	return (status);
37086349Sqs148142 }
37096349Sqs148142 
37106349Sqs148142 /*ARGSUSED*/
37116349Sqs148142 static hxge_status_t
37126349Sqs148142 hxge_add_soft_intrs(p_hxge_t hxgep)
37136349Sqs148142 {
37146349Sqs148142 	int		ddi_status = DDI_SUCCESS;
37156349Sqs148142 	hxge_status_t	status = HXGE_OK;
37166349Sqs148142 
37176349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_add_soft_intrs"));
37186349Sqs148142 
37196349Sqs148142 	hxgep->resched_id = NULL;
37206349Sqs148142 	hxgep->resched_running = B_FALSE;
37216349Sqs148142 	ddi_status = ddi_add_softintr(hxgep->dip, DDI_SOFTINT_LOW,
37226349Sqs148142 	    &hxgep->resched_id, NULL, NULL, hxge_reschedule, (caddr_t)hxgep);
37236349Sqs148142 	if (ddi_status != DDI_SUCCESS) {
37246349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_add_soft_intrs: "
37256349Sqs148142 		    "ddi_add_softintrs failed: status 0x%08x", ddi_status));
37266349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
37276349Sqs148142 	}
37286349Sqs148142 
37296349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_ddi_add_soft_intrs"));
37306349Sqs148142 
37316349Sqs148142 	return (status);
37326349Sqs148142 }
37336349Sqs148142 
37346349Sqs148142 /*ARGSUSED*/
37356349Sqs148142 static hxge_status_t
37366349Sqs148142 hxge_add_intrs_adv(p_hxge_t hxgep)
37376349Sqs148142 {
37386349Sqs148142 	int		intr_type;
37396349Sqs148142 	p_hxge_intr_t	intrp;
37406349Sqs148142 	hxge_status_t	status;
37416349Sqs148142 
37426349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs_adv"));
37436349Sqs148142 
37446349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
37456349Sqs148142 	intr_type = intrp->intr_type;
37466349Sqs148142 
37476349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs_adv: type 0x%x",
37486349Sqs148142 	    intr_type));
37496349Sqs148142 
37506349Sqs148142 	switch (intr_type) {
37516349Sqs148142 	case DDI_INTR_TYPE_MSI:		/* 0x2 */
37526349Sqs148142 	case DDI_INTR_TYPE_MSIX:	/* 0x4 */
37536349Sqs148142 		status = hxge_add_intrs_adv_type(hxgep, intr_type);
37546349Sqs148142 		break;
37556349Sqs148142 
37566349Sqs148142 	case DDI_INTR_TYPE_FIXED:	/* 0x1 */
37576349Sqs148142 		status = hxge_add_intrs_adv_type_fix(hxgep, intr_type);
37586349Sqs148142 		break;
37596349Sqs148142 
37606349Sqs148142 	default:
37616349Sqs148142 		status = HXGE_ERROR;
37626349Sqs148142 		break;
37636349Sqs148142 	}
37646349Sqs148142 
37656349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_add_intrs_adv"));
37666349Sqs148142 
37676349Sqs148142 	return (status);
37686349Sqs148142 }
37696349Sqs148142 
37706349Sqs148142 /*ARGSUSED*/
37716349Sqs148142 static hxge_status_t
37726349Sqs148142 hxge_add_intrs_adv_type(p_hxge_t hxgep, uint32_t int_type)
37736349Sqs148142 {
37746349Sqs148142 	dev_info_t	*dip = hxgep->dip;
37756349Sqs148142 	p_hxge_ldg_t	ldgp;
37766349Sqs148142 	p_hxge_intr_t	intrp;
37776349Sqs148142 	uint_t		*inthandler;
37786349Sqs148142 	void		*arg1, *arg2;
37796349Sqs148142 	int		behavior;
37806349Sqs148142 	int		nintrs, navail;
37816349Sqs148142 	int		nactual, nrequired;
37826349Sqs148142 	int		inum = 0;
37836349Sqs148142 	int		loop = 0;
37846349Sqs148142 	int		x, y;
37856349Sqs148142 	int		ddi_status = DDI_SUCCESS;
37866349Sqs148142 	hxge_status_t	status = HXGE_OK;
37876349Sqs148142 
37886349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs_adv_type"));
37896349Sqs148142 
37906349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
37916349Sqs148142 
37926349Sqs148142 	ddi_status = ddi_intr_get_nintrs(dip, int_type, &nintrs);
37936349Sqs148142 	if ((ddi_status != DDI_SUCCESS) || (nintrs == 0)) {
37946349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
37956349Sqs148142 		    "ddi_intr_get_nintrs() failed, status: 0x%x%, "
37966349Sqs148142 		    "nintrs: %d", ddi_status, nintrs));
37976349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
37986349Sqs148142 	}
37996349Sqs148142 
38006349Sqs148142 	ddi_status = ddi_intr_get_navail(dip, int_type, &navail);
38016349Sqs148142 	if ((ddi_status != DDI_SUCCESS) || (navail == 0)) {
38026349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
38036349Sqs148142 		    "ddi_intr_get_navail() failed, status: 0x%x%, "
38046349Sqs148142 		    "nintrs: %d", ddi_status, navail));
38056349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
38066349Sqs148142 	}
38076349Sqs148142 
38086349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
38096349Sqs148142 	    "ddi_intr_get_navail() returned: intr type %d nintrs %d, navail %d",
38106349Sqs148142 	    int_type, nintrs, navail));
38116349Sqs148142 
38126349Sqs148142 	if (int_type == DDI_INTR_TYPE_MSI && !ISP2(navail)) {
38136349Sqs148142 		/* MSI must be power of 2 */
38146349Sqs148142 		if ((navail & 16) == 16) {
38156349Sqs148142 			navail = 16;
38166349Sqs148142 		} else if ((navail & 8) == 8) {
38176349Sqs148142 			navail = 8;
38186349Sqs148142 		} else if ((navail & 4) == 4) {
38196349Sqs148142 			navail = 4;
38206349Sqs148142 		} else if ((navail & 2) == 2) {
38216349Sqs148142 			navail = 2;
38226349Sqs148142 		} else {
38236349Sqs148142 			navail = 1;
38246349Sqs148142 		}
38256349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
38266349Sqs148142 		    "ddi_intr_get_navail(): (msi power of 2) nintrs %d, "
38276349Sqs148142 		    "navail %d", nintrs, navail));
38286349Sqs148142 	}
38296349Sqs148142 
38306349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
38316349Sqs148142 	    "requesting: intr type %d nintrs %d, navail %d",
38326349Sqs148142 	    int_type, nintrs, navail));
38336349Sqs148142 
38346349Sqs148142 	behavior = ((int_type == DDI_INTR_TYPE_FIXED) ? DDI_INTR_ALLOC_STRICT :
38356349Sqs148142 	    DDI_INTR_ALLOC_NORMAL);
38366349Sqs148142 	intrp->intr_size = navail * sizeof (ddi_intr_handle_t);
38376349Sqs148142 	intrp->htable = kmem_zalloc(intrp->intr_size, KM_SLEEP);
38386349Sqs148142 
38396349Sqs148142 	ddi_status = ddi_intr_alloc(dip, intrp->htable, int_type, inum,
38406349Sqs148142 	    navail, &nactual, behavior);
38416349Sqs148142 	if (ddi_status != DDI_SUCCESS || nactual == 0) {
38426349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
38436349Sqs148142 		    " ddi_intr_alloc() failed: %d", ddi_status));
38446349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
38456349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
38466349Sqs148142 	}
38476349Sqs148142 
38486349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
38496349Sqs148142 	    "ddi_intr_alloc() returned: navail %d nactual %d",
38506349Sqs148142 	    navail, nactual));
38516349Sqs148142 
38526349Sqs148142 	if ((ddi_status = ddi_intr_get_pri(intrp->htable[0],
38536349Sqs148142 	    (uint_t *)&intrp->pri)) != DDI_SUCCESS) {
38546349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
38556349Sqs148142 		    " ddi_intr_get_pri() failed: %d", ddi_status));
38566349Sqs148142 		/* Free already allocated interrupts */
38576349Sqs148142 		for (y = 0; y < nactual; y++) {
38586349Sqs148142 			(void) ddi_intr_free(intrp->htable[y]);
38596349Sqs148142 		}
38606349Sqs148142 
38616349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
38626349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
38636349Sqs148142 	}
38646349Sqs148142 
38656349Sqs148142 	nrequired = 0;
38666349Sqs148142 	status = hxge_ldgv_init(hxgep, &nactual, &nrequired);
38676349Sqs148142 	if (status != HXGE_OK) {
38686349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
38696349Sqs148142 		    "hxge_add_intrs_adv_typ:hxge_ldgv_init "
38706349Sqs148142 		    "failed: 0x%x", status));
38716349Sqs148142 		/* Free already allocated interrupts */
38726349Sqs148142 		for (y = 0; y < nactual; y++) {
38736349Sqs148142 			(void) ddi_intr_free(intrp->htable[y]);
38746349Sqs148142 		}
38756349Sqs148142 
38766349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
38776349Sqs148142 		return (status);
38786349Sqs148142 	}
38796349Sqs148142 
38806349Sqs148142 	ldgp = hxgep->ldgvp->ldgp;
38816349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
38826349Sqs148142 	    "After hxge_ldgv_init(): nreq %d nactual %d", nrequired, nactual));
38836349Sqs148142 
38846349Sqs148142 	if (nactual < nrequired)
38856349Sqs148142 		loop = nactual;
38866349Sqs148142 	else
38876349Sqs148142 		loop = nrequired;
38886349Sqs148142 
38896349Sqs148142 	for (x = 0; x < loop; x++, ldgp++) {
38906349Sqs148142 		ldgp->vector = (uint8_t)x;
38916349Sqs148142 		arg1 = ldgp->ldvp;
38926349Sqs148142 		arg2 = hxgep;
38936349Sqs148142 		if (ldgp->nldvs == 1) {
38946349Sqs148142 			inthandler = (uint_t *)ldgp->ldvp->ldv_intr_handler;
38956349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
38966349Sqs148142 			    "hxge_add_intrs_adv_type: arg1 0x%x arg2 0x%x: "
38976349Sqs148142 			    "1-1 int handler (entry %d)\n",
38986349Sqs148142 			    arg1, arg2, x));
38996349Sqs148142 		} else if (ldgp->nldvs > 1) {
39006349Sqs148142 			inthandler = (uint_t *)ldgp->sys_intr_handler;
39016349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
39026349Sqs148142 			    "hxge_add_intrs_adv_type: arg1 0x%x arg2 0x%x: "
39036349Sqs148142 			    "nldevs %d int handler (entry %d)\n",
39046349Sqs148142 			    arg1, arg2, ldgp->nldvs, x));
39056349Sqs148142 		}
39066349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
39076349Sqs148142 		    "==> hxge_add_intrs_adv_type: ddi_add_intr(inum) #%d "
39086349Sqs148142 		    "htable 0x%llx", x, intrp->htable[x]));
39096349Sqs148142 
39106349Sqs148142 		if ((ddi_status = ddi_intr_add_handler(intrp->htable[x],
39116349Sqs148142 		    (ddi_intr_handler_t *)inthandler, arg1, arg2)) !=
39126349Sqs148142 		    DDI_SUCCESS) {
39136349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
39146349Sqs148142 			    "==> hxge_add_intrs_adv_type: failed #%d "
39156349Sqs148142 			    "status 0x%x", x, ddi_status));
39166349Sqs148142 			for (y = 0; y < intrp->intr_added; y++) {
39176349Sqs148142 				(void) ddi_intr_remove_handler(
39186349Sqs148142 				    intrp->htable[y]);
39196349Sqs148142 			}
39206349Sqs148142 
39216349Sqs148142 			/* Free already allocated intr */
39226349Sqs148142 			for (y = 0; y < nactual; y++) {
39236349Sqs148142 				(void) ddi_intr_free(intrp->htable[y]);
39246349Sqs148142 			}
39256349Sqs148142 			kmem_free(intrp->htable, intrp->intr_size);
39266349Sqs148142 
39276349Sqs148142 			(void) hxge_ldgv_uninit(hxgep);
39286349Sqs148142 
39296349Sqs148142 			return (HXGE_ERROR | HXGE_DDI_FAILED);
39306349Sqs148142 		}
39316349Sqs148142 
39326349Sqs148142 		intrp->intr_added++;
39336349Sqs148142 	}
39346349Sqs148142 	intrp->msi_intx_cnt = nactual;
39356349Sqs148142 
39366349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
39376349Sqs148142 	    "Requested: %d, Allowed: %d msi_intx_cnt %d intr_added %d",
39386349Sqs148142 	    navail, nactual, intrp->msi_intx_cnt, intrp->intr_added));
39396349Sqs148142 
39406349Sqs148142 	(void) ddi_intr_get_cap(intrp->htable[0], &intrp->intr_cap);
39416349Sqs148142 	(void) hxge_intr_ldgv_init(hxgep);
39426349Sqs148142 
39436349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_add_intrs_adv_type"));
39446349Sqs148142 
39456349Sqs148142 	return (status);
39466349Sqs148142 }
39476349Sqs148142 
39486349Sqs148142 /*ARGSUSED*/
39496349Sqs148142 static hxge_status_t
39506349Sqs148142 hxge_add_intrs_adv_type_fix(p_hxge_t hxgep, uint32_t int_type)
39516349Sqs148142 {
39526349Sqs148142 	dev_info_t	*dip = hxgep->dip;
39536349Sqs148142 	p_hxge_ldg_t	ldgp;
39546349Sqs148142 	p_hxge_intr_t	intrp;
39556349Sqs148142 	uint_t		*inthandler;
39566349Sqs148142 	void		*arg1, *arg2;
39576349Sqs148142 	int		behavior;
39586349Sqs148142 	int		nintrs, navail;
39596349Sqs148142 	int		nactual, nrequired;
39606349Sqs148142 	int		inum = 0;
39616349Sqs148142 	int		x, y;
39626349Sqs148142 	int		ddi_status = DDI_SUCCESS;
39636349Sqs148142 	hxge_status_t	status = HXGE_OK;
39646349Sqs148142 
39656349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_add_intrs_adv_type_fix"));
39666349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
39676349Sqs148142 
39686349Sqs148142 	ddi_status = ddi_intr_get_nintrs(dip, int_type, &nintrs);
39696349Sqs148142 	if ((ddi_status != DDI_SUCCESS) || (nintrs == 0)) {
39706349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
39716349Sqs148142 		    "ddi_intr_get_nintrs() failed, status: 0x%x%, "
39726349Sqs148142 		    "nintrs: %d", status, nintrs));
39736349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
39746349Sqs148142 	}
39756349Sqs148142 
39766349Sqs148142 	ddi_status = ddi_intr_get_navail(dip, int_type, &navail);
39776349Sqs148142 	if ((ddi_status != DDI_SUCCESS) || (navail == 0)) {
39786349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
39796349Sqs148142 		    "ddi_intr_get_navail() failed, status: 0x%x%, "
39806349Sqs148142 		    "nintrs: %d", ddi_status, navail));
39816349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
39826349Sqs148142 	}
39836349Sqs148142 
39846349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
39856349Sqs148142 	    "ddi_intr_get_navail() returned: nintrs %d, naavail %d",
39866349Sqs148142 	    nintrs, navail));
39876349Sqs148142 
39886349Sqs148142 	behavior = ((int_type == DDI_INTR_TYPE_FIXED) ? DDI_INTR_ALLOC_STRICT :
39896349Sqs148142 	    DDI_INTR_ALLOC_NORMAL);
39906349Sqs148142 	intrp->intr_size = navail * sizeof (ddi_intr_handle_t);
39916349Sqs148142 	intrp->htable = kmem_alloc(intrp->intr_size, KM_SLEEP);
39926349Sqs148142 	ddi_status = ddi_intr_alloc(dip, intrp->htable, int_type, inum,
39936349Sqs148142 	    navail, &nactual, behavior);
39946349Sqs148142 	if (ddi_status != DDI_SUCCESS || nactual == 0) {
39956349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
39966349Sqs148142 		    " ddi_intr_alloc() failed: %d", ddi_status));
39976349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
39986349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
39996349Sqs148142 	}
40006349Sqs148142 
40016349Sqs148142 	if ((ddi_status = ddi_intr_get_pri(intrp->htable[0],
40026349Sqs148142 	    (uint_t *)&intrp->pri)) != DDI_SUCCESS) {
40036349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
40046349Sqs148142 		    " ddi_intr_get_pri() failed: %d", ddi_status));
40056349Sqs148142 		/* Free already allocated interrupts */
40066349Sqs148142 		for (y = 0; y < nactual; y++) {
40076349Sqs148142 			(void) ddi_intr_free(intrp->htable[y]);
40086349Sqs148142 		}
40096349Sqs148142 
40106349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
40116349Sqs148142 		return (HXGE_ERROR | HXGE_DDI_FAILED);
40126349Sqs148142 	}
40136349Sqs148142 
40146349Sqs148142 	nrequired = 0;
40156349Sqs148142 	status = hxge_ldgv_init(hxgep, &nactual, &nrequired);
40166349Sqs148142 	if (status != HXGE_OK) {
40176349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
40186349Sqs148142 		    "hxge_add_intrs_adv_type_fix:hxge_ldgv_init "
40196349Sqs148142 		    "failed: 0x%x", status));
40206349Sqs148142 		/* Free already allocated interrupts */
40216349Sqs148142 		for (y = 0; y < nactual; y++) {
40226349Sqs148142 			(void) ddi_intr_free(intrp->htable[y]);
40236349Sqs148142 		}
40246349Sqs148142 
40256349Sqs148142 		kmem_free(intrp->htable, intrp->intr_size);
40266349Sqs148142 		return (status);
40276349Sqs148142 	}
40286349Sqs148142 
40296349Sqs148142 	ldgp = hxgep->ldgvp->ldgp;
40306349Sqs148142 	for (x = 0; x < nrequired; x++, ldgp++) {
40316349Sqs148142 		ldgp->vector = (uint8_t)x;
40326349Sqs148142 		arg1 = ldgp->ldvp;
40336349Sqs148142 		arg2 = hxgep;
40346349Sqs148142 		if (ldgp->nldvs == 1) {
40356349Sqs148142 			inthandler = (uint_t *)ldgp->ldvp->ldv_intr_handler;
40366349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
40376349Sqs148142 			    "hxge_add_intrs_adv_type_fix: "
40386349Sqs148142 			    "1-1 int handler(%d) ldg %d ldv %d "
40396349Sqs148142 			    "arg1 $%p arg2 $%p\n",
40406349Sqs148142 			    x, ldgp->ldg, ldgp->ldvp->ldv, arg1, arg2));
40416349Sqs148142 		} else if (ldgp->nldvs > 1) {
40426349Sqs148142 			inthandler = (uint_t *)ldgp->sys_intr_handler;
40436349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
40446349Sqs148142 			    "hxge_add_intrs_adv_type_fix: "
40456349Sqs148142 			    "shared ldv %d int handler(%d) ldv %d ldg %d"
40466349Sqs148142 			    "arg1 0x%016llx arg2 0x%016llx\n",
40476349Sqs148142 			    x, ldgp->nldvs, ldgp->ldg, ldgp->ldvp->ldv,
40486349Sqs148142 			    arg1, arg2));
40496349Sqs148142 		}
40506349Sqs148142 
40516349Sqs148142 		if ((ddi_status = ddi_intr_add_handler(intrp->htable[x],
40526349Sqs148142 		    (ddi_intr_handler_t *)inthandler, arg1, arg2)) !=
40536349Sqs148142 		    DDI_SUCCESS) {
40546349Sqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
40556349Sqs148142 			    "==> hxge_add_intrs_adv_type_fix: failed #%d "
40566349Sqs148142 			    "status 0x%x", x, ddi_status));
40576349Sqs148142 			for (y = 0; y < intrp->intr_added; y++) {
40586349Sqs148142 				(void) ddi_intr_remove_handler(
40596349Sqs148142 				    intrp->htable[y]);
40606349Sqs148142 			}
40616349Sqs148142 			for (y = 0; y < nactual; y++) {
40626349Sqs148142 				(void) ddi_intr_free(intrp->htable[y]);
40636349Sqs148142 			}
40646349Sqs148142 			/* Free already allocated intr */
40656349Sqs148142 			kmem_free(intrp->htable, intrp->intr_size);
40666349Sqs148142 
40676349Sqs148142 			(void) hxge_ldgv_uninit(hxgep);
40686349Sqs148142 
40696349Sqs148142 			return (HXGE_ERROR | HXGE_DDI_FAILED);
40706349Sqs148142 		}
40716349Sqs148142 		intrp->intr_added++;
40726349Sqs148142 	}
40736349Sqs148142 
40746349Sqs148142 	intrp->msi_intx_cnt = nactual;
40756349Sqs148142 
40766349Sqs148142 	(void) ddi_intr_get_cap(intrp->htable[0], &intrp->intr_cap);
40776349Sqs148142 
40786349Sqs148142 	status = hxge_intr_ldgv_init(hxgep);
40796349Sqs148142 
40806349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_add_intrs_adv_type_fix"));
40816349Sqs148142 
40826349Sqs148142 	return (status);
40836349Sqs148142 }
40846349Sqs148142 
40856349Sqs148142 /*ARGSUSED*/
40866349Sqs148142 static void
40876349Sqs148142 hxge_remove_intrs(p_hxge_t hxgep)
40886349Sqs148142 {
40896349Sqs148142 	int		i, inum;
40906349Sqs148142 	p_hxge_intr_t	intrp;
40916349Sqs148142 
40926349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_remove_intrs"));
40936349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
40946349Sqs148142 	if (!intrp->intr_registered) {
40956349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
40966349Sqs148142 		    "<== hxge_remove_intrs: interrupts not registered"));
40976349Sqs148142 		return;
40986349Sqs148142 	}
40996349Sqs148142 
41006349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_remove_intrs:advanced"));
41016349Sqs148142 
41026349Sqs148142 	if (intrp->intr_cap & DDI_INTR_FLAG_BLOCK) {
41036349Sqs148142 		(void) ddi_intr_block_disable(intrp->htable,
41046349Sqs148142 		    intrp->intr_added);
41056349Sqs148142 	} else {
41066349Sqs148142 		for (i = 0; i < intrp->intr_added; i++) {
41076349Sqs148142 			(void) ddi_intr_disable(intrp->htable[i]);
41086349Sqs148142 		}
41096349Sqs148142 	}
41106349Sqs148142 
41116349Sqs148142 	for (inum = 0; inum < intrp->intr_added; inum++) {
41126349Sqs148142 		if (intrp->htable[inum]) {
41136349Sqs148142 			(void) ddi_intr_remove_handler(intrp->htable[inum]);
41146349Sqs148142 		}
41156349Sqs148142 	}
41166349Sqs148142 
41176349Sqs148142 	for (inum = 0; inum < intrp->msi_intx_cnt; inum++) {
41186349Sqs148142 		if (intrp->htable[inum]) {
41196349Sqs148142 			HXGE_DEBUG_MSG((hxgep, DDI_CTL,
41206349Sqs148142 			    "hxge_remove_intrs: ddi_intr_free inum %d "
41216349Sqs148142 			    "msi_intx_cnt %d intr_added %d",
41226349Sqs148142 			    inum, intrp->msi_intx_cnt, intrp->intr_added));
41236349Sqs148142 
41246349Sqs148142 			(void) ddi_intr_free(intrp->htable[inum]);
41256349Sqs148142 		}
41266349Sqs148142 	}
41276349Sqs148142 
41286349Sqs148142 	kmem_free(intrp->htable, intrp->intr_size);
41296349Sqs148142 	intrp->intr_registered = B_FALSE;
41306349Sqs148142 	intrp->intr_enabled = B_FALSE;
41316349Sqs148142 	intrp->msi_intx_cnt = 0;
41326349Sqs148142 	intrp->intr_added = 0;
41336349Sqs148142 
41346349Sqs148142 	(void) hxge_ldgv_uninit(hxgep);
41356349Sqs148142 
41366349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_remove_intrs"));
41376349Sqs148142 }
41386349Sqs148142 
41396349Sqs148142 /*ARGSUSED*/
41406349Sqs148142 static void
41416349Sqs148142 hxge_remove_soft_intrs(p_hxge_t hxgep)
41426349Sqs148142 {
41436349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_remove_soft_intrs"));
41446349Sqs148142 
41456349Sqs148142 	if (hxgep->resched_id) {
41466349Sqs148142 		ddi_remove_softintr(hxgep->resched_id);
41476349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
41486349Sqs148142 		    "==> hxge_remove_soft_intrs: removed"));
41496349Sqs148142 		hxgep->resched_id = NULL;
41506349Sqs148142 	}
41516349Sqs148142 
41526349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_remove_soft_intrs"));
41536349Sqs148142 }
41546349Sqs148142 
41556349Sqs148142 /*ARGSUSED*/
41566349Sqs148142 void
41576349Sqs148142 hxge_intrs_enable(p_hxge_t hxgep)
41586349Sqs148142 {
41596349Sqs148142 	p_hxge_intr_t	intrp;
41606349Sqs148142 	int		i;
41616349Sqs148142 	int		status;
41626349Sqs148142 
41636349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intrs_enable"));
41646349Sqs148142 
41656349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
41666349Sqs148142 
41676349Sqs148142 	if (!intrp->intr_registered) {
41686349Sqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_intrs_enable: "
41696349Sqs148142 		    "interrupts are not registered"));
41706349Sqs148142 		return;
41716349Sqs148142 	}
41726349Sqs148142 
41736349Sqs148142 	if (intrp->intr_enabled) {
41746349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
41756349Sqs148142 		    "<== hxge_intrs_enable: already enabled"));
41766349Sqs148142 		return;
41776349Sqs148142 	}
41786349Sqs148142 
41796349Sqs148142 	if (intrp->intr_cap & DDI_INTR_FLAG_BLOCK) {
41806349Sqs148142 		status = ddi_intr_block_enable(intrp->htable,
41816349Sqs148142 		    intrp->intr_added);
41826349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intrs_enable "
41836349Sqs148142 		    "block enable - status 0x%x total inums #%d\n",
41846349Sqs148142 		    status, intrp->intr_added));
41856349Sqs148142 	} else {
41866349Sqs148142 		for (i = 0; i < intrp->intr_added; i++) {
41876349Sqs148142 			status = ddi_intr_enable(intrp->htable[i]);
41886349Sqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intrs_enable "
41896349Sqs148142 			    "ddi_intr_enable:enable - status 0x%x "
41906349Sqs148142 			    "total inums %d enable inum #%d\n",
41916349Sqs148142 			    status, intrp->intr_added, i));
41926349Sqs148142 			if (status == DDI_SUCCESS) {
41936349Sqs148142 				intrp->intr_enabled = B_TRUE;
41946349Sqs148142 			}
41956349Sqs148142 		}
41966349Sqs148142 	}
41976349Sqs148142 
41986349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intrs_enable"));
41996349Sqs148142 }
42006349Sqs148142 
42016349Sqs148142 /*ARGSUSED*/
42026349Sqs148142 static void
42036349Sqs148142 hxge_intrs_disable(p_hxge_t hxgep)
42046349Sqs148142 {
42056349Sqs148142 	p_hxge_intr_t	intrp;
42066349Sqs148142 	int		i;
42076349Sqs148142 
42086349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intrs_disable"));
42096349Sqs148142 
42106349Sqs148142 	intrp = (p_hxge_intr_t)&hxgep->hxge_intr_type;
42116349Sqs148142 
42126349Sqs148142 	if (!intrp->intr_registered) {
42136349Sqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intrs_disable: "
42146349Sqs148142 		    "interrupts are not registered"));
42156349Sqs148142 		return;
42166349Sqs148142 	}
42176349Sqs148142 
42186349Sqs148142 	if (intrp->intr_cap & DDI_INTR_FLAG_BLOCK) {
42196349Sqs148142 		(void) ddi_intr_block_disable(intrp->htable,
42206349Sqs148142 		    intrp->intr_added);
42216349Sqs148142 	} else {
42226349Sqs148142 		for (i = 0; i < intrp->intr_added; i++) {
42236349Sqs148142 			(void) ddi_intr_disable(intrp->htable[i]);
42246349Sqs148142 		}
42256349Sqs148142 	}
42266349Sqs148142 
42276349Sqs148142 	intrp->intr_enabled = B_FALSE;
42286349Sqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intrs_disable"));
42296349Sqs148142 }
42306349Sqs148142 
42316349Sqs148142 static hxge_status_t
42326349Sqs148142 hxge_mac_register(p_hxge_t hxgep)
42336349Sqs148142 {
42346349Sqs148142 	mac_register_t	*macp;
42356349Sqs148142 	int		status;
42366349Sqs148142 
42376349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_mac_register"));
42386349Sqs148142 
42396349Sqs148142 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
42406349Sqs148142 		return (HXGE_ERROR);
42416349Sqs148142 
42426349Sqs148142 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
42436349Sqs148142 	macp->m_driver = hxgep;
42446349Sqs148142 	macp->m_dip = hxgep->dip;
42456349Sqs148142 	macp->m_src_addr = hxgep->ouraddr.ether_addr_octet;
42466349Sqs148142 
42476349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
42486349Sqs148142 	    "hxge_mac_register: ether addr is %x:%x:%x:%x:%x:%x",
42496349Sqs148142 	    macp->m_src_addr[0],
42506349Sqs148142 	    macp->m_src_addr[1],
42516349Sqs148142 	    macp->m_src_addr[2],
42526349Sqs148142 	    macp->m_src_addr[3],
42536349Sqs148142 	    macp->m_src_addr[4],
42546349Sqs148142 	    macp->m_src_addr[5]));
42556349Sqs148142 
42566349Sqs148142 	macp->m_callbacks = &hxge_m_callbacks;
42576349Sqs148142 	macp->m_min_sdu = 0;
42587584SQiyan.Sun@Sun.COM 	macp->m_max_sdu = hxgep->vmac.maxframesize - MTU_TO_FRAME_SIZE;
42597584SQiyan.Sun@Sun.COM 	macp->m_margin = VLAN_TAGSZ;
42607584SQiyan.Sun@Sun.COM 	macp->m_priv_props = hxge_priv_props;
42617584SQiyan.Sun@Sun.COM 	macp->m_priv_prop_count = HXGE_MAX_PRIV_PROPS;
42626349Sqs148142 
42636349Sqs148142 	status = mac_register(macp, &hxgep->mach);
42646349Sqs148142 	mac_free(macp);
42656349Sqs148142 
42666349Sqs148142 	if (status != 0) {
42676349Sqs148142 		cmn_err(CE_WARN,
42686349Sqs148142 		    "hxge_mac_register failed (status %d instance %d)",
42696349Sqs148142 		    status, hxgep->instance);
42706349Sqs148142 		return (HXGE_ERROR);
42716349Sqs148142 	}
42726349Sqs148142 
42736349Sqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_mac_register success "
42746349Sqs148142 	    "(instance %d)", hxgep->instance));
42756349Sqs148142 
42766349Sqs148142 	return (HXGE_OK);
42776349Sqs148142 }
42786349Sqs148142 
42796349Sqs148142 static int
42806349Sqs148142 hxge_init_common_dev(p_hxge_t hxgep)
42816349Sqs148142 {
42826349Sqs148142 	p_hxge_hw_list_t	hw_p;
42836349Sqs148142 	dev_info_t		*p_dip;
42846349Sqs148142 
42856349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL, "==> hxge_init_common_dev"));
42866349Sqs148142 
42876349Sqs148142 	p_dip = hxgep->p_dip;
42886349Sqs148142 	MUTEX_ENTER(&hxge_common_lock);
42896349Sqs148142 
42906349Sqs148142 	/*
42916349Sqs148142 	 * Loop through existing per Hydra hardware list.
42926349Sqs148142 	 */
42936349Sqs148142 	for (hw_p = hxge_hw_list; hw_p; hw_p = hw_p->next) {
42946349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MOD_CTL,
42956349Sqs148142 		    "==> hxge_init_common_dev: hw_p $%p parent dip $%p",
42966349Sqs148142 		    hw_p, p_dip));
42976349Sqs148142 		if (hw_p->parent_devp == p_dip) {
42986349Sqs148142 			hxgep->hxge_hw_p = hw_p;
42996349Sqs148142 			hw_p->ndevs++;
43006349Sqs148142 			hw_p->hxge_p = hxgep;
43016349Sqs148142 			HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43026349Sqs148142 			    "==> hxge_init_common_device: "
43036349Sqs148142 			    "hw_p $%p parent dip $%p ndevs %d (found)",
43046349Sqs148142 			    hw_p, p_dip, hw_p->ndevs));
43056349Sqs148142 			break;
43066349Sqs148142 		}
43076349Sqs148142 	}
43086349Sqs148142 
43096349Sqs148142 	if (hw_p == NULL) {
43106349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43116349Sqs148142 		    "==> hxge_init_common_dev: parent dip $%p (new)", p_dip));
43126349Sqs148142 		hw_p = kmem_zalloc(sizeof (hxge_hw_list_t), KM_SLEEP);
43136349Sqs148142 		hw_p->parent_devp = p_dip;
43146349Sqs148142 		hw_p->magic = HXGE_MAGIC;
43156349Sqs148142 		hxgep->hxge_hw_p = hw_p;
43166349Sqs148142 		hw_p->ndevs++;
43176349Sqs148142 		hw_p->hxge_p = hxgep;
43186349Sqs148142 		hw_p->next = hxge_hw_list;
43196349Sqs148142 
43206349Sqs148142 		MUTEX_INIT(&hw_p->hxge_cfg_lock, NULL, MUTEX_DRIVER, NULL);
43216349Sqs148142 		MUTEX_INIT(&hw_p->hxge_tcam_lock, NULL, MUTEX_DRIVER, NULL);
43226349Sqs148142 		MUTEX_INIT(&hw_p->hxge_vlan_lock, NULL, MUTEX_DRIVER, NULL);
43236349Sqs148142 
43246349Sqs148142 		hxge_hw_list = hw_p;
43256349Sqs148142 	}
43266349Sqs148142 	MUTEX_EXIT(&hxge_common_lock);
43276349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43286349Sqs148142 	    "==> hxge_init_common_dev (hxge_hw_list) $%p", hxge_hw_list));
43296349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL, "<== hxge_init_common_dev"));
43306349Sqs148142 
43316349Sqs148142 	return (HXGE_OK);
43326349Sqs148142 }
43336349Sqs148142 
43346349Sqs148142 static void
43356349Sqs148142 hxge_uninit_common_dev(p_hxge_t hxgep)
43366349Sqs148142 {
43376349Sqs148142 	p_hxge_hw_list_t	hw_p, h_hw_p;
43386349Sqs148142 	dev_info_t		*p_dip;
43396349Sqs148142 
43406349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL, "==> hxge_uninit_common_dev"));
43416349Sqs148142 	if (hxgep->hxge_hw_p == NULL) {
43426349Sqs148142 		HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43436349Sqs148142 		    "<== hxge_uninit_common_dev (no common)"));
43446349Sqs148142 		return;
43456349Sqs148142 	}
43466349Sqs148142 
43476349Sqs148142 	MUTEX_ENTER(&hxge_common_lock);
43486349Sqs148142 	h_hw_p = hxge_hw_list;
43496349Sqs148142 	for (hw_p = hxge_hw_list; hw_p; hw_p = hw_p->next) {
43506349Sqs148142 		p_dip = hw_p->parent_devp;
43516349Sqs148142 		if (hxgep->hxge_hw_p == hw_p && p_dip == hxgep->p_dip &&
43526349Sqs148142 		    hxgep->hxge_hw_p->magic == HXGE_MAGIC &&
43536349Sqs148142 		    hw_p->magic == HXGE_MAGIC) {
43546349Sqs148142 			HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43556349Sqs148142 			    "==> hxge_uninit_common_dev: "
43566349Sqs148142 			    "hw_p $%p parent dip $%p ndevs %d (found)",
43576349Sqs148142 			    hw_p, p_dip, hw_p->ndevs));
43586349Sqs148142 
43596349Sqs148142 			hxgep->hxge_hw_p = NULL;
43606349Sqs148142 			if (hw_p->ndevs) {
43616349Sqs148142 				hw_p->ndevs--;
43626349Sqs148142 			}
43636349Sqs148142 			hw_p->hxge_p = NULL;
43646349Sqs148142 			if (!hw_p->ndevs) {
43656349Sqs148142 				MUTEX_DESTROY(&hw_p->hxge_vlan_lock);
43666349Sqs148142 				MUTEX_DESTROY(&hw_p->hxge_tcam_lock);
43676349Sqs148142 				MUTEX_DESTROY(&hw_p->hxge_cfg_lock);
43686349Sqs148142 				HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43696349Sqs148142 				    "==> hxge_uninit_common_dev: "
43706349Sqs148142 				    "hw_p $%p parent dip $%p ndevs %d (last)",
43716349Sqs148142 				    hw_p, p_dip, hw_p->ndevs));
43726349Sqs148142 
43736349Sqs148142 				if (hw_p == hxge_hw_list) {
43746349Sqs148142 					HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43756349Sqs148142 					    "==> hxge_uninit_common_dev:"
43766349Sqs148142 					    "remove head "
43776349Sqs148142 					    "hw_p $%p parent dip $%p "
43786349Sqs148142 					    "ndevs %d (head)",
43796349Sqs148142 					    hw_p, p_dip, hw_p->ndevs));
43806349Sqs148142 					hxge_hw_list = hw_p->next;
43816349Sqs148142 				} else {
43826349Sqs148142 					HXGE_DEBUG_MSG((hxgep, MOD_CTL,
43836349Sqs148142 					    "==> hxge_uninit_common_dev:"
43846349Sqs148142 					    "remove middle "
43856349Sqs148142 					    "hw_p $%p parent dip $%p "
43866349Sqs148142 					    "ndevs %d (middle)",
43876349Sqs148142 					    hw_p, p_dip, hw_p->ndevs));
43886349Sqs148142 					h_hw_p->next = hw_p->next;
43896349Sqs148142 				}
43906349Sqs148142 
43916349Sqs148142 				KMEM_FREE(hw_p, sizeof (hxge_hw_list_t));
43926349Sqs148142 			}
43936349Sqs148142 			break;
43946349Sqs148142 		} else {
43956349Sqs148142 			h_hw_p = hw_p;
43966349Sqs148142 		}
43976349Sqs148142 	}
43986349Sqs148142 
43996349Sqs148142 	MUTEX_EXIT(&hxge_common_lock);
44006349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL,
44016349Sqs148142 	    "==> hxge_uninit_common_dev (hxge_hw_list) $%p", hxge_hw_list));
44026349Sqs148142 
44036349Sqs148142 	HXGE_DEBUG_MSG((hxgep, MOD_CTL, "<= hxge_uninit_common_dev"));
44046349Sqs148142 }
44057584SQiyan.Sun@Sun.COM 
44067584SQiyan.Sun@Sun.COM static void
44077584SQiyan.Sun@Sun.COM hxge_link_poll(void *arg)
44087584SQiyan.Sun@Sun.COM {
44097584SQiyan.Sun@Sun.COM 	p_hxge_t		hxgep = (p_hxge_t)arg;
44107584SQiyan.Sun@Sun.COM 	hpi_handle_t		handle;
44117584SQiyan.Sun@Sun.COM 	p_hxge_stats_t		statsp;
44127584SQiyan.Sun@Sun.COM 	cip_link_stat_t		link_stat;
44137584SQiyan.Sun@Sun.COM 	hxge_timeout		*to = &hxgep->timeout;
44147584SQiyan.Sun@Sun.COM 
44157584SQiyan.Sun@Sun.COM 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
44167584SQiyan.Sun@Sun.COM 	statsp = (p_hxge_stats_t)hxgep->statsp;
44177584SQiyan.Sun@Sun.COM 	HXGE_REG_RD32(handle, CIP_LINK_STAT, &link_stat.value);
44187584SQiyan.Sun@Sun.COM 
44197584SQiyan.Sun@Sun.COM 	if (to->link_status != link_stat.bits.xpcs0_link_up) {
44207584SQiyan.Sun@Sun.COM 		to->link_status = link_stat.bits.xpcs0_link_up;
44217584SQiyan.Sun@Sun.COM 
44227584SQiyan.Sun@Sun.COM 		if (link_stat.bits.xpcs0_link_up) {
44237584SQiyan.Sun@Sun.COM 			mac_link_update(hxgep->mach, LINK_STATE_UP);
44247584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_speed = 10000;
44257584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_duplex = 2;
44267584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_up = 1;
44277584SQiyan.Sun@Sun.COM 		} else {
44287584SQiyan.Sun@Sun.COM 			mac_link_update(hxgep->mach, LINK_STATE_DOWN);
44297584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_speed = 0;
44307584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_duplex = 0;
44317584SQiyan.Sun@Sun.COM 			statsp->mac_stats.link_up = 0;
44327584SQiyan.Sun@Sun.COM 		}
44337584SQiyan.Sun@Sun.COM 	}
44347584SQiyan.Sun@Sun.COM 
44357584SQiyan.Sun@Sun.COM 	/* Restart the link status timer to check the link status */
44367584SQiyan.Sun@Sun.COM 	MUTEX_ENTER(&to->lock);
44377584SQiyan.Sun@Sun.COM 	to->id = timeout(hxge_link_poll, arg, to->ticks);
44387584SQiyan.Sun@Sun.COM 	MUTEX_EXIT(&to->lock);
44397584SQiyan.Sun@Sun.COM }
4440