xref: /titanic_51/usr/src/uts/common/io/hxge/hxge_virtual.c (revision 2bc987325e3ded1865bff043128661815c4690b9)
13dec9fcdSqs148142 /*
23dec9fcdSqs148142  * CDDL HEADER START
33dec9fcdSqs148142  *
43dec9fcdSqs148142  * The contents of this file are subject to the terms of the
53dec9fcdSqs148142  * Common Development and Distribution License (the "License").
63dec9fcdSqs148142  * You may not use this file except in compliance with the License.
73dec9fcdSqs148142  *
83dec9fcdSqs148142  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93dec9fcdSqs148142  * or http://www.opensolaris.org/os/licensing.
103dec9fcdSqs148142  * See the License for the specific language governing permissions
113dec9fcdSqs148142  * and limitations under the License.
123dec9fcdSqs148142  *
133dec9fcdSqs148142  * When distributing Covered Code, include this CDDL HEADER in each
143dec9fcdSqs148142  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153dec9fcdSqs148142  * If applicable, add the following below this CDDL HEADER, with the
163dec9fcdSqs148142  * fields enclosed by brackets "[]" replaced with your own identifying
173dec9fcdSqs148142  * information: Portions Copyright [yyyy] [name of copyright owner]
183dec9fcdSqs148142  *
193dec9fcdSqs148142  * CDDL HEADER END
203dec9fcdSqs148142  */
213dec9fcdSqs148142 /*
223dec9fcdSqs148142  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233dec9fcdSqs148142  * Use is subject to license terms.
24b97d6ca7SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
253dec9fcdSqs148142  */
263dec9fcdSqs148142 
273dec9fcdSqs148142 #include <hxge_impl.h>
283dec9fcdSqs148142 #include <hxge_vmac.h>
293dec9fcdSqs148142 #include <hxge_pfc.h>
303dec9fcdSqs148142 #include <hpi_pfc.h>
313dec9fcdSqs148142 
323dec9fcdSqs148142 static hxge_status_t hxge_get_mac_addr_properties(p_hxge_t);
333dec9fcdSqs148142 static void hxge_use_cfg_hydra_properties(p_hxge_t);
343dec9fcdSqs148142 static void hxge_use_cfg_dma_config(p_hxge_t);
353dec9fcdSqs148142 static void hxge_use_cfg_class_config(p_hxge_t);
363dec9fcdSqs148142 static void hxge_set_hw_dma_config(p_hxge_t);
373dec9fcdSqs148142 static void hxge_set_hw_class_config(p_hxge_t);
383dec9fcdSqs148142 static void hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
393dec9fcdSqs148142 	uint8_t endldg, int *ngrps);
403dec9fcdSqs148142 
413dec9fcdSqs148142 extern uint16_t hxge_rcr_timeout;
423dec9fcdSqs148142 extern uint16_t hxge_rcr_threshold;
433dec9fcdSqs148142 
443dec9fcdSqs148142 extern uint32_t hxge_rbr_size;
453dec9fcdSqs148142 extern uint32_t hxge_rcr_size;
463dec9fcdSqs148142 
47b97d6ca7SMilan Jurik extern uint_t hxge_rx_intr(caddr_t, caddr_t);
48b97d6ca7SMilan Jurik extern uint_t hxge_tx_intr(caddr_t, caddr_t);
49b97d6ca7SMilan Jurik extern uint_t hxge_vmac_intr(caddr_t, caddr_t);
50b97d6ca7SMilan Jurik extern uint_t hxge_syserr_intr(caddr_t, caddr_t);
51b97d6ca7SMilan Jurik extern uint_t hxge_pfc_intr(caddr_t, caddr_t);
523dec9fcdSqs148142 
533dec9fcdSqs148142 /*
543dec9fcdSqs148142  * Entry point to populate configuration parameters into the master hxge
553dec9fcdSqs148142  * data structure and to update the NDD parameter list.
563dec9fcdSqs148142  */
573dec9fcdSqs148142 hxge_status_t
583dec9fcdSqs148142 hxge_get_config_properties(p_hxge_t hxgep)
593dec9fcdSqs148142 {
603dec9fcdSqs148142 	hxge_status_t		status = HXGE_OK;
613dec9fcdSqs148142 
623dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " ==> hxge_get_config_properties"));
633dec9fcdSqs148142 
643dec9fcdSqs148142 	if (hxgep->hxge_hw_p == NULL) {
653dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
663dec9fcdSqs148142 		    " hxge_get_config_properties: common hardware not set"));
673dec9fcdSqs148142 		return (HXGE_ERROR);
683dec9fcdSqs148142 	}
693dec9fcdSqs148142 
703dec9fcdSqs148142 	hxgep->classifier.tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
713dec9fcdSqs148142 
723dec9fcdSqs148142 	status = hxge_get_mac_addr_properties(hxgep);
733dec9fcdSqs148142 	if (status != HXGE_OK) {
743dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
753dec9fcdSqs148142 		    " hxge_get_config_properties: mac addr properties failed"));
763dec9fcdSqs148142 		return (status);
773dec9fcdSqs148142 	}
783dec9fcdSqs148142 
793dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, VPD_CTL,
803dec9fcdSqs148142 	    " ==> hxge_get_config_properties: Hydra"));
813dec9fcdSqs148142 
823dec9fcdSqs148142 	hxge_use_cfg_hydra_properties(hxgep);
833dec9fcdSqs148142 
843dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, VPD_CTL, " <== hxge_get_config_properties"));
853dec9fcdSqs148142 	return (HXGE_OK);
863dec9fcdSqs148142 }
873dec9fcdSqs148142 
883dec9fcdSqs148142 
893dec9fcdSqs148142 static void
903dec9fcdSqs148142 hxge_set_hw_vlan_class_config(p_hxge_t hxgep)
913dec9fcdSqs148142 {
923dec9fcdSqs148142 	int			i;
933dec9fcdSqs148142 	p_hxge_param_t		param_arr;
943dec9fcdSqs148142 	uint_t			vlan_cnt;
953dec9fcdSqs148142 	int			*vlan_cfg_val;
963dec9fcdSqs148142 	hxge_param_map_t	*vmap;
973dec9fcdSqs148142 	char			*prop;
983dec9fcdSqs148142 	p_hxge_class_pt_cfg_t 	p_class_cfgp;
993dec9fcdSqs148142 	uint32_t		good_cfg[32];
1003dec9fcdSqs148142 	int			good_count = 0;
1013dec9fcdSqs148142 	hxge_mv_cfg_t		*vlan_tbl;
1023dec9fcdSqs148142 
1033dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_vlan_config"));
1043dec9fcdSqs148142 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
1053dec9fcdSqs148142 
1063dec9fcdSqs148142 	param_arr = hxgep->param_arr;
1073dec9fcdSqs148142 	prop = param_arr[param_vlan_ids].fcode_name;
1083dec9fcdSqs148142 
1093dec9fcdSqs148142 	/*
1103dec9fcdSqs148142 	 * uint32_t array, each array entry specifying a VLAN id
1113dec9fcdSqs148142 	 */
1123dec9fcdSqs148142 	for (i = 0; i <= VLAN_ID_MAX; i++) {
1133dec9fcdSqs148142 		p_class_cfgp->vlan_tbl[i].flag = 0;
1143dec9fcdSqs148142 	}
1153dec9fcdSqs148142 
1163dec9fcdSqs148142 	vlan_tbl = (hxge_mv_cfg_t *)&p_class_cfgp->vlan_tbl[0];
1173dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
1183dec9fcdSqs148142 	    &vlan_cfg_val, &vlan_cnt) != DDI_PROP_SUCCESS) {
1193dec9fcdSqs148142 		return;
1203dec9fcdSqs148142 	}
1213dec9fcdSqs148142 
1223dec9fcdSqs148142 	for (i = 0; i < vlan_cnt; i++) {
1233dec9fcdSqs148142 		vmap = (hxge_param_map_t *)&vlan_cfg_val[i];
1243dec9fcdSqs148142 		if ((vmap->param_id) && (vmap->param_id <= VLAN_ID_MAX)) {
1253dec9fcdSqs148142 			HXGE_DEBUG_MSG((hxgep, CFG2_CTL,
1263dec9fcdSqs148142 			    " hxge_vlan_config vlan id %d", vmap->param_id));
1273dec9fcdSqs148142 
1283dec9fcdSqs148142 			good_cfg[good_count] = vlan_cfg_val[i];
1293dec9fcdSqs148142 			if (vlan_tbl[vmap->param_id].flag == 0)
1303dec9fcdSqs148142 				good_count++;
1313dec9fcdSqs148142 
1323dec9fcdSqs148142 			vlan_tbl[vmap->param_id].flag = 1;
1333dec9fcdSqs148142 		}
1343dec9fcdSqs148142 	}
1353dec9fcdSqs148142 
1363dec9fcdSqs148142 	ddi_prop_free(vlan_cfg_val);
1373dec9fcdSqs148142 	if (good_count != vlan_cnt) {
1383dec9fcdSqs148142 		(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
1393dec9fcdSqs148142 		    hxgep->dip, prop, (int *)good_cfg, good_count);
1403dec9fcdSqs148142 	}
1413dec9fcdSqs148142 
1423dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_vlan_config"));
1433dec9fcdSqs148142 }
1443dec9fcdSqs148142 
1453dec9fcdSqs148142 
1463dec9fcdSqs148142 /*
1473dec9fcdSqs148142  * Read param_vlan_ids and param_implicit_vlan_id properties from either
1483dec9fcdSqs148142  * hxge.conf or OBP. Update the soft properties. Populate these
1493dec9fcdSqs148142  * properties into the hxge data structure.
1503dec9fcdSqs148142  */
1513dec9fcdSqs148142 static void
1523dec9fcdSqs148142 hxge_use_cfg_vlan_class_config(p_hxge_t hxgep)
1533dec9fcdSqs148142 {
1543dec9fcdSqs148142 	uint_t		vlan_cnt;
1553dec9fcdSqs148142 	int		*vlan_cfg_val;
1563dec9fcdSqs148142 	int		status;
1573dec9fcdSqs148142 	p_hxge_param_t	param_arr;
1583dec9fcdSqs148142 	char		*prop;
1593dec9fcdSqs148142 	uint32_t	implicit_vlan_id = 0;
1603dec9fcdSqs148142 	int		*int_prop_val;
1613dec9fcdSqs148142 	uint_t		prop_len;
1623dec9fcdSqs148142 	p_hxge_param_t	pa;
1633dec9fcdSqs148142 
1643dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_vlan_config"));
1653dec9fcdSqs148142 	param_arr = hxgep->param_arr;
1663dec9fcdSqs148142 	prop = param_arr[param_vlan_ids].fcode_name;
1673dec9fcdSqs148142 
1683dec9fcdSqs148142 	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
1693dec9fcdSqs148142 	    &vlan_cfg_val, &vlan_cnt);
1703dec9fcdSqs148142 	if (status == DDI_PROP_SUCCESS) {
1713dec9fcdSqs148142 		status = ddi_prop_update_int_array(DDI_DEV_T_NONE,
1723dec9fcdSqs148142 		    hxgep->dip, prop, vlan_cfg_val, vlan_cnt);
1733dec9fcdSqs148142 		ddi_prop_free(vlan_cfg_val);
1743dec9fcdSqs148142 	}
1753dec9fcdSqs148142 
1763dec9fcdSqs148142 	pa = &param_arr[param_implicit_vlan_id];
1773dec9fcdSqs148142 	prop = pa->fcode_name;
1783dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
1793dec9fcdSqs148142 	    &int_prop_val, &prop_len) == DDI_PROP_SUCCESS) {
1803dec9fcdSqs148142 		implicit_vlan_id = (uint32_t)*int_prop_val;
1813dec9fcdSqs148142 		if ((implicit_vlan_id >= pa->minimum) ||
1823dec9fcdSqs148142 		    (implicit_vlan_id <= pa->maximum)) {
1833dec9fcdSqs148142 			status = ddi_prop_update_int(DDI_DEV_T_NONE, hxgep->dip,
1843dec9fcdSqs148142 			    prop, (int)implicit_vlan_id);
1853dec9fcdSqs148142 		}
1863dec9fcdSqs148142 		ddi_prop_free(int_prop_val);
1873dec9fcdSqs148142 	}
1883dec9fcdSqs148142 
1893dec9fcdSqs148142 	hxge_set_hw_vlan_class_config(hxgep);
1903dec9fcdSqs148142 
1913dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_vlan_config"));
1923dec9fcdSqs148142 }
1933dec9fcdSqs148142 
1943dec9fcdSqs148142 /*
1953dec9fcdSqs148142  * Read in the configuration parameters from either hxge.conf or OBP and
1963dec9fcdSqs148142  * populate the master data structure hxge.
1973dec9fcdSqs148142  * Use these parameters to update the soft properties and the ndd array.
1983dec9fcdSqs148142  */
1993dec9fcdSqs148142 static void
2003dec9fcdSqs148142 hxge_use_cfg_hydra_properties(p_hxge_t hxgep)
2013dec9fcdSqs148142 {
2023dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_hydra_properties"));
2033dec9fcdSqs148142 
2043dec9fcdSqs148142 	(void) hxge_use_cfg_dma_config(hxgep);
2053dec9fcdSqs148142 	(void) hxge_use_cfg_vlan_class_config(hxgep);
2063dec9fcdSqs148142 	(void) hxge_use_cfg_class_config(hxgep);
2073dec9fcdSqs148142 
2083dec9fcdSqs148142 	/*
2093dec9fcdSqs148142 	 * Read in the hardware (fcode) properties and use these properties
2103dec9fcdSqs148142 	 * to update the ndd array.
2113dec9fcdSqs148142 	 */
2123dec9fcdSqs148142 	(void) hxge_get_param_soft_properties(hxgep);
2133dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_hydra_properties"));
2143dec9fcdSqs148142 }
2153dec9fcdSqs148142 
2163dec9fcdSqs148142 
2173dec9fcdSqs148142 /*
2183dec9fcdSqs148142  * Read param_accept_jumbo, param_rxdma_intr_time, and param_rxdma_intr_pkts
2193dec9fcdSqs148142  * from either hxge.conf or OBP.
2203dec9fcdSqs148142  * Update the soft properties.
2213dec9fcdSqs148142  * Populate these properties into the hxge data structure for latter use.
2223dec9fcdSqs148142  */
2233dec9fcdSqs148142 static void
2243dec9fcdSqs148142 hxge_use_cfg_dma_config(p_hxge_t hxgep)
2253dec9fcdSqs148142 {
2263dec9fcdSqs148142 	int			tx_ndmas, rx_ndmas;
2273dec9fcdSqs148142 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
2283dec9fcdSqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
2293dec9fcdSqs148142 	dev_info_t		*dip;
2303dec9fcdSqs148142 	p_hxge_param_t		param_arr;
2313dec9fcdSqs148142 	char			*prop;
2323dec9fcdSqs148142 	int 			*prop_val;
2333dec9fcdSqs148142 	uint_t 			prop_len;
2343dec9fcdSqs148142 
2353dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_dma_config"));
2363dec9fcdSqs148142 	param_arr = hxgep->param_arr;
2373dec9fcdSqs148142 
2383dec9fcdSqs148142 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
2393dec9fcdSqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
2403dec9fcdSqs148142 	dip = hxgep->dip;
2413dec9fcdSqs148142 
2423dec9fcdSqs148142 	tx_ndmas = 4;
2433dec9fcdSqs148142 	p_cfgp->start_tdc = 0;
2443dec9fcdSqs148142 	p_cfgp->max_tdcs =  hxgep->max_tdcs = tx_ndmas;
2453dec9fcdSqs148142 	hxgep->tdc_mask = (tx_ndmas - 1);
2463dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
2473dec9fcdSqs148142 	    "p_cfgp 0x%llx max_tdcs %d hxgep->max_tdcs %d",
2483dec9fcdSqs148142 	    p_cfgp, p_cfgp->max_tdcs, hxgep->max_tdcs));
2493dec9fcdSqs148142 
2503dec9fcdSqs148142 	rx_ndmas = 4;
2513dec9fcdSqs148142 	p_cfgp->start_rdc = 0;
2523dec9fcdSqs148142 	p_cfgp->max_rdcs =  hxgep->max_rdcs = rx_ndmas;
2533dec9fcdSqs148142 
2543dec9fcdSqs148142 	p_cfgp->start_ldg = 0;
2553dec9fcdSqs148142 	p_cfgp->max_ldgs = HXGE_INT_MAX_LDG;
2563dec9fcdSqs148142 
2573dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_default_dma_config: "
2583dec9fcdSqs148142 	    "p_cfgp 0x%llx max_rdcs %d hxgep->max_rdcs %d",
2593dec9fcdSqs148142 	    p_cfgp, p_cfgp->max_rdcs, hxgep->max_rdcs));
2603dec9fcdSqs148142 
2613dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
2623dec9fcdSqs148142 	    "p_cfgp 0x%016llx start_ldg %d hxgep->max_ldgs %d ",
2633dec9fcdSqs148142 	    p_cfgp, p_cfgp->start_ldg,  p_cfgp->max_ldgs));
2643dec9fcdSqs148142 
2653dec9fcdSqs148142 	/*
2663dec9fcdSqs148142 	 * add code for individual rdc properties
2673dec9fcdSqs148142 	 */
2683dec9fcdSqs148142 	prop = param_arr[param_accept_jumbo].fcode_name;
2693dec9fcdSqs148142 
2703dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
2713dec9fcdSqs148142 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
2723dec9fcdSqs148142 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
2733dec9fcdSqs148142 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
2743dec9fcdSqs148142 			    hxgep->dip, prop, prop_val, prop_len);
2753dec9fcdSqs148142 		}
2763dec9fcdSqs148142 		ddi_prop_free(prop_val);
2773dec9fcdSqs148142 	}
2783dec9fcdSqs148142 
2793dec9fcdSqs148142 	prop = param_arr[param_rxdma_intr_time].fcode_name;
2803dec9fcdSqs148142 
2813dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
2823dec9fcdSqs148142 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
2833dec9fcdSqs148142 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
2843dec9fcdSqs148142 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
2853dec9fcdSqs148142 			    hxgep->dip, prop, prop_val, prop_len);
2863dec9fcdSqs148142 		}
2873dec9fcdSqs148142 		ddi_prop_free(prop_val);
2883dec9fcdSqs148142 	}
2893dec9fcdSqs148142 
2903dec9fcdSqs148142 	prop = param_arr[param_rxdma_intr_pkts].fcode_name;
2913dec9fcdSqs148142 
2923dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
2933dec9fcdSqs148142 	    &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
2943dec9fcdSqs148142 		if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
2953dec9fcdSqs148142 			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
2963dec9fcdSqs148142 			    hxgep->dip, prop, prop_val, prop_len);
2973dec9fcdSqs148142 		}
2983dec9fcdSqs148142 		ddi_prop_free(prop_val);
2993dec9fcdSqs148142 	}
3003dec9fcdSqs148142 
3013dec9fcdSqs148142 	hxge_set_hw_dma_config(hxgep);
3023dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "<== hxge_use_cfg_dma_config"));
3033dec9fcdSqs148142 }
3043dec9fcdSqs148142 
3053dec9fcdSqs148142 static void
3063dec9fcdSqs148142 hxge_use_cfg_class_config(p_hxge_t hxgep)
3073dec9fcdSqs148142 {
3083dec9fcdSqs148142 	hxge_set_hw_class_config(hxgep);
3093dec9fcdSqs148142 }
3103dec9fcdSqs148142 
3113dec9fcdSqs148142 static void
3123dec9fcdSqs148142 hxge_set_hw_dma_config(p_hxge_t hxgep)
3133dec9fcdSqs148142 {
3143dec9fcdSqs148142 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
3153dec9fcdSqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
3163dec9fcdSqs148142 
3173dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_set_hw_dma_config"));
3183dec9fcdSqs148142 
3193dec9fcdSqs148142 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
3203dec9fcdSqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
3213dec9fcdSqs148142 
3223dec9fcdSqs148142 	/* Transmit DMA Channels */
3233dec9fcdSqs148142 	hxgep->ntdc = p_cfgp->max_tdcs;
3243dec9fcdSqs148142 
3253dec9fcdSqs148142 	/* Receive DMA Channels */
3263dec9fcdSqs148142 	hxgep->nrdc = p_cfgp->max_rdcs;
3273dec9fcdSqs148142 
3283dec9fcdSqs148142 	p_dma_cfgp->rbr_size = hxge_rbr_size;
3298ad8db65SMichael Speer 	if (hxge_rcr_size > HXGE_RCR_MAX)
3308ad8db65SMichael Speer 		hxge_rcr_size = HXGE_RCR_MAX;
3313dec9fcdSqs148142 	p_dma_cfgp->rcr_size = hxge_rcr_size;
3323dec9fcdSqs148142 
3333dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_dma_config"));
3343dec9fcdSqs148142 }
3353dec9fcdSqs148142 
3363dec9fcdSqs148142 
3373dec9fcdSqs148142 boolean_t
3383dec9fcdSqs148142 hxge_check_rxdma_port_member(p_hxge_t hxgep, uint8_t rdc)
3393dec9fcdSqs148142 {
3403dec9fcdSqs148142 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
3413dec9fcdSqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
3423dec9fcdSqs148142 	int			status = B_TRUE;
3433dec9fcdSqs148142 
3443dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_rxdma_port_member"));
3453dec9fcdSqs148142 
3463dec9fcdSqs148142 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
3473dec9fcdSqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
3483dec9fcdSqs148142 
3493dec9fcdSqs148142 	/* Receive DMA Channels */
3503dec9fcdSqs148142 	if (rdc < p_cfgp->max_rdcs)
3513dec9fcdSqs148142 		status = B_TRUE;
3523dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_rxdma_port_member"));
3533dec9fcdSqs148142 
3543dec9fcdSqs148142 	return (status);
3553dec9fcdSqs148142 }
3563dec9fcdSqs148142 
3573dec9fcdSqs148142 boolean_t
3583dec9fcdSqs148142 hxge_check_txdma_port_member(p_hxge_t hxgep, uint8_t tdc)
3593dec9fcdSqs148142 {
3603dec9fcdSqs148142 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
3613dec9fcdSqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
3623dec9fcdSqs148142 	int			status = B_FALSE;
3633dec9fcdSqs148142 
3643dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_txdma_port_member"));
3653dec9fcdSqs148142 
3663dec9fcdSqs148142 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
3673dec9fcdSqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
3683dec9fcdSqs148142 
3693dec9fcdSqs148142 	/* Receive DMA Channels */
3703dec9fcdSqs148142 	if (tdc < p_cfgp->max_tdcs)
3713dec9fcdSqs148142 		status = B_TRUE;
3723dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_txdma_port_member"));
3733dec9fcdSqs148142 
3743dec9fcdSqs148142 	return (status);
3753dec9fcdSqs148142 }
3763dec9fcdSqs148142 
3773dec9fcdSqs148142 
3783dec9fcdSqs148142 /*
3793dec9fcdSqs148142  * Read the L2 classes, L3 classes, and initial hash from either hxge.conf
3803dec9fcdSqs148142  * or OBP. Populate these properties into the hxge data structure for latter
3813dec9fcdSqs148142  * use. Note that we are not updating these soft properties.
3823dec9fcdSqs148142  */
3833dec9fcdSqs148142 static void
3843dec9fcdSqs148142 hxge_set_hw_class_config(p_hxge_t hxgep)
3853dec9fcdSqs148142 {
3863dec9fcdSqs148142 	int			i, j;
3873dec9fcdSqs148142 	p_hxge_param_t		param_arr;
3883dec9fcdSqs148142 	int			*int_prop_val;
3893dec9fcdSqs148142 	uint32_t		cfg_value;
3903dec9fcdSqs148142 	char			*prop;
3913dec9fcdSqs148142 	p_hxge_class_pt_cfg_t	p_class_cfgp;
3923dec9fcdSqs148142 	int			start_prop, end_prop;
3933dec9fcdSqs148142 	uint_t			prop_cnt;
3943dec9fcdSqs148142 
3953dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_class_config"));
3963dec9fcdSqs148142 
3973dec9fcdSqs148142 	p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
3983dec9fcdSqs148142 
3993dec9fcdSqs148142 	param_arr = hxgep->param_arr;
4003dec9fcdSqs148142 
4013dec9fcdSqs148142 	/*
4023dec9fcdSqs148142 	 * L2 class configuration. User configurable ether types
4033dec9fcdSqs148142 	 */
4043dec9fcdSqs148142 	start_prop =  param_class_cfg_ether_usr1;
4053dec9fcdSqs148142 	end_prop = param_class_cfg_ether_usr2;
4063dec9fcdSqs148142 
4073dec9fcdSqs148142 	for (i = start_prop; i <= end_prop; i++) {
4083dec9fcdSqs148142 		prop = param_arr[i].fcode_name;
4093dec9fcdSqs148142 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
4103dec9fcdSqs148142 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
4113dec9fcdSqs148142 			cfg_value =  (uint32_t)*int_prop_val;
4123dec9fcdSqs148142 			ddi_prop_free(int_prop_val);
4133dec9fcdSqs148142 		} else {
4143dec9fcdSqs148142 			cfg_value = (uint32_t)param_arr[i].value;
4153dec9fcdSqs148142 		}
4163dec9fcdSqs148142 
4173dec9fcdSqs148142 		j = (i - start_prop) + TCAM_CLASS_ETYPE_1;
4183dec9fcdSqs148142 		p_class_cfgp->class_cfg[j] = cfg_value;
4193dec9fcdSqs148142 	}
4203dec9fcdSqs148142 
4213dec9fcdSqs148142 	/*
4223dec9fcdSqs148142 	 * Use properties from either .conf or the NDD param array. Only bits
4233dec9fcdSqs148142 	 * 2 and 3 are significant
4243dec9fcdSqs148142 	 */
4253dec9fcdSqs148142 	start_prop =  param_class_opt_ipv4_tcp;
4263dec9fcdSqs148142 	end_prop = param_class_opt_ipv6_sctp;
4273dec9fcdSqs148142 
4283dec9fcdSqs148142 	for (i = start_prop; i <= end_prop; i++) {
4293dec9fcdSqs148142 		prop = param_arr[i].fcode_name;
4303dec9fcdSqs148142 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
4313dec9fcdSqs148142 		    0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
4323dec9fcdSqs148142 			cfg_value =  (uint32_t)*int_prop_val;
4333dec9fcdSqs148142 			ddi_prop_free(int_prop_val);
4343dec9fcdSqs148142 		} else {
4353dec9fcdSqs148142 			cfg_value = (uint32_t)param_arr[i].value;
4363dec9fcdSqs148142 		}
4373dec9fcdSqs148142 
4383dec9fcdSqs148142 		j = (i - start_prop) + TCAM_CLASS_TCP_IPV4;
4393dec9fcdSqs148142 		p_class_cfgp->class_cfg[j] = cfg_value;
4403dec9fcdSqs148142 	}
4413dec9fcdSqs148142 
4423dec9fcdSqs148142 	prop = param_arr[param_hash_init_value].fcode_name;
4433dec9fcdSqs148142 
4443dec9fcdSqs148142 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
4453dec9fcdSqs148142 	    &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
4463dec9fcdSqs148142 		cfg_value =  (uint32_t)*int_prop_val;
4473dec9fcdSqs148142 		ddi_prop_free(int_prop_val);
4483dec9fcdSqs148142 	} else {
4493dec9fcdSqs148142 		cfg_value = (uint32_t)param_arr[param_hash_init_value].value;
4503dec9fcdSqs148142 	}
4513dec9fcdSqs148142 
4523dec9fcdSqs148142 	p_class_cfgp->init_hash = (uint32_t)cfg_value;
4533dec9fcdSqs148142 
4543dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_class_config"));
4553dec9fcdSqs148142 }
4563dec9fcdSqs148142 
4573dec9fcdSqs148142 
4583dec9fcdSqs148142 /*
4593dec9fcdSqs148142  * Interrupts related interface functions.
4603dec9fcdSqs148142  */
4613dec9fcdSqs148142 hxge_status_t
4623dec9fcdSqs148142 hxge_ldgv_init(p_hxge_t hxgep, int *navail_p, int *nrequired_p)
4633dec9fcdSqs148142 {
4643dec9fcdSqs148142 	uint8_t			ldv, i, maxldvs, maxldgs, start, end, nldvs;
4653dec9fcdSqs148142 	int			ldg, endldg, ngrps;
4663dec9fcdSqs148142 	uint8_t			channel;
4673dec9fcdSqs148142 	p_hxge_dma_pt_cfg_t	p_dma_cfgp;
4683dec9fcdSqs148142 	p_hxge_hw_pt_cfg_t	p_cfgp;
4693dec9fcdSqs148142 	p_hxge_ldgv_t		ldgvp;
4703dec9fcdSqs148142 	p_hxge_ldg_t		ldgp, ptr;
4713dec9fcdSqs148142 	p_hxge_ldv_t		ldvp;
4723dec9fcdSqs148142 	hxge_status_t		status = HXGE_OK;
473e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	peu_intr_mask_t		parity_err_mask;
4743dec9fcdSqs148142 
4753dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_init"));
4763dec9fcdSqs148142 	if (!*navail_p) {
4773dec9fcdSqs148142 		*nrequired_p = 0;
4783dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
4793dec9fcdSqs148142 		    "<== hxge_ldgv_init:no avail"));
4803dec9fcdSqs148142 		return (HXGE_ERROR);
4813dec9fcdSqs148142 	}
4823dec9fcdSqs148142 	p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
4833dec9fcdSqs148142 	p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
4843dec9fcdSqs148142 
4853dec9fcdSqs148142 	/* each DMA channels */
4863dec9fcdSqs148142 	nldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
4873dec9fcdSqs148142 
4883dec9fcdSqs148142 	/* vmac */
4893dec9fcdSqs148142 	nldvs++;
4903dec9fcdSqs148142 
4913dec9fcdSqs148142 	/* pfc */
4923dec9fcdSqs148142 	nldvs++;
4933dec9fcdSqs148142 
4943dec9fcdSqs148142 	/* system error interrupts. */
4953dec9fcdSqs148142 	nldvs++;
4963dec9fcdSqs148142 
4973dec9fcdSqs148142 	maxldvs = nldvs;
4983dec9fcdSqs148142 	maxldgs = p_cfgp->max_ldgs;
4993dec9fcdSqs148142 
5003dec9fcdSqs148142 	if (!maxldvs || !maxldgs) {
5013dec9fcdSqs148142 		/* No devices configured. */
5023dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_ldgv_init: "
5033dec9fcdSqs148142 		    "no logical devices or groups configured."));
5043dec9fcdSqs148142 		return (HXGE_ERROR);
5053dec9fcdSqs148142 	}
5063dec9fcdSqs148142 	ldgvp = hxgep->ldgvp;
5073dec9fcdSqs148142 	if (ldgvp == NULL) {
5083dec9fcdSqs148142 		ldgvp = KMEM_ZALLOC(sizeof (hxge_ldgv_t), KM_SLEEP);
5093dec9fcdSqs148142 		hxgep->ldgvp = ldgvp;
5103dec9fcdSqs148142 		ldgvp->maxldgs = maxldgs;
5113dec9fcdSqs148142 		ldgvp->maxldvs = maxldvs;
5123dec9fcdSqs148142 		ldgp = ldgvp->ldgp =
5133dec9fcdSqs148142 		    KMEM_ZALLOC(sizeof (hxge_ldg_t) * maxldgs, KM_SLEEP);
5143dec9fcdSqs148142 		ldvp = ldgvp->ldvp =
5153dec9fcdSqs148142 		    KMEM_ZALLOC(sizeof (hxge_ldv_t) * maxldvs, KM_SLEEP);
5163dec9fcdSqs148142 	}
5173dec9fcdSqs148142 
5183dec9fcdSqs148142 	ldgvp->ndma_ldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
5193dec9fcdSqs148142 	ldgvp->tmres = HXGE_TIMER_RESO;
5203dec9fcdSqs148142 
5213dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
5223dec9fcdSqs148142 	    "==> hxge_ldgv_init: maxldvs %d maxldgs %d nldvs %d",
5233dec9fcdSqs148142 	    maxldvs, maxldgs, nldvs));
5243dec9fcdSqs148142 
5253dec9fcdSqs148142 	ldg = p_cfgp->start_ldg;
5263dec9fcdSqs148142 	ptr = ldgp;
5273dec9fcdSqs148142 	for (i = 0; i < maxldgs; i++) {
5283dec9fcdSqs148142 		ptr->arm = B_TRUE;
5293dec9fcdSqs148142 		ptr->vldg_index = i;
5303dec9fcdSqs148142 		ptr->ldg_timer = HXGE_TIMER_LDG;
5313dec9fcdSqs148142 		ptr->ldg = ldg++;
5323dec9fcdSqs148142 		ptr->sys_intr_handler = hxge_intr;
5333dec9fcdSqs148142 		ptr->nldvs = 0;
5343dec9fcdSqs148142 		ptr->hxgep = hxgep;
5353dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
5363dec9fcdSqs148142 		    "==> hxge_ldgv_init: maxldvs %d maxldgs %d ldg %d",
5373dec9fcdSqs148142 		    maxldvs, maxldgs, ptr->ldg));
5383dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
5393dec9fcdSqs148142 		    "==> hxge_ldv_init: timer %d", ptr->ldg_timer));
5403dec9fcdSqs148142 		ptr++;
5413dec9fcdSqs148142 	}
5423dec9fcdSqs148142 
5433dec9fcdSqs148142 	ldg = p_cfgp->start_ldg;
5443dec9fcdSqs148142 	if (maxldgs > *navail_p) {
5453dec9fcdSqs148142 		ngrps = *navail_p;
5463dec9fcdSqs148142 	} else {
5473dec9fcdSqs148142 		ngrps = maxldgs;
5483dec9fcdSqs148142 	}
5493dec9fcdSqs148142 	endldg = ldg + ngrps;
5503dec9fcdSqs148142 
5513dec9fcdSqs148142 	/*
5523dec9fcdSqs148142 	 * Receive DMA channels.
5533dec9fcdSqs148142 	 */
5543dec9fcdSqs148142 	channel = p_cfgp->start_rdc;
5553dec9fcdSqs148142 	start = p_cfgp->start_rdc + HXGE_RDMA_LD_START;
5563dec9fcdSqs148142 	end = start + p_cfgp->max_rdcs;
5573dec9fcdSqs148142 	nldvs = 0;
5583dec9fcdSqs148142 	ldgvp->nldvs = 0;
5593dec9fcdSqs148142 	ldgp->ldvp = NULL;
5603dec9fcdSqs148142 	*nrequired_p = 0;
5613dec9fcdSqs148142 	ptr = ldgp;
5623dec9fcdSqs148142 
5633dec9fcdSqs148142 	/*
5643dec9fcdSqs148142 	 * Start with RDC to configure logical devices for each group.
5653dec9fcdSqs148142 	 */
5663dec9fcdSqs148142 	for (i = 0, ldv = start; ldv < end; i++, ldv++) {
5673dec9fcdSqs148142 		ldvp->is_rxdma = B_TRUE;
5683dec9fcdSqs148142 		ldvp->ldv = ldv;
5693dec9fcdSqs148142 
5703dec9fcdSqs148142 		/*
5713dec9fcdSqs148142 		 * If non-seq needs to change the following code
5723dec9fcdSqs148142 		 */
5733dec9fcdSqs148142 		ldvp->channel = channel++;
5743dec9fcdSqs148142 		ldvp->vdma_index = i;
5753dec9fcdSqs148142 		ldvp->ldv_intr_handler = hxge_rx_intr;
5763dec9fcdSqs148142 		ldvp->ldv_ldf_masks = 0;
5773dec9fcdSqs148142 		ldvp->use_timer = B_FALSE;
5783dec9fcdSqs148142 		ldvp->hxgep = hxgep;
5793dec9fcdSqs148142 		hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
5803dec9fcdSqs148142 		nldvs++;
5813dec9fcdSqs148142 	}
5823dec9fcdSqs148142 
5833dec9fcdSqs148142 	/*
5843dec9fcdSqs148142 	 * Transmit DMA channels.
5853dec9fcdSqs148142 	 */
5863dec9fcdSqs148142 	channel = p_cfgp->start_tdc;
5873dec9fcdSqs148142 	start = p_cfgp->start_tdc + HXGE_TDMA_LD_START;
5883dec9fcdSqs148142 	end = start + p_cfgp->max_tdcs;
5893dec9fcdSqs148142 	for (i = 0, ldv = start; ldv < end; i++, ldv++) {
5903dec9fcdSqs148142 		ldvp->is_txdma = B_TRUE;
5913dec9fcdSqs148142 		ldvp->ldv = ldv;
5923dec9fcdSqs148142 		ldvp->channel = channel++;
5933dec9fcdSqs148142 		ldvp->vdma_index = i;
5943dec9fcdSqs148142 		ldvp->ldv_intr_handler = hxge_tx_intr;
5953dec9fcdSqs148142 		ldvp->ldv_ldf_masks = 0;
5963dec9fcdSqs148142 		ldvp->use_timer = B_FALSE;
5973dec9fcdSqs148142 		ldvp->hxgep = hxgep;
5983dec9fcdSqs148142 		hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
5993dec9fcdSqs148142 		nldvs++;
6003dec9fcdSqs148142 	}
6013dec9fcdSqs148142 
6023dec9fcdSqs148142 	/*
6033dec9fcdSqs148142 	 * VMAC
6043dec9fcdSqs148142 	 */
6053dec9fcdSqs148142 	ldvp->is_vmac = B_TRUE;
6063dec9fcdSqs148142 	ldvp->ldv_intr_handler = hxge_vmac_intr;
6073dec9fcdSqs148142 	ldvp->ldv_ldf_masks = 0;
6083dec9fcdSqs148142 	ldv = HXGE_VMAC_LD;
6093dec9fcdSqs148142 	ldvp->ldv = ldv;
6103dec9fcdSqs148142 	ldvp->use_timer = B_FALSE;
6113dec9fcdSqs148142 	ldvp->hxgep = hxgep;
6123dec9fcdSqs148142 	hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
6133dec9fcdSqs148142 	nldvs++;
6143dec9fcdSqs148142 
6153dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
6163dec9fcdSqs148142 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
6173dec9fcdSqs148142 	    nldvs, *navail_p, *nrequired_p));
6183dec9fcdSqs148142 
6193dec9fcdSqs148142 	/*
6203dec9fcdSqs148142 	 * PFC
6213dec9fcdSqs148142 	 */
6223dec9fcdSqs148142 	ldvp->is_pfc = B_TRUE;
6233dec9fcdSqs148142 	ldvp->ldv_intr_handler = hxge_pfc_intr;
6243dec9fcdSqs148142 	ldvp->ldv_ldf_masks = 0;
6253dec9fcdSqs148142 	ldv = HXGE_PFC_LD;
6263dec9fcdSqs148142 	ldvp->ldv = ldv;
6273dec9fcdSqs148142 	ldvp->use_timer = B_FALSE;
6283dec9fcdSqs148142 	ldvp->hxgep = hxgep;
6293dec9fcdSqs148142 	hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
6303dec9fcdSqs148142 	nldvs++;
6313dec9fcdSqs148142 
6323dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
6333dec9fcdSqs148142 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
6343dec9fcdSqs148142 	    nldvs, *navail_p, *nrequired_p));
6353dec9fcdSqs148142 
6363dec9fcdSqs148142 	/*
6373dec9fcdSqs148142 	 * System error interrupts.
6383dec9fcdSqs148142 	 */
6393dec9fcdSqs148142 	ldv = HXGE_SYS_ERROR_LD;
6403dec9fcdSqs148142 	ldvp->ldv = ldv;
6413dec9fcdSqs148142 	ldvp->is_syserr = B_TRUE;
6423dec9fcdSqs148142 	ldvp->ldv_intr_handler = hxge_syserr_intr;
6433dec9fcdSqs148142 	ldvp->ldv_ldf_masks = 0;
6443dec9fcdSqs148142 	ldvp->hxgep = hxgep;
6453dec9fcdSqs148142 	ldvp->use_timer = B_FALSE;
6463dec9fcdSqs148142 	ldgvp->ldvp_syserr = ldvp;
6473dec9fcdSqs148142 
6483dec9fcdSqs148142 	/* Reset PEU error mask to allow PEU error interrupts */
649e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	/*
650e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	 * Keep the msix parity error mask here and remove it
651e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	 * after ddi_intr_enable call to avoid a msix par err
652e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	 */
653e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	parity_err_mask.value = 0;
654e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	parity_err_mask.bits.eic_msix_parerr_mask = 1;
655e5d97391SQiyan Sun - Sun Microsystems - San Diego United States 	HXGE_REG_WR32(hxgep->hpi_handle, PEU_INTR_MASK, parity_err_mask.value);
6563dec9fcdSqs148142 
6573dec9fcdSqs148142 	/*
6583dec9fcdSqs148142 	 * Unmask the system interrupt states.
6593dec9fcdSqs148142 	 */
6603dec9fcdSqs148142 	(void) hxge_fzc_sys_err_mask_set(hxgep, B_FALSE);
6613dec9fcdSqs148142 	(void) hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
6623dec9fcdSqs148142 	nldvs++;
6633dec9fcdSqs148142 
6643dec9fcdSqs148142 	ldgvp->ldg_intrs = *nrequired_p;
6653dec9fcdSqs148142 
6663dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
6673dec9fcdSqs148142 	    "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
6683dec9fcdSqs148142 	    nldvs, *navail_p, *nrequired_p));
6693dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_init"));
6703dec9fcdSqs148142 	return (status);
6713dec9fcdSqs148142 }
6723dec9fcdSqs148142 
6733dec9fcdSqs148142 hxge_status_t
6743dec9fcdSqs148142 hxge_ldgv_uninit(p_hxge_t hxgep)
6753dec9fcdSqs148142 {
6763dec9fcdSqs148142 	p_hxge_ldgv_t		ldgvp;
6773dec9fcdSqs148142 
6783dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_uninit"));
6793dec9fcdSqs148142 	ldgvp = hxgep->ldgvp;
6803dec9fcdSqs148142 	if (ldgvp == NULL) {
6813dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
6823dec9fcdSqs148142 		    "<== hxge_ldgv_uninit: no logical group configured."));
6833dec9fcdSqs148142 		return (HXGE_OK);
6843dec9fcdSqs148142 	}
6853dec9fcdSqs148142 
6863dec9fcdSqs148142 	if (ldgvp->ldgp) {
6873dec9fcdSqs148142 		KMEM_FREE(ldgvp->ldgp, sizeof (hxge_ldg_t) * ldgvp->maxldgs);
6883dec9fcdSqs148142 	}
6893dec9fcdSqs148142 	if (ldgvp->ldvp) {
6903dec9fcdSqs148142 		KMEM_FREE(ldgvp->ldvp, sizeof (hxge_ldv_t) * ldgvp->maxldvs);
6913dec9fcdSqs148142 	}
6923dec9fcdSqs148142 
6933dec9fcdSqs148142 	KMEM_FREE(ldgvp, sizeof (hxge_ldgv_t));
6943dec9fcdSqs148142 	hxgep->ldgvp = NULL;
6953dec9fcdSqs148142 
6963dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_uninit"));
6973dec9fcdSqs148142 	return (HXGE_OK);
6983dec9fcdSqs148142 }
6993dec9fcdSqs148142 
7003dec9fcdSqs148142 hxge_status_t
7013dec9fcdSqs148142 hxge_intr_ldgv_init(p_hxge_t hxgep)
7023dec9fcdSqs148142 {
7033dec9fcdSqs148142 	hxge_status_t	status = HXGE_OK;
7043dec9fcdSqs148142 
7053dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_ldgv_init"));
7063dec9fcdSqs148142 	/*
7073dec9fcdSqs148142 	 * Configure the logical device group numbers, state vectors
7083dec9fcdSqs148142 	 * and interrupt masks for each logical device.
7093dec9fcdSqs148142 	 */
7103dec9fcdSqs148142 	status = hxge_fzc_intr_init(hxgep);
7113dec9fcdSqs148142 
7123dec9fcdSqs148142 	/*
7133dec9fcdSqs148142 	 * Configure logical device masks and timers.
7143dec9fcdSqs148142 	 */
7153dec9fcdSqs148142 	status = hxge_intr_mask_mgmt(hxgep);
7163dec9fcdSqs148142 
7173dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_ldgv_init"));
7183dec9fcdSqs148142 	return (status);
7193dec9fcdSqs148142 }
7203dec9fcdSqs148142 
7213dec9fcdSqs148142 hxge_status_t
7223dec9fcdSqs148142 hxge_intr_mask_mgmt(p_hxge_t hxgep)
7233dec9fcdSqs148142 {
7243dec9fcdSqs148142 	p_hxge_ldgv_t	ldgvp;
7253dec9fcdSqs148142 	p_hxge_ldg_t	ldgp;
7263dec9fcdSqs148142 	p_hxge_ldv_t	ldvp;
7273dec9fcdSqs148142 	hpi_handle_t	handle;
7283dec9fcdSqs148142 	int		i, j;
7293dec9fcdSqs148142 	hpi_status_t	rs = HPI_SUCCESS;
7303dec9fcdSqs148142 
7313dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_mask_mgmt"));
7323dec9fcdSqs148142 
7333dec9fcdSqs148142 	if ((ldgvp = hxgep->ldgvp) == NULL) {
7343dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
7353dec9fcdSqs148142 		    "<== hxge_intr_mask_mgmt: Null ldgvp"));
7363dec9fcdSqs148142 		return (HXGE_ERROR);
7373dec9fcdSqs148142 	}
7383dec9fcdSqs148142 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
7393dec9fcdSqs148142 	ldgp = ldgvp->ldgp;
7403dec9fcdSqs148142 	ldvp = ldgvp->ldvp;
7413dec9fcdSqs148142 	if (ldgp == NULL || ldvp == NULL) {
7423dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
7433dec9fcdSqs148142 		    "<== hxge_intr_mask_mgmt: Null ldgp or ldvp"));
7443dec9fcdSqs148142 		return (HXGE_ERROR);
7453dec9fcdSqs148142 	}
7463dec9fcdSqs148142 
7473dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
7483dec9fcdSqs148142 	    "==> hxge_intr_mask_mgmt: # of intrs %d ", ldgvp->ldg_intrs));
7493dec9fcdSqs148142 	/* Initialize masks. */
7503dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
7513dec9fcdSqs148142 	    "==> hxge_intr_mask_mgmt(Hydra): # intrs %d ", ldgvp->ldg_intrs));
7523dec9fcdSqs148142 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
7533dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
7543dec9fcdSqs148142 		    "==> hxge_intr_mask_mgmt(Hydra): # ldv %d in group %d",
7553dec9fcdSqs148142 		    ldgp->nldvs, ldgp->ldg));
7563dec9fcdSqs148142 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
7573dec9fcdSqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
7583dec9fcdSqs148142 			    "==> hxge_intr_mask_mgmt: set ldv # %d "
7593dec9fcdSqs148142 			    "for ldg %d", ldvp->ldv, ldgp->ldg));
7603dec9fcdSqs148142 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
7613dec9fcdSqs148142 			    ldvp->ldv_ldf_masks);
7623dec9fcdSqs148142 			if (rs != HPI_SUCCESS) {
7633dec9fcdSqs148142 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
7643dec9fcdSqs148142 				    "<== hxge_intr_mask_mgmt: set mask failed "
7653dec9fcdSqs148142 				    " rs 0x%x ldv %d mask 0x%x",
7663dec9fcdSqs148142 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
7673dec9fcdSqs148142 				return (HXGE_ERROR | rs);
7683dec9fcdSqs148142 			}
7693dec9fcdSqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
7703dec9fcdSqs148142 			    "==> hxge_intr_mask_mgmt: set mask OK "
7713dec9fcdSqs148142 			    " rs 0x%x ldv %d mask 0x%x",
7723dec9fcdSqs148142 			    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
7733dec9fcdSqs148142 		}
7743dec9fcdSqs148142 	}
7753dec9fcdSqs148142 
7763dec9fcdSqs148142 	ldgp = ldgvp->ldgp;
7773dec9fcdSqs148142 	/* Configure timer and arm bit */
7783dec9fcdSqs148142 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
7793dec9fcdSqs148142 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
7803dec9fcdSqs148142 		    ldgp->arm, ldgp->ldg_timer);
7813dec9fcdSqs148142 		if (rs != HPI_SUCCESS) {
7823dec9fcdSqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
7833dec9fcdSqs148142 			    "<== hxge_intr_mask_mgmt: set timer failed "
7843dec9fcdSqs148142 			    " rs 0x%x dg %d timer 0x%x",
7853dec9fcdSqs148142 			    rs, ldgp->ldg, ldgp->ldg_timer));
7863dec9fcdSqs148142 			return (HXGE_ERROR | rs);
7873dec9fcdSqs148142 		}
7883dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
7893dec9fcdSqs148142 		    "==> hxge_intr_mask_mgmt: set timer OK "
7903dec9fcdSqs148142 		    " rs 0x%x ldg %d timer 0x%x",
7913dec9fcdSqs148142 		    rs, ldgp->ldg, ldgp->ldg_timer));
7923dec9fcdSqs148142 	}
7933dec9fcdSqs148142 
7943dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_mask_mgmt"));
7953dec9fcdSqs148142 	return (HXGE_OK);
7963dec9fcdSqs148142 }
7973dec9fcdSqs148142 
7983dec9fcdSqs148142 hxge_status_t
7993dec9fcdSqs148142 hxge_intr_mask_mgmt_set(p_hxge_t hxgep, boolean_t on)
8003dec9fcdSqs148142 {
8013dec9fcdSqs148142 	p_hxge_ldgv_t	ldgvp;
8023dec9fcdSqs148142 	p_hxge_ldg_t	ldgp;
8033dec9fcdSqs148142 	p_hxge_ldv_t	ldvp;
8043dec9fcdSqs148142 	hpi_handle_t	handle;
8053dec9fcdSqs148142 	int		i, j;
8063dec9fcdSqs148142 	hpi_status_t	rs = HPI_SUCCESS;
8073dec9fcdSqs148142 
8083dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL,
8093dec9fcdSqs148142 	    "==> hxge_intr_mask_mgmt_set (%d)", on));
8103dec9fcdSqs148142 
8113dec9fcdSqs148142 	if ((ldgvp = hxgep->ldgvp) == NULL) {
8123dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8133dec9fcdSqs148142 		    "==> hxge_intr_mask_mgmt_set: Null ldgvp"));
8143dec9fcdSqs148142 		return (HXGE_ERROR);
8153dec9fcdSqs148142 	}
8163dec9fcdSqs148142 	handle = HXGE_DEV_HPI_HANDLE(hxgep);
8173dec9fcdSqs148142 	ldgp = ldgvp->ldgp;
8183dec9fcdSqs148142 	ldvp = ldgvp->ldvp;
8193dec9fcdSqs148142 	if (ldgp == NULL || ldvp == NULL) {
8203dec9fcdSqs148142 		HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8213dec9fcdSqs148142 		    "<== hxge_intr_mask_mgmt_set: Null ldgp or ldvp"));
8223dec9fcdSqs148142 		return (HXGE_ERROR);
8233dec9fcdSqs148142 	}
8243dec9fcdSqs148142 
8253dec9fcdSqs148142 	/* set masks. */
8263dec9fcdSqs148142 	for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
8273dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
8283dec9fcdSqs148142 		    "==> hxge_intr_mask_mgmt_set: flag %d ldg %d"
8293dec9fcdSqs148142 		    "set mask nldvs %d", on, ldgp->ldg, ldgp->nldvs));
8303dec9fcdSqs148142 		for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
8313dec9fcdSqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
8323dec9fcdSqs148142 			    "==> hxge_intr_mask_mgmt_set: "
8333dec9fcdSqs148142 			    "for %d %d flag %d", i, j, on));
8343dec9fcdSqs148142 			if (on) {
8353dec9fcdSqs148142 				ldvp->ldv_ldf_masks = 0;
8363dec9fcdSqs148142 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
8373dec9fcdSqs148142 				    "==> hxge_intr_mask_mgmt_set: "
8383dec9fcdSqs148142 				    "ON mask off"));
8393dec9fcdSqs148142 			} else {
8403dec9fcdSqs148142 				ldvp->ldv_ldf_masks = (uint8_t)LD_IM_MASK;
8413dec9fcdSqs148142 				HXGE_DEBUG_MSG((hxgep, INT_CTL,
8423dec9fcdSqs148142 				    "==> hxge_intr_mask_mgmt_set:mask on"));
8433dec9fcdSqs148142 			}
8443dec9fcdSqs148142 
8453dec9fcdSqs148142 			rs = hpi_intr_mask_set(handle, ldvp->ldv,
8463dec9fcdSqs148142 			    ldvp->ldv_ldf_masks);
8473dec9fcdSqs148142 			if (rs != HPI_SUCCESS) {
8483dec9fcdSqs148142 				HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8493dec9fcdSqs148142 				    "==> hxge_intr_mask_mgmt_set: "
8503dec9fcdSqs148142 				    "set mask failed rs 0x%x ldv %d mask 0x%x",
8513dec9fcdSqs148142 				    rs, ldvp->ldv, ldvp->ldv_ldf_masks));
8523dec9fcdSqs148142 				return (HXGE_ERROR | rs);
8533dec9fcdSqs148142 			}
8543dec9fcdSqs148142 			HXGE_DEBUG_MSG((hxgep, INT_CTL,
8553dec9fcdSqs148142 			    "==> hxge_intr_mask_mgmt_set: flag %d"
8563dec9fcdSqs148142 			    "set mask OK ldv %d mask 0x%x",
8573dec9fcdSqs148142 			    on, ldvp->ldv, ldvp->ldv_ldf_masks));
8583dec9fcdSqs148142 		}
8593dec9fcdSqs148142 	}
8603dec9fcdSqs148142 
8613dec9fcdSqs148142 	ldgp = ldgvp->ldgp;
8623dec9fcdSqs148142 	/* set the arm bit */
8633dec9fcdSqs148142 	for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
8643dec9fcdSqs148142 		if (on && !ldgp->arm) {
8653dec9fcdSqs148142 			ldgp->arm = B_TRUE;
8663dec9fcdSqs148142 		} else if (!on && ldgp->arm) {
8673dec9fcdSqs148142 			ldgp->arm = B_FALSE;
8683dec9fcdSqs148142 		}
8693dec9fcdSqs148142 		rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
8703dec9fcdSqs148142 		    ldgp->arm, ldgp->ldg_timer);
8713dec9fcdSqs148142 		if (rs != HPI_SUCCESS) {
8723dec9fcdSqs148142 			HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
8733dec9fcdSqs148142 			    "<== hxge_intr_mask_mgmt_set: "
8743dec9fcdSqs148142 			    "set timer failed rs 0x%x ldg %d timer 0x%x",
8753dec9fcdSqs148142 			    rs, ldgp->ldg, ldgp->ldg_timer));
8763dec9fcdSqs148142 			return (HXGE_ERROR | rs);
8773dec9fcdSqs148142 		}
8783dec9fcdSqs148142 		HXGE_DEBUG_MSG((hxgep, INT_CTL,
8793dec9fcdSqs148142 		    "==> hxge_intr_mask_mgmt_set: OK (flag %d) "
8803dec9fcdSqs148142 		    "set timer ldg %d timer 0x%x",
8813dec9fcdSqs148142 		    on, ldgp->ldg, ldgp->ldg_timer));
8823dec9fcdSqs148142 	}
8833dec9fcdSqs148142 
8843dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_mask_mgmt_set"));
8853dec9fcdSqs148142 	return (HXGE_OK);
8863dec9fcdSqs148142 }
8873dec9fcdSqs148142 
8883dec9fcdSqs148142 /*
8893dec9fcdSqs148142  * For Big Endian systems, the mac address will be from OBP. For Little
8903dec9fcdSqs148142  * Endian (x64) systems, it will be retrieved from the card since it cannot
8913dec9fcdSqs148142  * be programmed into PXE.
8923dec9fcdSqs148142  * This function also populates the MMAC parameters.
8933dec9fcdSqs148142  */
8943dec9fcdSqs148142 static hxge_status_t
8953dec9fcdSqs148142 hxge_get_mac_addr_properties(p_hxge_t hxgep)
8963dec9fcdSqs148142 {
8973dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_get_mac_addr_properties "));
8983dec9fcdSqs148142 
8993dec9fcdSqs148142 	(void) hxge_pfc_mac_addrs_get(hxgep);
9003dec9fcdSqs148142 	hxgep->ouraddr = hxgep->factaddr;
9013dec9fcdSqs148142 
9023dec9fcdSqs148142 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_get_mac_addr_properties "));
9033dec9fcdSqs148142 	return (HXGE_OK);
9043dec9fcdSqs148142 }
9053dec9fcdSqs148142 
9063dec9fcdSqs148142 static void
9073dec9fcdSqs148142 hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
9083dec9fcdSqs148142 	uint8_t endldg, int *ngrps)
9093dec9fcdSqs148142 {
9103dec9fcdSqs148142 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup"));
9113dec9fcdSqs148142 	/* Assign the group number for each device. */
9123dec9fcdSqs148142 	(*ldvp)->ldg_assigned = (*ldgp)->ldg;
9133dec9fcdSqs148142 	(*ldvp)->ldgp = *ldgp;
9143dec9fcdSqs148142 	(*ldvp)->ldv = ldv;
9153dec9fcdSqs148142 
9163dec9fcdSqs148142 	HXGE_DEBUG_MSG((NULL, INT_CTL,
9173dec9fcdSqs148142 	    "==> hxge_ldgv_setup: ldv %d endldg %d ldg %d, ldvp $%p",
9183dec9fcdSqs148142 	    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
9193dec9fcdSqs148142 
9203dec9fcdSqs148142 	(*ldgp)->nldvs++;
9213dec9fcdSqs148142 	if ((*ldgp)->ldg == (endldg - 1)) {
9223dec9fcdSqs148142 		if ((*ldgp)->ldvp == NULL) {
9233dec9fcdSqs148142 			(*ldgp)->ldvp = *ldvp;
9243dec9fcdSqs148142 			*ngrps += 1;
9253dec9fcdSqs148142 			HXGE_DEBUG_MSG((NULL, INT_CTL,
9263dec9fcdSqs148142 			    "==> hxge_ldgv_setup: ngrps %d", *ngrps));
9273dec9fcdSqs148142 		}
9283dec9fcdSqs148142 		HXGE_DEBUG_MSG((NULL, INT_CTL,
9293dec9fcdSqs148142 		    "==> hxge_ldgv_setup: ldvp $%p ngrps %d",
9303dec9fcdSqs148142 		    *ldvp, *ngrps));
9313dec9fcdSqs148142 		++*ldvp;
9323dec9fcdSqs148142 	} else {
9333dec9fcdSqs148142 		(*ldgp)->ldvp = *ldvp;
9343dec9fcdSqs148142 		*ngrps += 1;
9353dec9fcdSqs148142 		HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup(done): "
9363dec9fcdSqs148142 		    "ldv %d endldg %d ldg %d, ldvp $%p",
9373dec9fcdSqs148142 		    ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
938*2bc98732SRichard Lowe 		++*ldvp;
939*2bc98732SRichard Lowe 		++*ldgp;
9403dec9fcdSqs148142 		HXGE_DEBUG_MSG((NULL, INT_CTL,
9413dec9fcdSqs148142 		    "==> hxge_ldgv_setup: new ngrps %d", *ngrps));
9423dec9fcdSqs148142 	}
9433dec9fcdSqs148142 
9443dec9fcdSqs148142 	HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup: "
9453dec9fcdSqs148142 	    "ldg %d nldvs %d ldv %d ldvp $%p endldg %d ngrps %d",
9463dec9fcdSqs148142 	    (*ldgp)->ldg, (*ldgp)->nldvs, ldv, ldvp, endldg, *ngrps));
9473dec9fcdSqs148142 
9483dec9fcdSqs148142 	HXGE_DEBUG_MSG((NULL, INT_CTL, "<== hxge_ldgv_setup"));
9493dec9fcdSqs148142 }
950